Lex / Yacc的语法

时间:2014-05-10 20:51:42

标签: c++ grammar bison lex

我的任务是一个项目,涉及我采用语法(以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)

1 个答案:

答案 0 :(得分:2)

大部分内容相当简单。然而,其中一部分显然有问题。您已定义了一个号码(可能)包含一个前导-,这是一个问题。

问题很简单。给定像321-123这样的输入,对于词法分析器(它通常不会跟踪当前状态)来说,基本上不可能猜测这是否应该是两个令牌({ {1}}和321或三个-123321-)。在这种情况下,123几乎肯定会与-分开,但如果输入为123,您显然希望321 + -123为单个令牌代替。

为了解决这个问题,你可能想要改变你的语法,因此领先的-123不是数字的一部分。相反,您总是希望将-视为运算符,而数字本身仅由数字组成。然后由解析器来整理-一元与二元的表达式。

考虑到这一点,lexer文件看起来像这样:

-

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

%{
#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); }

注意:我已经对这些进行了最低限度的测试 - 足以验证我认为具有语法性的输入,例如:%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 end9:=13 都打印出a=13条消息。由于这并没有尝试用表达式做更多的事情而不是识别那些语法上的语法,所以我们可以做到最好。