Lex - 显示语法错误的 yacc 程序
Lex - yacc program showing syntax error
下面的两段代码是为了对输入进行算术运算而写的,但是一直给我语法错误
这是 lex 程序
%{
#include "y.tab.h"
#include <stdlib.h>
%}
%%
[0-9]+ {yylval = atoi(yytext);return ID;}
[*-+/()] {return yytext[0];}
'\n' {return END;}
. {return yytext[0];}
%%
这是 yacc 程序:
%{
#include <stdio.h>
#include <stdlib.h>
#include "y.tab.h"
%}
%token ID END
%%
S: expr END { printf("Answer is : %d\n",$$); exit(1); }
expr: ID
|
| expr '+' expr { $$ = +;}
| expr '-' expr { $$ = -;}
| expr '*' expr { $$ = *;}
| expr '/' expr { $$ = /;}
| '(' expr ')' {$$ = ;}
;
%%
int main()
{
yyparse();
}
输出:
2+3
2+3
Syntax error
可能是什么问题?
存在三个问题
第一个问题是你的语法只识别一个表达式:
S: expr END { printf("Answer is : %d\n",$$); exit(1); }
因此,如果您输入两个表达式,则会出现语法错误。
第二个问题是您的扫描仪实际上并没有将换行符识别为 END
标记:
'\n' {return END;}
' 不是 (f)lex 的特殊字符。 (有关可接受的模式字符的完整列表,请参阅 Flex manual。)所以该规则正在查找三个字符:一个撇号、一个换行符和另一个撇号。如果您提供该输入,您将获得 "expected" 输出:
$ ./badexpr
2+3'
'
Answer is : 5
$
你想写的是
\n { return END; }
但这可能也不理想。那将 return 紧接在单个表达式之后。一个更有趣的语法将允许任意数量的表达式:
file.l
%{
#include <stdlib.h>
#include "y.tab.h"
%}
%%
[0-9]+ {yylval = atoi(yytext);return ID;}
.|\n {return yytext[0];}
file.y
%{
#include <stdio.h>
#include <stdlib.h>
%}
%token ID
%%
S: /* %empty */
| S expr '\n' { printf("Answer is : %d\n",); }
| S '\n'
expr: ID
| expr '+' expr { $$ = +;}
| expr '-' expr { $$ = -;}
| expr '*' expr { $$ = *;}
| expr '/' expr { $$ = /;}
| '(' expr ')' {$$ = ;}
;
%%
int main()
{
yyparse();
}
改动:
- 我从 flex 输入中删除了所有 single-character 模式,因为它们都具有相同的效果:return 单个字符读取。由于以下更改,这包括换行符。
- 我更改了语法的开始产生式,以便它明确查找换行符(而不是
END
)并接受任意数量的输入行。
- 我从 bison 输入中删除了
#include "y.tab.h"
,因为不需要在解析器文件中包含解析器 header。
- 我将
expr
的空产生式移到了 S
产生式中,这样它就不会尝试打印空表达式的值。
最后,您尝试在开始制作时明确识别 END
令牌。这可能有效,但不推荐这样做。
Yacc/bison 通过添加一个看起来与您的规则 S
完全一样的外部规则来自动扩充您的语法:它识别开头 non-terminal 后跟 END
。所以不需要添加你自己的作品。
下面的两段代码是为了对输入进行算术运算而写的,但是一直给我语法错误 这是 lex 程序
%{
#include "y.tab.h"
#include <stdlib.h>
%}
%%
[0-9]+ {yylval = atoi(yytext);return ID;}
[*-+/()] {return yytext[0];}
'\n' {return END;}
. {return yytext[0];}
%%
这是 yacc 程序:
%{
#include <stdio.h>
#include <stdlib.h>
#include "y.tab.h"
%}
%token ID END
%%
S: expr END { printf("Answer is : %d\n",$$); exit(1); }
expr: ID
|
| expr '+' expr { $$ = +;}
| expr '-' expr { $$ = -;}
| expr '*' expr { $$ = *;}
| expr '/' expr { $$ = /;}
| '(' expr ')' {$$ = ;}
;
%%
int main()
{
yyparse();
}
输出:
2+3
2+3
Syntax error
可能是什么问题?
存在三个问题
第一个问题是你的语法只识别一个表达式:
S: expr END { printf("Answer is : %d\n",$$); exit(1); }
因此,如果您输入两个表达式,则会出现语法错误。
第二个问题是您的扫描仪实际上并没有将换行符识别为 END
标记:
'\n' {return END;}
' 不是 (f)lex 的特殊字符。 (有关可接受的模式字符的完整列表,请参阅 Flex manual。)所以该规则正在查找三个字符:一个撇号、一个换行符和另一个撇号。如果您提供该输入,您将获得 "expected" 输出:
$ ./badexpr
2+3'
'
Answer is : 5
$
你想写的是
\n { return END; }
但这可能也不理想。那将 return 紧接在单个表达式之后。一个更有趣的语法将允许任意数量的表达式:
file.l
%{
#include <stdlib.h>
#include "y.tab.h"
%}
%%
[0-9]+ {yylval = atoi(yytext);return ID;}
.|\n {return yytext[0];}
file.y
%{
#include <stdio.h>
#include <stdlib.h>
%}
%token ID
%%
S: /* %empty */
| S expr '\n' { printf("Answer is : %d\n",); }
| S '\n'
expr: ID
| expr '+' expr { $$ = +;}
| expr '-' expr { $$ = -;}
| expr '*' expr { $$ = *;}
| expr '/' expr { $$ = /;}
| '(' expr ')' {$$ = ;}
;
%%
int main()
{
yyparse();
}
改动:
- 我从 flex 输入中删除了所有 single-character 模式,因为它们都具有相同的效果:return 单个字符读取。由于以下更改,这包括换行符。
- 我更改了语法的开始产生式,以便它明确查找换行符(而不是
END
)并接受任意数量的输入行。 - 我从 bison 输入中删除了
#include "y.tab.h"
,因为不需要在解析器文件中包含解析器 header。 - 我将
expr
的空产生式移到了S
产生式中,这样它就不会尝试打印空表达式的值。
最后,您尝试在开始制作时明确识别 END
令牌。这可能有效,但不推荐这样做。
Yacc/bison 通过添加一个看起来与您的规则 S
完全一样的外部规则来自动扩充您的语法:它识别开头 non-terminal 后跟 END
。所以不需要添加你自己的作品。