语法转换为Lex/Yacc

Grammar to Lex/Yacc

本文关键字:Yacc Lex 转换 语法      更新时间:2023-10-16

我已经被分配了一个项目,涉及到我使用一个语法(以BNF形式)并创建一个词法扫描程序(使用lex)和一个解析器(使用bison)。我从来没有使用过这些程序,我认为一个很好的参考是看看这些项目是如何从语法中创建的。我正在寻找一个语法,它的关联。l和。ypp文件,最好在c++。我已经能够找到示例文件或示例语法,但不是两者都能找到。我花了些时间找,但什么也没找到。我想我应该贴在这里,希望有人能给我一些东西,但我将继续寻找在此期间。

我正在读Tom Niemann的书http://epaperpress.com/lexandyacc/download/LexAndYaccTutorial.pdf这似乎写得很好,可以理解。

感谢

编辑:我还在寻找,我开始认为我正在寻找的不存在。谷歌通常不会让我失望!

编辑2:也许如果我提供一些语法,你们可以告诉我合适的。l和。ypp文件是什么样子的。这只是语法的一小部分,我只需要稍微"尝尝"一下它是如何工作的,我想我可以从那里开始。 语法:

Program ::= Compound
Statements ::= Compound | Assignment | ...
Assignment ::= Var ASSIGN Expression
Expression ::= Var | Operator Expression Expression | Number
Compound := START Statements END
Number ::= NUMBER

描述:

Assignment is the equal sign ":="
Var is an identifier that begins with a lower case letter and is followed by lower case letters or digits
START is the "start" keyword
END is the "end keyword
Operator is "+", "-", "*", "/"
Number is decimal digits which could potentially be negative (minus sign in front)

大部分操作都相当简单。然而,有一部分显然有问题。您已经定义了一个数字(可能)包含一个前导-,这是一个问题。

这个问题很简单。给定像321-123这样的输入,词法分析器(通常不会跟踪当前状态)基本上不可能猜测这是两个令牌(321-123还是三个321, -, 123)。在这种情况下,-几乎肯定是打算与123分开的,但如果输入是321 + -123,您显然希望将-123作为单个令牌。

为了解决这个问题,可能要更改语法,以便前导-不是数字的一部分。相反,您总是希望将-视为一个运算符,并且该数字本身仅由数字组成。然后由解析器来对-是一元还是二进制的表达式进行排序。 考虑到这一点,词法分析器文件看起来像这样:
%{
#include "y.tab.h"
%}
%option noyywrap case-insensitive  
%%
:=        { return ASSIGN;   }
start     { return START;    }
end       { return END;      }
[+/*]     { return OPERATOR; }
-         { return MINUS;    }
[0-9]+    { return NUMBER;   }
[a-z][a-z0-9]* { return VAR; }
[ rn]   { ; }
%%
void yyerror(char const *s) { fputs(s, stderr); }

匹配的yacc文件看起来像这样:

%token ASSIGN START END OPERATOR MINUS NUMBER VAR
%left '-' '+' '*' '/'
%%
program : compound
statement : compound
            | assignment
            ;
assignment : VAR ASSIGN expression
            ;
statements :
            | statements statement
            ;
expression : VAR
            | expression OPERATOR expression 
            | expression MINUS expression
            | value
            ;
value: NUMBER
     | MINUS NUMBER
     ;          
compound : START statements END
%%
int main() {
    yyparse();
    return 0;
}

注意:我只测试了这些极其最低限度-足以验证我认为是语法的输入,例如:start a:=1 b:=2 endstart a:=1+3*3 b:=a+4 c:=b*3 end被接受(没有打印出错误消息)和我认为是不语法的输入,例如:9:=13a=13 都打印出syntax error消息。因为这并没有尝试对表达式做更多的事情,只是识别那些符合或不符合语法的表达式,这是我们所能做的最好的了。