C++ 使用yacc和readline解析行
我开始为管理图形的单一语言编写一个light解释器。我正在使用flex和bison,在定义语法时遇到了一些问题 现在,我只想分析三个单独的命令:C++ 使用yacc和readline解析行,c++,parsing,bison,readline,yacc,C++,Parsing,Bison,Readline,Yacc,我开始为管理图形的单一语言编写一个light解释器。我正在使用flex和bison,在定义语法时遇到了一些问题 现在,我只想分析三个单独的命令: 加载“文件名” 保存“文件名” 退出 这是yacc中的语法: %{ # include <iostream> using namespace std; int yylex(void); void yyerror(char const *); %} %token LOAD SAVE RIF COD EXIT STRCON
加载“文件名”
保存“文件名”
退出
%{
# include <iostream>
using namespace std;
int yylex(void);
void yyerror(char const *);
%}
%token LOAD SAVE RIF COD EXIT STRCONST VARNAME
%%
input: line
;
line: cmd_unit '\n'
{
cout << "PARSED LINE with EOL" << endl;
}
| cmd_unit
{
cout << "PARSED LINE without EOL" << endl;
}
;
cmd_unit: LOAD STRCONST
{
cout << "PARSED LOAD" << endl;
}
| SAVE STRCONST
{
cout << "PARSED SAVE" << endl;
}
| EXIT { }
;
%%
也就是说,语法肯定是错误的,它无法识别规则
cmd_unit: LOAD STRCONST
好吧,虽然我确信我不会主宰语法世界,但我已经花了一些重要的时间来理解这个小而简单的规范,我仍然无法理解为什么它不能解析一个非常单一的规则。我几乎可以肯定这是一个愚蠢的错误,但我知道哪个是
因此,我非常感谢您的帮助。这里有一个问题:
{NEWLINE} { ++curr_lineno; return NEWLINE; }
我甚至不知道它是如何编译的,因为换行符
没有定义为令牌。我在任何地方都看不到它的任何定义(模式宏不起作用,因为它们在生成扫描仪之前就被解析了。)
由于您的语法期望'\n'
作为换行符的标记值,因此您需要返回:
{NEWLINE} { ++curr_lineno; return '\n'; }
在没有调试辅助的情况下解决这样的问题可能很棘手。幸运的是,flex和bison都提供了调试选项,这使得查看正在发生的事情变得非常简单(并且避免了在bison操作中包含您自己的跟踪消息的必要性) 对于flex,在生成扫描仪时使用
-d
标志。这将打印有关扫描仪进度的大量信息。(无论如何,在这种情况下,这似乎是最有可能的起点。)
对于bison,在生成解析器时使用-t
标志,并将全局变量yydebug
设置为非零值。由于bison跟踪取决于yydebug
全局变量(其默认值为0)的设置,因此您只需将-t
标志添加到bison调用中,就不必重新生成文件来关闭跟踪
注意:在
ID
和VARNAME
规则中,将yytext
插入语义值:
yylval.symbol = yytext;
那不行yytext
仅在下次调用yylex
之前有效,因此在执行使用语义值的bison操作时,yytext
指向的字符串将发生更改。(即使bison操作仅引用右侧的最后一个标记,这也可能是正确的,因为bison通常在决定执行缩减之前读取一个前瞻标记。)您必须复制该标记(例如使用strdup
),并记住在不再需要该值时释放它
关于风格的说明。只是个人意见,随意忽略: 就个人而言,我发现过度使用模式宏会分散注意力。您可以将该规则写成:
\n { ++curr_lineno; return '\n'; }
类似地,您可以使用Posix标准字符类来代替定义,例如,数字、大写字母等:
INTEGER [[:digit:]]+
VAR_NAME [[:alpha:]][[:alnum:]_.-]*
(在字符类中不需要反斜杠转义。)非常感谢@rici。然而,我已经做了所有你建议的mods,它还不起作用。我无法理解为什么它无法识别cmd\u装置的第二条规则。A在没有readline的情况下进行了测试,将字符串常量'load\'name'传递给它“而且还是这样fails@lrleon:使用您生成的错误消息可能不会有什么坏处:)否则,您或多或少是瞎了眼,不是吗?为什么不启用flex和bison跟踪,以便查看实际情况?对于flex,生成扫描仪时只需使用-d
标志。(无论如何,这似乎是最有可能开始的地方。)对于bison,在生成解析器时使用-t
标志,并将全局变量yydebug
设置为非零值。已修复!你的建议使我能够追踪错误的来源。标头net parser.H
包含一个enum yytokentype
,该数字与%token
规范冲突。再次感谢!是的,我是一只瞎子,因为我的编译经验不仅仅局限于学校的练习
\n { ++curr_lineno; return '\n'; }
INTEGER [[:digit:]]+
VAR_NAME [[:alpha:]][[:alnum:]_.-]*