c++ - 语法到 Lex/Yacc

标签 c++ grammar bison lex

我的项目任务包括学习语法(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 endstart a:=1+3*3 b:=a+4 c:=b*3 end被接受(没有打印出错误消息)并且我认为输入不符合语法,例如:9:=13a=13 do 都打印出 syntax error消息。由于除了识别那些符合语法或不符合语法的表达式之外,它不会尝试对表达式做更多的事情,因此这就是我们能做的最好的事情。

关于c++ - 语法到 Lex/Yacc,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23586193/

相关文章:

c++ - CMake 和 Flex/Bison

c++ - 迭代超过 10GB+ 的二进制文件

c++ - 提升精神: parse boolean expression and reduce to canonical normal form

compiler-construction - 如何将语法转换为自上而下的可解析语法

c++ - D 的语法真的是上下文无关的吗?

grammar - 不明白为什么 Bison 扔 "Rules useless in parser due to conflicts"

c++ - 将成员函数指针强制转换为另一个类并再次返回是否安全?

c++ - 固定大小参数包的状态

c++ - 多字节字符集中的_tcslen : how to convert WCHAR [1] to const char *?

grammar - Flex 和 Bison 的使用