C# 检查C中特定结构的源文件(文本文件)#

C# 检查C中特定结构的源文件(文本文件)#,c#,C#,下面是一些文本的示例(在本例中,它是C源代码,可以是任何结构化文本)。我试图读取两个长度可变、结构不同的文件,并弄清楚是否在每次\define之后都会出现\include“test.h” 同样的情况也适用于预处理器指令内外(#if、#ifdef、#ifndef、#endif)。如果在此之前正确的#定义在if指令中,则允许在#endif之后出现#include“test.h” 一些旁注: 我从文件中提取文本,执行一些操作,如删除注释、无关行、空行等,然后将文件作为字符串[]返回。这使得在行之间进行

下面是一些文本的示例(在本例中,它是C源代码,可以是任何结构化文本)。我试图读取两个长度可变、结构不同的文件,并弄清楚是否在每次
\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();
        }
    }
}