65.9K
CodeProject 正在变化。 阅读更多。
Home

针对PIC微控制器的逆波兰表达式(RPN)编译器评估引擎1.4

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.80/5 (10投票s)

2009年4月22日

CPOL

3分钟阅读

viewsIcon

37457

downloadIcon

386

该评估引擎是一个开源的C编译器、解析器和解释器,可用于构建业务规则引擎。它允许使用数学和布尔表达式、操作数函数、变量、变量赋值、注释和短路求值。适用于PIC微控制器。

引言

这是对一篇优秀文章评估引擎的更新,作者是Donald Snowdy

我对文章做了一些修改,使其更像一个典型的C编译器。它是一个编写编译器的良好起点。稍加修改,就可以将其完成为一个真正的C编译器!通过一些修改,还可以使其成为适用于ATMega32、ATMega64系列IC的AVR编译器,或适用于PIC16F、PIC17、PIC24、PIC32的PIC编译器。

用于评估系统

当您打开一个新的控制台项目,编写一个简单的FOR循环块,添加断点并运行项目时 -

for (int i=iii; i <= 5; i++)
{
iii++;
}

在调试模式下,如果右键单击for循环块并单击“转到反汇编”,您将看到代码和相应的汇编代码。在“for”循环块的末尾,您会看到另一个“for”声明:for(int i = iii ; i<= 5; i++)

for ( int i=iii; i <= 5 ; i++; )

编译器只是将另外两句i <= 5 ; i++;复制粘贴到“FOR”块的末尾,但顺序相反i++; i <= 5 ;,并且有两个敏感的关键字

1. “FOR”关键字的结束函数括号 ')',其TokenType=Token_For_InitializeEnd,运行时指针在此处跳转到增量语句的末尾和“for条件”的开头,这意味着在FOR初始化后 - int i = 0; 将检查条件。

2. 条件检查结束:此时编译器检查条件的结果,如果结果为真,则运行时指针应跳转回for代码块的开头;如果结果为假,则继续执行。

if(eval.Count != 0) 
    if(eval.Peek().TokenName_Boolean == true) 
    {
        index = item.FOR_FirstLevel.StartTokenBlock.Position+1;
    }

您可以在下面的图片中看到此过程。

RPN_Compiler_FOR_doodle.gif

在Token.cs中解析“FOR”

下图显示了解析代码的检测图。

RPN_Compiler1_4

背景

逆波兰表达式(RPN)“if”语句求值解析

if”关键字检查语句的truefalse状态,并决定运行时指针应跳转到哪里。此编译器需要使用特定字符作为标志,如示意图1所示。“if”具有三组状态。

  1. Token_if_True:指的是“if”语句的末尾,即')',如果语句为True,则运行时指针将继续运行,直到遇到其结束点并跳转到结束点。
  2. Token_IF_False:如果语句失败,运行时指针将跳转到失败点。
  3. Token_IF_END:如果语句完成了True块或False块,运行时将跳转到结束点。

创建RPN队列后处理IF/FOR

我为文章评估引擎添加了一些代码,作者是Donald Snowdy,使其更像C编译器。

此时队列已准备好,但我们需要指定在哪里检查语句以及编译器指针应该跳转到哪里,还需要更改一些FOR标记的位置,就像我前面提到的那样,记住当循环搜索列表时,更改项目很危险,但我就是这么做了!但我使它们安全,更改只是将标记从搜索到的标记移动到列表中光标之后尚未探索的点。

            Stack<TokenItem> IF = new Stack<TokenItem>(); // list of found IF 
            Stack<TokenItem> IF_FOR_FUNC_CLASS = new Stack<TokenItem>(); //list of found IF or FOR or Function or Class Tokens to see the owning current position
            Stack<bool> EncloseInBrackets = new Stack<bool>();// bool value to see weather the opening block is Embeded in brackets or just a one line and ends with semicolon
 
            FOR = new Stack<TokenItem>(); //list of founded FOR
            Stack<TokenItem> Else = new Stack<TokenItem>(); //list of founded Else
            Stack<TokenItem> Element = new Stack<TokenItem>(); // list of all usefull element throughout search
            Stack<TokenItem> CurlyBracket = new Stack<TokenItem>(); //list of founded bracket left / right

            
            Stack<bool> isTrueBlock = new Stack<bool>();// this is useful for IF statement to see if we are at the True block of IF or we passed Else of an IF
            bool readFOR2sentense = false ; // this indicate when should we start reading two sentence of FOR for CUT and paste them
            Stack<EvaluationEngine.Support.ExQueue<TokenItem>> readedFOR2sentences = new Stack<EvaluationEngine.Support.ExQueue<TokenItem>>();//this is a stack full of queues of readed pair FOR sentences i added them to a stack for FORs that are embeded in a FOR
            TokenItem NextTok = null;
            for (int i = 0; i < rpn_queue.Count; i++)
            {
                TokenItem tok = rpn_queue[i];

                if (i + 1 < rpn_queue.Count)
                    NextTok = rpn_queue[i + 1];
                else
                    NextTok = null;


                tok.Position = i;

                if (tok.TokenName == "if(")                                                               ///   if
                {
                    //tok.TokenType = TokenType.Token_if;
                    isTrueBlock.Push(true);
                    Element.Push(tok);
                    tok.Usage = TokenItem.UsageType.IF_Related;
                    IF.Push(tok);
                    IF_FOR_FUNC_CLASS.Push(tok);


                }
                if (tok.TokenName == "for")                                                               ///   for
                {
                    FOR.Push(tok);
                    Element.Push(tok);
                    IF_FOR_FUNC_CLASS.Push(tok);
                    readedFOR2sentences.Push(new EvaluationEngine.Support.ExQueue<TokenItem>());

                }
                if (tok.TokenName == ";")
                {
                    if (Element.Count > 0 && Element.Peek().TokenName == "for")
                    {

                        readFOR2sentense = true;

                    }
                }

                if (tok.TokenName == "{")                                                                  ///   {
                {
                    if ((Element.Peek().TokenName == "]" && Element.Peek().IF_FirstLevel != null) || (Element.Peek().TokenName == "else" && Element.Peek().IF_FirstLevel != null))
                        tok.Usage = TokenItem.UsageType.IF_Related;
                    if (Element.Peek().TokenName == "]" && Element.Peek().FOR_FirstLevel != null)
                        tok.Usage = TokenItem.UsageType.FOR_Related;
                    CurlyBracket.Push(tok);


                    Element.Push(tok);
                    tok.TokenType = TokenType.LeftCurlyBracket;

                }
                if (tok.TokenName == "]")                                                                ///   ]
                {
                    if (readFOR2sentense == true)
                    {
                        readFOR2sentense = false;
                        //readedFOR2sentences.Enqueue(new TokenItem(";", TokenType.Token_Assignment_Stop, TokenDataType.Token_DataType_None,false  )); 
                    }
                    if (tok.IF_FirstLevel != null && isTrueBlock.Peek() && !(isTrueBlock.Peek() == true && tok.TokenName == "{"))
                    {
                        tok.TokenType = TokenType.Token_if_True;
                        tok.Usage = TokenItem.UsageType.IF_Related;
                        tok.IF_FirstLevel.IF_TruePosition = i;
                        Element.Push(tok);
                        if (NextTok != null && NextTok.TokenName == "{")
                            tok.IF_TrueIsWithinBracket = true;
                    }
                    if (tok.FOR_FirstLevel != null)
                    {
                        //tok.TokenType = TokenType.Token_if_True;
                       // tok.FOR_FirstLevel.FOR_CondithionToken = tok;
                        Element.Push(tok);
                        tok.FOR_FirstLevel.StartTokenBlock = tok;
                        tok.TokenType = TokenType.Token_FOR_InitializeEnd;
                    }
                    if (tok.FOR_FirstLevel != null || tok.IF_FirstLevel != null)
                        if (NextTok!=null && NextTok.TokenName == "{") EncloseInBrackets.Push(true); else EncloseInBrackets.Push(false);
                }


                if (readFOR2sentense)
                    readedFOR2sentences.Peek().Enqueue(tok);

 

                if (tok.TokenName == "else")                                                               ///   else
                {
                    Element.Push(tok);
                    Else.Push(tok);
                    tok.Usage = TokenItem.UsageType.IF_Related;
                    tok.IF_FirstLevel = IF.Peek();
                    isTrueBlock.Pop();
                    isTrueBlock.Push(false);
                    IF.Peek().FalseToken = tok;
                    tok.TokenType = TokenType.Token_IF_False;
                    if (tok.FOR_FirstLevel != null || tok.IF_FirstLevel != null)
                        if (NextTok!=null && NextTok.TokenName == "{") EncloseInBrackets.Push(true); else EncloseInBrackets.Push(false);

                }

 

 

                if (tok.TokenName == ";" || tok.TokenName == "}")   ///E                                                               ///   ;
                {
                    //if (isTrueBlock.Count > 0 && CurlyBracket.Count != 0 && CurlyBracket.Peek().Usage == TokenItem.UsageType.IF_Related)

                    if (Element.Count > 0)
                        if (tok.TokenName == ";" && (Element.Peek().TokenName == "]" || Element.Peek().TokenName == "else") || (tok.TokenName == "}"  && CurlyBracket.Count != 0))
                        {
                            //if (IF_FOR_FUNC_CLASS.Peek().TokenName == "if(")
                            //{

                            #region GoUp IF
                            while (IF_FOR_FUNC_CLASS.Count > 0)
                            {
                                if (IF_FOR_FUNC_CLASS.Peek().Usage == TokenItem.UsageType.IF_Related)
                                {
                                    if (EncloseInBrackets.Peek() == true && tok.TokenName == ";") break;
                                        if (isTrueBlock.Peek() == true)
                                        {
                                                IF.Peek().EndTokenBlock = tok;
                                                IF.Peek().FalseToken = tok;
                                                if (NextTok == null || NextTok.TokenName != "else")
                                                {
                                                    IF.Pop();
                                                    IF_FOR_FUNC_CLASS.Pop();
                                                    isTrueBlock.Pop();
                                                }
                                                if (EncloseInBrackets.Peek() == true )
                                                    CurlyBracket.Pop();
                                                EncloseInBrackets.Pop();
                                                if (EncloseInBrackets.Peek() == true) break;
                                        }
                                        else
                                        {
                                            isTrueBlock.Pop();
                                            IF.Peek().EndTokenBlock = tok;
                                            IF.Pop();
                                            IF_FOR_FUNC_CLASS.Pop();

                                            if (EncloseInBrackets.Peek() == true )
                                                CurlyBracket.Pop();
                                            EncloseInBrackets.Pop();
                                            if (EncloseInBrackets.Peek() == true) break;
                                        }
                                }
                                else
                                    if (IF_FOR_FUNC_CLASS.Count > 0 && IF_FOR_FUNC_CLASS.Peek().Usage == TokenItem.UsageType.FOR_Related)
                                    {

 

 

                                        FOR.Peek().EndTokenBlock = tok;
                                        tok.FOR_FirstLevel = FOR.Peek();
                                        FOR.Pop();

                                        IF_FOR_FUNC_CLASS.Pop();
                                        readedFOR2sentences.Peek().Dequeue();

                                        bool found = false;
                                        for (int ii = 0; ii < readedFOR2sentences.Peek().Count; ii++) ///for(;;i++)
                                        {
                                            if (found == true)
                                            {
                                                ///
                                                rpn_queue.Insert(i, readedFOR2sentences.Peek()[ii]);
                                                ///
                                            }
                                            if (readedFOR2sentences.Peek()[ii].TokenName == ";")
                                            {
                                                if (found == true)
                                                {
                                                    tok.FOR_FirstLevel.FOR_ConditionToken = readedFOR2sentences.Peek()[ii];
                                                    break;
                                                }
                                                found = true;
                                                //break;
                                            }
                                        }
                                        found = false;
                                        for (int ii = 0; ii < readedFOR2sentences.Peek().Count; ii++)///for(;i>3;)
                                        {
                                            ///
                                            rpn_queue.Insert(i, readedFOR2sentences.Peek()[ii]);
                                            ///
                                            if (readedFOR2sentences.Peek()[ii].TokenName == ";")
                                            {
                                                readedFOR2sentences.Peek()[ii].TokenType = TokenType.Token_FOR_ConditionEnd;
                                                readedFOR2sentences.Peek()[ii].FOR_FirstLevel = tok.FOR_FirstLevel;
                                                tok.FOR_FirstLevel.TrueToken = readedFOR2sentences.Peek()[ii];
                                                break;
                                            }
                                        }

                                        while (readedFOR2sentences.Peek().Count > 0) readedFOR2sentences.Peek().Dequeue().Usage = TokenItem.UsageType.FOR_Related;
                                        readedFOR2sentences.Pop();


                                        if (EncloseInBrackets.Peek() == true)
                                            CurlyBracket.Pop();
                                        EncloseInBrackets.Pop();
                                        if (EncloseInBrackets.Count ==0 || EncloseInBrackets.Peek() == true) 
                                            break;

 

 


                                    }

                            }
                            #endregion


                            Element.Push(tok);

                        }

                }

 


            }
            for (int i = 0; i < rpn_queue.Count; i++)
            {
                rpn_queue[i].Position = i ;
            }

历史

版本 描述 状态
1.1 使用括号表示函数 sin[3*3.14] --> sin(3*3.14),并释放方括号以供进一步使用。

完成/测试通过

1.2 将等式从 = 更改为 ==,使其更像 C#,并将赋值运算符从 := 更改为 =。

完成/测试通过

1.3 添加if(语句作为比较函数和相关的处理。

完成/测试通过

1.4 添加for(语句作为函数和相关的处理。

完成/测试中

1.5 添加函数声明和块处理,以及所有参数的压栈和弹出以供执行。 进行中
1.6 将RPN队列转换为PIC汇编代码。

待办事项

关注点

要获取在我的网站上提供的电子软件列表,请点击这里

您也可以在线与我聊天

consult.gif

© . All rights reserved.