我的项目任务包括学习语法(BNF 形式)并创建词法扫描器(使用 lex)和解析器(使用 bison)。我从未使用过任何这些程序,我认为一个很好的引用是了解这些项目是如何从语法创建的。我正在寻找语法及其关联的 .l 和 .ypp 文件,最好是 C++ 格式的。我已经能够找到示例文件或示例语法,但不是两者都找到。我花了一些时间寻找但找不到任何东西。我想我会在这里发帖,希望有人能给我一些东西,但同时我会继续搜索。
我目前正在阅读汤姆·尼曼的著作 http://epaperpress.com/lexandyacc/download/LexAndYaccTutorial.pdf这似乎写得很好并且易于理解。
谢谢
编辑:我仍在寻找,我开始认为我正在寻找的东西不存在。 Google 通常永远不会让我失望!
编辑 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
作为单个 token 。
为了解决这个问题,您可能想要更改语法,因此前导 -
不是号码的一部分。相反,您总是想处理 -
作为运算符,数字本身仅由数字组成。然后由解析器对 -
所在的表达式进行排序。是一元与二进制。
考虑到这一点,词法分析器文件将如下所示:
%{
#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; }
[ \r\n] { ; }
%%
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 end
和start a:=1+3*3 b:=a+4 c:=b*3 end
被接受(没有打印出错误消息)并且我认为输入不符合语法,例如:9:=13
和a=13
do 都打印出 syntax error
消息。由于除了识别那些符合语法或不符合语法的表达式之外,它不会尝试对表达式做更多的事情,因此这就是我们能做的最好的事情。
关于c++ - 语法到 Lex/Yacc,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23586193/