C# 检查C中特定结构的源文件(文本文件)#
下面是一些文本的示例(在本例中,它是C源代码,可以是任何结构化文本)。我试图读取两个长度可变、结构不同的文件,并弄清楚是否在每次C# 检查C中特定结构的源文件(文本文件)#,c#,C#,下面是一些文本的示例(在本例中,它是C源代码,可以是任何结构化文本)。我试图读取两个长度可变、结构不同的文件,并弄清楚是否在每次\define之后都会出现\include“test.h” 同样的情况也适用于预处理器指令内外(#if、#ifdef、#ifndef、#endif)。如果在此之前正确的#定义在if指令中,则允许在#endif之后出现#include“test.h” 一些旁注: 我从文件中提取文本,执行一些操作,如删除注释、无关行、空行等,然后将文件作为字符串[]返回。这使得在行之间进行
\define
之后都会出现\include“test.h”
同样的情况也适用于预处理器指令内外(#if、#ifdef、#ifndef、#endif
)。如果在此之前正确的#定义在if指令
中,则允许在#endif
之后出现#include“test.h”
一些旁注:
我从文件中提取文本,执行一些操作,如删除注释、无关行、空行等,然后将文件作为字符串[]
返回。这使得在行之间进行迭代和来回跳转变得相当容易SourceCode[i]
我曾尝试用几种不同的方法来实现一个解决方案,但从未完全做到一针见血
我的第一次尝试包括无限量的if-else语句和while循环,用于逻辑中每个可以想象的路径。这最终很难维护、混淆和控制
接下来,我尝试实现一个状态机,跟踪我在文本文件中的位置,根据需要跳转到不同的状态。我找不到一个完美的解决办法
我尝试过的另一种尝试是使用堆栈,将#define
推到堆栈中,检查它是什么,将下一行推到堆栈中,检查它是否为#include
,如果不是,则返回错误。当然,一旦我有了指令,这也就有点复杂了,因为对于多个#定义
,一个include就足够了
我已经研究了解析器(主要是Antlr),意识到这对于这样的问题来说可能太过分了,还考虑到我对解析器一无所知,需要自己编写语法
源代码示例
有没有人有一些一般的建议,也许可以给我指出一个具体的方向。这个问题的合适解决方案是什么
编辑:@jdweng
dt.Columns.Add("Next #elif State", typeof(int));
dt.Rows.Add(new object[] { 12, DEFINE_STATE.FOUND_ELIF, 13, 0, 2, 7, 12, 10, ERROR.NO_ERROR, ACTION.NONE });
dt.Rows.Add(new object[] { 13, DEFINE_STATE.FOUND_DEFINE_IN_ELIF, -1, 14, 2, 7, 12, 10, ERROR.DEFINE_FOLLOWED_BY_DEFINE, ACTION.SET_DEFINE_ELIF_LINE_NUMBER });
dt.Rows.Add(new object[] { 14, DEFINE_STATE.FOUND_INCLUDE_IN_ELIF, 13, 0, 2, 7, 12, 10, ERROR.NO_ERROR, ACTION.RESET_DEFINE_ELIF_LINE_NUMBER });
我添加了一个检查,以查看elif_level是否为==0,如果是,则像往常一样继续,删除if-nest的级别。否则,我将删除elif_级别,然后删除if嵌套级别
上面的行看起来正确吗?我想要么在找到elif时将bool变量添加到设置为true的状态,然后在找到#endif时,我可以弹出所有将elif设置为true的状态。如果要分析的所有文本的公分母都是某种层次结构的文档,may bee您应该首先将其转换为该格式,然后对已解析的文档执行其余的分析,而不是同时执行这两项操作。也许将其转换为XML文档就足以满足您的情况,然后使用XSLT/XPath(或LINQ for XDocument,如果您愿意的话)进行分析。这基本上也是其他代码分析的执行方式(Roslyn代码分析器,带有语法树,当然更奇特的除外)。如果要分析的所有文本的公分母都是某种层次结构的文档,may bee您应该首先将其转换为该格式,然后对已解析的文档执行其余的分析,而不是同时执行这两项操作。也许将其转换为XML文档就足以满足您的情况,然后使用XSLT/XPath(或LINQ for XDocument,如果您愿意的话)进行分析。这基本上就是其他代码分析的执行方式(Roslyn代码分析器带有语法树,当然除了更奇特的语法树)。我解析这样的文本文件已经超过40年了。这是一个复杂的逻辑问题,所以对于任何复杂的逻辑问题,我都会使用状态机。首先我画了一张状态图
然后我编写代码来实现状态表
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
using System.Data;
namespace ConsoleApplication1
{
public enum DEFINE_STATE
{
SPECIAL = -4, //define followed by IF
NONE = -3,
INVALID = -2, //Compile will give error, cannot occur
ERROR = -1,
DO_NOT_CARE = 0,
START = 1,
FOUND_IF = 2,
FOUND_DEFINE_IN_IF = 3,
FOUND_DEFINE_NOT_IN_IF = 4,
FOUND_INCLUDE_IN_IF = 5,
FOUND_ELSE = 6,
FOUND_DEFINE_IN_ELSE = 7,
FOUND_INCLUDE_IN_ELSE = 8,
FOUND_INCLUDE_NOT_IN_IF = 9,
FOUND_END_IF = 10,
RETURN = 11,
FOUND_ELIF = 12,
FOUND_DEFINE_IN_ELIF = 13,
FOUND_INCLUDE_IN_ELIF = 14,
}
public enum ERROR
{
NO_ERROR,
DEFINE_FOLLOWED_BY_DEFINE,
DEFINE_FOLLOWED_BY_DEFINE_OR_IF
}
public enum TABLE_COLUMN
{
STATE = 0,
DESCRIPTION = 1,
DEFINE,
INCLUDE,
IF,
ELSE,
ELIF,
END_IF,
ERROR,
ACTION
}
public enum ACTION
{
NONE,
RESET_DEFINE_LINE_NUMBER,
RESET_DEFINE_IF_LINE_NUMBER,
RESET_DEFINE_ELSE_LINE_NUMBER,
RESET_DEFINE_ELIF_LINE_NUMBER,
SET_DEFINE_LINE_NUMBER,
SET_DEFINE_IF_LINE_NUMBER,
SET_DEFINE_ELSE_LINE_NUMBER,
SET_DEFINE_ELIF_LINE_NUMBER,
}
public class State_Variables
{
public int define_Line_Number = 0;
public int define_If_Line_Number = 0;
public int define_Else_Line_Number = 0;
public int define_Elif_Line_Number = 0;
public int return_end_level = 0;
public DEFINE_STATE state = DEFINE_STATE.START;
public DataRow row { get; set; }
}
class Program
{
const string FILENAME = @"c:\temp\test.txt";
static void Main(string[] args)
{
string pattern = "#include\\s+\"test.h\"";
StreamReader reader = new StreamReader(FILENAME);
string input = "";
DataTable dt = new DataTable();
dt.Columns.Add("State", typeof(int));
dt.Columns.Add("Description", typeof(DEFINE_STATE));
dt.Columns.Add("Next Define State", typeof(int));
dt.Columns.Add("Next Include State", typeof(int));
dt.Columns.Add("Next IF State", typeof(int));
dt.Columns.Add("Next Else State", typeof(int));
dt.Columns.Add("Next ELIF State", typeof(int));
dt.Columns.Add("Next ENDIF State", typeof(int));
dt.Columns.Add("Error Number", typeof(ERROR));
dt.Columns.Add("Action", typeof(ACTION));
//0 do not care
//-1 error
//-2 invalid
dt.Rows.Add(new object[] { 1, DEFINE_STATE.START, 4, 0, 2, -2, -2, -2, ERROR.NO_ERROR, ACTION.NONE });
dt.Rows.Add(new object[] { 2, DEFINE_STATE.FOUND_IF, 3, 0, 2, 6, 12, 10, ERROR.NO_ERROR, ACTION.NONE });
dt.Rows.Add(new object[] { 3, DEFINE_STATE.FOUND_DEFINE_IN_IF, -1, 5, 2, 6, 12, 10, ERROR.DEFINE_FOLLOWED_BY_DEFINE, ACTION.SET_DEFINE_IF_LINE_NUMBER });
dt.Rows.Add(new object[] { 4, DEFINE_STATE.FOUND_DEFINE_NOT_IN_IF, -1, 9, -4, -2, -2, -2, ERROR.DEFINE_FOLLOWED_BY_DEFINE, ACTION.SET_DEFINE_LINE_NUMBER });
dt.Rows.Add(new object[] { 5, DEFINE_STATE.FOUND_INCLUDE_IN_IF, 3, 0, 2, 6, 12, 10, ERROR.NO_ERROR, ACTION.RESET_DEFINE_IF_LINE_NUMBER });
dt.Rows.Add(new object[] { 6, DEFINE_STATE.FOUND_ELSE, 7, 0, 2, -2, -2, 10, ERROR.NO_ERROR, ACTION.NONE });
dt.Rows.Add(new object[] { 7, DEFINE_STATE.FOUND_DEFINE_IN_ELSE, -1, 8, 2, -2, -2, 10, ERROR.DEFINE_FOLLOWED_BY_DEFINE, ACTION.SET_DEFINE_ELSE_LINE_NUMBER });
dt.Rows.Add(new object[] { 8, DEFINE_STATE.FOUND_INCLUDE_IN_ELSE, 7, 0, 2, -2, -2, 10, ERROR.NO_ERROR, ACTION.RESET_DEFINE_ELSE_LINE_NUMBER });
dt.Rows.Add(new object[] { 9, DEFINE_STATE.FOUND_INCLUDE_NOT_IN_IF, 4, 0, 2, -2, -2, -2, ERROR.NO_ERROR, ACTION.RESET_DEFINE_LINE_NUMBER });
dt.Rows.Add(new object[] { 10, DEFINE_STATE.FOUND_END_IF, 11, 1, 2, -2, -2, -2, ERROR.NO_ERROR, ACTION.NONE });
dt.Rows.Add(new object[] { 11, DEFINE_STATE.RETURN, -2, -2, 2, -2, -2, -2, ERROR.NO_ERROR, ACTION.NONE });
dt.Rows.Add(new object[] { 12, DEFINE_STATE.FOUND_ELIF, 13, 0, 2, -2, 12, 10, ERROR.NO_ERROR, ACTION.NONE });
dt.Rows.Add(new object[] { 13, DEFINE_STATE.FOUND_DEFINE_IN_ELIF, -1, 14, 2, -2, 12, 10, ERROR.DEFINE_FOLLOWED_BY_DEFINE, ACTION.SET_DEFINE_ELIF_LINE_NUMBER });
dt.Rows.Add(new object[] { 14, DEFINE_STATE.FOUND_INCLUDE_IN_ELIF, 13, 0, 2, 7, 12, 10, ERROR.NO_ERROR, ACTION.RESET_DEFINE_ELIF_LINE_NUMBER });
int level = 0;
List<State_Variables> states = new List<State_Variables>();
State_Variables newState = new State_Variables();
states.Add(newState);
DEFINE_STATE nextState = DEFINE_STATE.START;
ACTION action = ACTION.NONE;
int line_number = 0;
while ((input = reader.ReadLine()) != null)
{
line_number++;
input = input.Trim();
if (input.StartsWith("//")) continue; //ignore comments
if (input.Length == 0) continue;
Boolean returnFromIF = false;
Match match = Regex.Match(input, pattern);
//test if end if is followed by include
if (states[level].state == DEFINE_STATE.FOUND_END_IF)
{
int return_end_level = 0;
do
{
if (!match.Success)
{
int define_If_Line_Number = states[level].define_If_Line_Number;
int define_Else_Line_Number = states[level].define_Else_Line_Number;
int define_Elif_Line_Number = states[level].define_Elif_Line_Number;
if (define_If_Line_Number != 0)
{
Console.WriteLine("Define in IF at line {0} does not have and include", define_If_Line_Number.ToString());
}
if (define_Else_Line_Number != 0)
{
Console.WriteLine("Define in ELSE at line {0} does not have and include", define_Else_Line_Number.ToString());
}
if (define_Elif_Line_Number != 0)
{
Console.WriteLine("Define in ELSE at line {0} does not have and include", define_Else_Line_Number.ToString());
}
}
return_end_level = states[level].return_end_level;
states.RemoveAt(level--);
} while (level > return_end_level);
returnFromIF = true;
}
else
{
states[level].row = dt.AsEnumerable().Where(x => x.Field<int>((int)TABLE_COLUMN.STATE) == (int)states[level].state).FirstOrDefault();
}
nextState = DEFINE_STATE.NONE;
//check if defines are terminated with include
if (input.Contains("#define"))
{
nextState = (DEFINE_STATE)states[level].row.Field<int>((int)TABLE_COLUMN.DEFINE);
}
if (match.Success)
{
if (returnFromIF)
{
nextState = states[level].state;
}
else
{
nextState = (DEFINE_STATE)states[level].row.Field<int>((int)TABLE_COLUMN.INCLUDE);
}
}
if (input.Contains("#if"))
{
nextState = (DEFINE_STATE)states[level].row.Field<int>((int)TABLE_COLUMN.IF);
states.Add(new State_Variables());
level++;
states[level].return_end_level = level - 1;
}
if (input.Contains("#else"))
{
nextState = (DEFINE_STATE)states[level].row.Field<int>((int)TABLE_COLUMN.ELSE);
}
if (input.Contains("#elif"))
{
nextState = (DEFINE_STATE)states[level].row.Field<int>((int)TABLE_COLUMN.ELIF);
states.Add(new State_Variables());
level++;
states[level].return_end_level = states[level - 1].return_end_level;
}
if (input.Contains("#endif"))
{
nextState = (DEFINE_STATE)states[level].row.Field<int>((int)TABLE_COLUMN.END_IF);
}
if ((nextState != DEFINE_STATE.ERROR) && (nextState != DEFINE_STATE.DO_NOT_CARE) && (nextState != DEFINE_STATE.NONE))
{
states[level].state = nextState;
}
switch (nextState)
{
case DEFINE_STATE.DO_NOT_CARE:
//stay at current state
break;
case DEFINE_STATE.NONE: //stay at current state
Console.WriteLine("Did not find state at line {0}", line_number);
break;
case DEFINE_STATE.INVALID:
Console.WriteLine("Invalid IF/ELSE/END_IF at line {0}", line_number);
break;
case DEFINE_STATE.ERROR:
action = states[level].row.Field<ACTION>((int)TABLE_COLUMN.ACTION);
switch (action)
{
case ACTION.SET_DEFINE_LINE_NUMBER:
Console.WriteLine("Define followed by Define at line {0}", states[level].define_Line_Number.ToString());
states[level].define_Line_Number = line_number;
break;
case ACTION.SET_DEFINE_IF_LINE_NUMBER:
Console.WriteLine("Define in IF followed by Define by at line {0}", states[level].define_If_Line_Number.ToString());
states[level].define_If_Line_Number = line_number;
break;
case ACTION.SET_DEFINE_ELSE_LINE_NUMBER:
Console.WriteLine("Define in ELSE followed by Define at line {0}", states[level].define_Else_Line_Number.ToString());
states[level].define_Else_Line_Number = line_number;
break;
case ACTION.SET_DEFINE_ELIF_LINE_NUMBER :
Console.WriteLine("Define in ELIF followed by Define at line {0}", states[level].define_Elif_Line_Number.ToString());
states[level].define_Elif_Line_Number = line_number;
break;
}
break;
case DEFINE_STATE.SPECIAL:
Console.WriteLine("Define followed IF at line {0}", states[level].define_Line_Number.ToString());
states[level - 1].state = DEFINE_STATE.START;
states[level].state = DEFINE_STATE.FOUND_IF;
nextState = DEFINE_STATE.FOUND_IF;
states[level].row = dt.AsEnumerable().Where(x => x.Field<DEFINE_STATE>((int)TABLE_COLUMN.STATE) == nextState).FirstOrDefault();
break;
default:
states[level].row = dt.AsEnumerable().Where(x => x.Field<DEFINE_STATE>((int)TABLE_COLUMN.STATE) == nextState).FirstOrDefault();
action = states[level].row.Field<ACTION>((int)TABLE_COLUMN.ACTION);
switch (action)
{
case ACTION.RESET_DEFINE_LINE_NUMBER:
states[level].define_Line_Number = 0;
break;
case ACTION.RESET_DEFINE_IF_LINE_NUMBER:
states[level].define_If_Line_Number = 0;
break;
case ACTION.RESET_DEFINE_ELSE_LINE_NUMBER:
states[level].define_Else_Line_Number = 0;
break;
case ACTION.RESET_DEFINE_ELIF_LINE_NUMBER:
states[level].define_Elif_Line_Number = 0;
break;
case ACTION.SET_DEFINE_LINE_NUMBER:
states[level].define_Line_Number = line_number;
break;
case ACTION.SET_DEFINE_IF_LINE_NUMBER:
states[level].define_If_Line_Number = line_number;
break;
case ACTION.SET_DEFINE_ELSE_LINE_NUMBER:
states[level].define_Else_Line_Number = line_number;
break;
case ACTION.SET_DEFINE_ELIF_LINE_NUMBER:
states[level].define_Elif_Line_Number = line_number;
break;
}
states[level].state = nextState;
break;
}
}
//final checks
int define_Line_Number = states[level].define_Line_Number;
if (define_Line_Number != 0)
{
Console.WriteLine("Define at line {0} does not have and include", define_Line_Number.ToString());
}
if (level != 0)
{
Console.WriteLine("Did not close all IFs with End_If");
}
Console.WriteLine("Done");
Console.ReadLine();
}
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.IO;
使用System.Text.RegularExpressions;
使用系统数据;
命名空间控制台应用程序1
{
公共枚举定义_状态
{
SPECIAL=-4,//定义,后跟IF
无=-3,
无效=-2,//编译将给出错误,无法发生
错误=-1,
不关心=0,
开始=1,
如果=2,则找到,
如果=3,则在\u中找到\u定义\u,
如果=4,则在\u中找到\u DEFINE\u NOT \u,
如果=5,则在中找到,
已找到\u ELSE=6,
在\u ELSE=7中找到\u DEFINE\u,
已找到包含在其他项中的项=8,
如果=9,则在中找到包含,
如果=10,则找到\u END\u,
返回=11,
找到的_ELIF=12,
在\u ELIF=13中找到\u DEFINE\u,
发现包含在ELIF=14中的,
}
公共枚举错误
{
没有错误,
定义然后定义,
定义\后接\定义\或\如果
}
公共枚举表_列
{
状态=0,
DESCRIPTION=1,
定义
包括,,
如果,,
其他的
埃利夫,
如果,
错误,
行动
}
公开枚举操作
{
没有一个
重置\u定义\u行\u编号,
重置\u定义\u如果\u行\u编号,
重置\u定义\u其他\u行\u编号,
重置\u定义\u删除线\u编号,
设置\u定义\u行\u编号,
设置定义如果行编号,
设置\u定义\u其他\u行\u编号,
设置\u定义\u线\u编号,
}
公共类状态变量
{
公共整数定义线数=0;
如果线号=0,则定义公共整数;
public int define_Else_Line_Number=0;
public int define_Elif_Line_Number=0;
公共整数返回\结束\级别=0;
public DEFINE_STATE STATE=DEFINE_STATE.START;
公共数据行{get;set;}
}
班级计划
{
常量字符串文件名=@“c:\temp\test.txt”;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
using System.Data;
namespace ConsoleApplication1
{
public enum DEFINE_STATE
{
SPECIAL = -4, //define followed by IF
NONE = -3,
INVALID = -2, //Compile will give error, cannot occur
ERROR = -1,
DO_NOT_CARE = 0,
START = 1,
FOUND_IF = 2,
FOUND_DEFINE_IN_IF = 3,
FOUND_DEFINE_NOT_IN_IF = 4,
FOUND_INCLUDE_IN_IF = 5,
FOUND_ELSE = 6,
FOUND_DEFINE_IN_ELSE = 7,
FOUND_INCLUDE_IN_ELSE = 8,
FOUND_INCLUDE_NOT_IN_IF = 9,
FOUND_END_IF = 10,
RETURN = 11,
FOUND_ELIF = 12,
FOUND_DEFINE_IN_ELIF = 13,
FOUND_INCLUDE_IN_ELIF = 14,
}
public enum ERROR
{
NO_ERROR,
DEFINE_FOLLOWED_BY_DEFINE,
DEFINE_FOLLOWED_BY_DEFINE_OR_IF
}
public enum TABLE_COLUMN
{
STATE = 0,
DESCRIPTION = 1,
DEFINE,
INCLUDE,
IF,
ELSE,
ELIF,
END_IF,
ERROR,
ACTION
}
public enum ACTION
{
NONE,
RESET_DEFINE_LINE_NUMBER,
RESET_DEFINE_IF_LINE_NUMBER,
RESET_DEFINE_ELSE_LINE_NUMBER,
RESET_DEFINE_ELIF_LINE_NUMBER,
SET_DEFINE_LINE_NUMBER,
SET_DEFINE_IF_LINE_NUMBER,
SET_DEFINE_ELSE_LINE_NUMBER,
SET_DEFINE_ELIF_LINE_NUMBER,
}
public class State_Variables
{
public int define_Line_Number = 0;
public int define_If_Line_Number = 0;
public int define_Else_Line_Number = 0;
public int define_Elif_Line_Number = 0;
public int return_end_level = 0;
public DEFINE_STATE state = DEFINE_STATE.START;
public DataRow row { get; set; }
}
class Program
{
const string FILENAME = @"c:\temp\test.txt";
static void Main(string[] args)
{
string pattern = "#include\\s+\"test.h\"";
StreamReader reader = new StreamReader(FILENAME);
string input = "";
DataTable dt = new DataTable();
dt.Columns.Add("State", typeof(int));
dt.Columns.Add("Description", typeof(DEFINE_STATE));
dt.Columns.Add("Next Define State", typeof(int));
dt.Columns.Add("Next Include State", typeof(int));
dt.Columns.Add("Next IF State", typeof(int));
dt.Columns.Add("Next Else State", typeof(int));
dt.Columns.Add("Next ELIF State", typeof(int));
dt.Columns.Add("Next ENDIF State", typeof(int));
dt.Columns.Add("Error Number", typeof(ERROR));
dt.Columns.Add("Action", typeof(ACTION));
//0 do not care
//-1 error
//-2 invalid
dt.Rows.Add(new object[] { 1, DEFINE_STATE.START, 4, 0, 2, -2, -2, -2, ERROR.NO_ERROR, ACTION.NONE });
dt.Rows.Add(new object[] { 2, DEFINE_STATE.FOUND_IF, 3, 0, 2, 6, 12, 10, ERROR.NO_ERROR, ACTION.NONE });
dt.Rows.Add(new object[] { 3, DEFINE_STATE.FOUND_DEFINE_IN_IF, -1, 5, 2, 6, 12, 10, ERROR.DEFINE_FOLLOWED_BY_DEFINE, ACTION.SET_DEFINE_IF_LINE_NUMBER });
dt.Rows.Add(new object[] { 4, DEFINE_STATE.FOUND_DEFINE_NOT_IN_IF, -1, 9, -4, -2, -2, -2, ERROR.DEFINE_FOLLOWED_BY_DEFINE, ACTION.SET_DEFINE_LINE_NUMBER });
dt.Rows.Add(new object[] { 5, DEFINE_STATE.FOUND_INCLUDE_IN_IF, 3, 0, 2, 6, 12, 10, ERROR.NO_ERROR, ACTION.RESET_DEFINE_IF_LINE_NUMBER });
dt.Rows.Add(new object[] { 6, DEFINE_STATE.FOUND_ELSE, 7, 0, 2, -2, -2, 10, ERROR.NO_ERROR, ACTION.NONE });
dt.Rows.Add(new object[] { 7, DEFINE_STATE.FOUND_DEFINE_IN_ELSE, -1, 8, 2, -2, -2, 10, ERROR.DEFINE_FOLLOWED_BY_DEFINE, ACTION.SET_DEFINE_ELSE_LINE_NUMBER });
dt.Rows.Add(new object[] { 8, DEFINE_STATE.FOUND_INCLUDE_IN_ELSE, 7, 0, 2, -2, -2, 10, ERROR.NO_ERROR, ACTION.RESET_DEFINE_ELSE_LINE_NUMBER });
dt.Rows.Add(new object[] { 9, DEFINE_STATE.FOUND_INCLUDE_NOT_IN_IF, 4, 0, 2, -2, -2, -2, ERROR.NO_ERROR, ACTION.RESET_DEFINE_LINE_NUMBER });
dt.Rows.Add(new object[] { 10, DEFINE_STATE.FOUND_END_IF, 11, 1, 2, -2, -2, -2, ERROR.NO_ERROR, ACTION.NONE });
dt.Rows.Add(new object[] { 11, DEFINE_STATE.RETURN, -2, -2, 2, -2, -2, -2, ERROR.NO_ERROR, ACTION.NONE });
dt.Rows.Add(new object[] { 12, DEFINE_STATE.FOUND_ELIF, 13, 0, 2, -2, 12, 10, ERROR.NO_ERROR, ACTION.NONE });
dt.Rows.Add(new object[] { 13, DEFINE_STATE.FOUND_DEFINE_IN_ELIF, -1, 14, 2, -2, 12, 10, ERROR.DEFINE_FOLLOWED_BY_DEFINE, ACTION.SET_DEFINE_ELIF_LINE_NUMBER });
dt.Rows.Add(new object[] { 14, DEFINE_STATE.FOUND_INCLUDE_IN_ELIF, 13, 0, 2, 7, 12, 10, ERROR.NO_ERROR, ACTION.RESET_DEFINE_ELIF_LINE_NUMBER });
int level = 0;
List<State_Variables> states = new List<State_Variables>();
State_Variables newState = new State_Variables();
states.Add(newState);
DEFINE_STATE nextState = DEFINE_STATE.START;
ACTION action = ACTION.NONE;
int line_number = 0;
while ((input = reader.ReadLine()) != null)
{
line_number++;
input = input.Trim();
if (input.StartsWith("//")) continue; //ignore comments
if (input.Length == 0) continue;
Boolean returnFromIF = false;
Match match = Regex.Match(input, pattern);
//test if end if is followed by include
if (states[level].state == DEFINE_STATE.FOUND_END_IF)
{
int return_end_level = 0;
do
{
if (!match.Success)
{
int define_If_Line_Number = states[level].define_If_Line_Number;
int define_Else_Line_Number = states[level].define_Else_Line_Number;
int define_Elif_Line_Number = states[level].define_Elif_Line_Number;
if (define_If_Line_Number != 0)
{
Console.WriteLine("Define in IF at line {0} does not have and include", define_If_Line_Number.ToString());
}
if (define_Else_Line_Number != 0)
{
Console.WriteLine("Define in ELSE at line {0} does not have and include", define_Else_Line_Number.ToString());
}
if (define_Elif_Line_Number != 0)
{
Console.WriteLine("Define in ELSE at line {0} does not have and include", define_Else_Line_Number.ToString());
}
}
return_end_level = states[level].return_end_level;
states.RemoveAt(level--);
} while (level > return_end_level);
returnFromIF = true;
}
else
{
states[level].row = dt.AsEnumerable().Where(x => x.Field<int>((int)TABLE_COLUMN.STATE) == (int)states[level].state).FirstOrDefault();
}
nextState = DEFINE_STATE.NONE;
//check if defines are terminated with include
if (input.Contains("#define"))
{
nextState = (DEFINE_STATE)states[level].row.Field<int>((int)TABLE_COLUMN.DEFINE);
}
if (match.Success)
{
if (returnFromIF)
{
nextState = states[level].state;
}
else
{
nextState = (DEFINE_STATE)states[level].row.Field<int>((int)TABLE_COLUMN.INCLUDE);
}
}
if (input.Contains("#if"))
{
nextState = (DEFINE_STATE)states[level].row.Field<int>((int)TABLE_COLUMN.IF);
states.Add(new State_Variables());
level++;
states[level].return_end_level = level - 1;
}
if (input.Contains("#else"))
{
nextState = (DEFINE_STATE)states[level].row.Field<int>((int)TABLE_COLUMN.ELSE);
}
if (input.Contains("#elif"))
{
nextState = (DEFINE_STATE)states[level].row.Field<int>((int)TABLE_COLUMN.ELIF);
states.Add(new State_Variables());
level++;
states[level].return_end_level = states[level - 1].return_end_level;
}
if (input.Contains("#endif"))
{
nextState = (DEFINE_STATE)states[level].row.Field<int>((int)TABLE_COLUMN.END_IF);
}
if ((nextState != DEFINE_STATE.ERROR) && (nextState != DEFINE_STATE.DO_NOT_CARE) && (nextState != DEFINE_STATE.NONE))
{
states[level].state = nextState;
}
switch (nextState)
{
case DEFINE_STATE.DO_NOT_CARE:
//stay at current state
break;
case DEFINE_STATE.NONE: //stay at current state
Console.WriteLine("Did not find state at line {0}", line_number);
break;
case DEFINE_STATE.INVALID:
Console.WriteLine("Invalid IF/ELSE/END_IF at line {0}", line_number);
break;
case DEFINE_STATE.ERROR:
action = states[level].row.Field<ACTION>((int)TABLE_COLUMN.ACTION);
switch (action)
{
case ACTION.SET_DEFINE_LINE_NUMBER:
Console.WriteLine("Define followed by Define at line {0}", states[level].define_Line_Number.ToString());
states[level].define_Line_Number = line_number;
break;
case ACTION.SET_DEFINE_IF_LINE_NUMBER:
Console.WriteLine("Define in IF followed by Define by at line {0}", states[level].define_If_Line_Number.ToString());
states[level].define_If_Line_Number = line_number;
break;
case ACTION.SET_DEFINE_ELSE_LINE_NUMBER:
Console.WriteLine("Define in ELSE followed by Define at line {0}", states[level].define_Else_Line_Number.ToString());
states[level].define_Else_Line_Number = line_number;
break;
case ACTION.SET_DEFINE_ELIF_LINE_NUMBER :
Console.WriteLine("Define in ELIF followed by Define at line {0}", states[level].define_Elif_Line_Number.ToString());
states[level].define_Elif_Line_Number = line_number;
break;
}
break;
case DEFINE_STATE.SPECIAL:
Console.WriteLine("Define followed IF at line {0}", states[level].define_Line_Number.ToString());
states[level - 1].state = DEFINE_STATE.START;
states[level].state = DEFINE_STATE.FOUND_IF;
nextState = DEFINE_STATE.FOUND_IF;
states[level].row = dt.AsEnumerable().Where(x => x.Field<DEFINE_STATE>((int)TABLE_COLUMN.STATE) == nextState).FirstOrDefault();
break;
default:
states[level].row = dt.AsEnumerable().Where(x => x.Field<DEFINE_STATE>((int)TABLE_COLUMN.STATE) == nextState).FirstOrDefault();
action = states[level].row.Field<ACTION>((int)TABLE_COLUMN.ACTION);
switch (action)
{
case ACTION.RESET_DEFINE_LINE_NUMBER:
states[level].define_Line_Number = 0;
break;
case ACTION.RESET_DEFINE_IF_LINE_NUMBER:
states[level].define_If_Line_Number = 0;
break;
case ACTION.RESET_DEFINE_ELSE_LINE_NUMBER:
states[level].define_Else_Line_Number = 0;
break;
case ACTION.RESET_DEFINE_ELIF_LINE_NUMBER:
states[level].define_Elif_Line_Number = 0;
break;
case ACTION.SET_DEFINE_LINE_NUMBER:
states[level].define_Line_Number = line_number;
break;
case ACTION.SET_DEFINE_IF_LINE_NUMBER:
states[level].define_If_Line_Number = line_number;
break;
case ACTION.SET_DEFINE_ELSE_LINE_NUMBER:
states[level].define_Else_Line_Number = line_number;
break;
case ACTION.SET_DEFINE_ELIF_LINE_NUMBER:
states[level].define_Elif_Line_Number = line_number;
break;
}
states[level].state = nextState;
break;
}
}
//final checks
int define_Line_Number = states[level].define_Line_Number;
if (define_Line_Number != 0)
{
Console.WriteLine("Define at line {0} does not have and include", define_Line_Number.ToString());
}
if (level != 0)
{
Console.WriteLine("Did not close all IFs with End_If");
}
Console.WriteLine("Done");
Console.ReadLine();
}
}
}