Var*_*yan 5 yacc lex bison lexical-analysis flex-lexer
我正在尝试编写一个能够使用以下输入的语法:
begin #this is a example
x = 56;
while x > 0 do
begin
point 15.6 78.96;
end;
end;
Run Code Online (Sandbox Code Playgroud)
这是 lexer.l 文件:
%option noyywrap
%{
#include "parser.h"
#include <stdlib.h>
#include <stdio.h>
const char * const unrecognizedToken = "Unrecognized token";
%}
NewLine \n
WhiteSpaces [\r\t\f\v ]+
Semicolon ;
digit [0-9]
number1 {digit}+\.?([eE][-+]?{digit}+)?
number2 {digit}*\.{digit}+([eE][-+]?{digit}+)?
double_number {number1}|{number2}
BEGIN "begin"
END "end"
WHILE "while"
DO "do"
POINT "point"
%x POINT_DEFINITIONS
%%
{WhiteSpaces} {
printf("WhiteSpaces");
printf("\n");
}
{NewLine} {
printf("NewLine");
printf("\n");
}
{WHILE} {
printf("While");
printf("\n");
return TOKEN_WHILE;
}
{BEGIN} {
printf("TOKEN_BEGIN");
printf("\n");
return TOKEN_BEGIN;
}
{END} {
printf("TOKEN_END");
printf("\n");
return TOKEN_END;
}
{DO} {
printf("DO");
printf("\n");
return TOKEN_DO;
}
{POINT} {
printf("POINT_START");
printf("\n");
BEGIN POINT_DEFINITIONS;
return TOKEN_POINT;
}
<POINT_DEFINITIONS>{double_number} {
printf("POINT_DEFINITIONS %s", yytext);
printf("\n");
yylval.dval = atof(yytext);
return TOKEN_DOUBLE;
}
<POINT_DEFINITIONS>{WhiteSpaces} {
printf("WhiteSpaces");
printf("\n");
}
[a-zA-Z_][a-zA-Z0-9_]* {
printf("TOKEN_IDENTIFIER");
printf("\n");
yylval.name = strdup(yytext);
return TOKEN_IDENTIFIER;
}
[()=;] {
printf("yytext = %s", yytext);
printf("\n");
return *yytext;
}
[*/+\-<>] {
printf("TOKEN_OPERATOR");
printf("\n");
yylval.op = *yytext;
return TOKEN_OPERATOR;
}
[-]?[0-9]+ {
printf("TOKEN_VALUE");
printf("\n");
yylval.val = atoi(yytext);
return TOKEN_VALUE;
}
#.* {
printf("COMMENT");
printf("\n");
/*comment*/
}
. { printf("%s", unrecognizedToken); }
Run Code Online (Sandbox Code Playgroud)
这是 parser.y 文件:
%error-verbose
%{
#define YYDEBUG 1
%}
%union {
int val;
double dval;
char op;
char* name;
}
%token TOKEN_BEGIN TOKEN_END TOKEN_WHILE TOKEN_DO TOKEN_POINT TOKEN_OPERATOR TOKEN_VALUE TOKEN_IDENTIFIER TOKEN_DOUBLE
%start program
%{
void yyerror(const char* const message);
%}
%%
program: statement';';
block: TOKEN_BEGIN statements TOKEN_END { printf("rule block\n"); };
statements:
statement';' statements { printf("rule statements\n"); }
|;
statement:
| assignment
| command
| whileStmt
| block;
assignment: TOKEN_IDENTIFIER '=' TOKEN_VALUE {
printf("rule Assignment\n");
} ;
whileStmt: TOKEN_WHILE condition TOKEN_DO block {printf("rule While\n");};
condition: TOKEN_IDENTIFIER { printf("rule token_identifier\n"); }
| TOKEN_VALUE { printf("rule token_value\n"); }
| condition TOKEN_OPERATOR condition { printf("rule condition TOKEN_OPERATOR condition\n"); };
command: TOKEN_POINT TOKEN_DOUBLE TOKEN_DOUBLE { printf("rule Command\n"); };
%%
#include <stdlib.h>
void yyerror(const char* const message)
{
printf("Parse error:%s\n", message);
exit(1);
}
int main()
{
yyparse();
}
Run Code Online (Sandbox Code Playgroud)
但是我收到以下错误消息:
Parse error:syntax error, unexpected $end, expecting ';'
Run Code Online (Sandbox Code Playgroud)
编译成这样:
flex -o lexer.c lexer.l
bison -v -d -o parser.c parser.y
gcc parser.c lexer.c -o parser -g -DYYDEBUG=1
Run Code Online (Sandbox Code Playgroud)
运行解析器:
./parser < example
Run Code Online (Sandbox Code Playgroud)
你能帮我找出问题所在吗?为什么语法不能接受上面的例子作为输入?
你的问题出在你的词法分析器中(与你的语法是否有问题无关 \xe2\x80\x94 我没有分析语法,因为我首先遇到了词法分析器中的问题,这就足够了以防止语法工作)。
\n\n我添加了一个main()测试lexer.l:
%%\n\nYYSTYPE yylval;\n\nint main(void)\n{\n int token;\n while ((token = yylex()) != 0)\n printf("Token: %d (%s)\\n", token, yytext);\n return 0;\n}\nRun Code Online (Sandbox Code Playgroud)\n\n然后我在您的示例代码上运行它以查看令牌流是否正确生成。我得到的输出是:
\n\nTOKEN_BEGIN\nToken: 258 (begin)\nWhiteSpaces\nCOMMENT\nNewLine\nWhiteSpaces\nTOKEN_IDENTIFIER\nToken: 265 (x)\nWhiteSpaces\nyytext = =\nToken: 61 (=)\nWhiteSpaces\nTOKEN_VALUE\nToken: 264 (56)\nyytext = ;\nToken: 59 (;)\nNewLine\nNewLine\nWhiteSpaces\nWhile\nToken: 260 (while)\nWhiteSpaces\nTOKEN_IDENTIFIER\nToken: 265 (x)\nWhiteSpaces\nTOKEN_OPERATOR\nToken: 263 (>)\nWhiteSpaces\nTOKEN_VALUE\nToken: 264 (0)\nWhiteSpaces\nDO\nToken: 261 (do)\nNewLine\nWhiteSpaces\nTOKEN_BEGIN\nToken: 258 (begin)\nNewLine\nWhiteSpaces\nPOINT_START\nToken: 262 (point)\nWhiteSpaces\nPOINT_DEFINITIONS 15.6\nToken: 266 (15.6)\nWhiteSpaces\nPOINT_DEFINITIONS 78.96\nToken: 266 (78.96)\n;\nWhiteSpaces\nend;\nend;\nRun Code Online (Sandbox Code Playgroud)\n\n正如您所看到的,最后返回到主程序的令牌是 78.96。
\n\n当您识别出一个 POINT 时,您就启动了 POINT_DEFINITIONS 状态。然而,一旦处于这种状态,你就永远处于这种状态;你永远不会回到初始状态。您可能需要向 POINT_DEFINITIONS 启动状态添加一条规则来识别分号并执行BEGIN INITIAL;:
<POINT_DEFINITIONS>{Semicolon} {\n printf("Semicolon in POINT_DEFINITION state\\n");\n BEGIN INITIAL;\n return *yytext;\n}\nRun Code Online (Sandbox Code Playgroud)\n\n完成此操作后,输出的尾部为:
\n\n...\nTOKEN_BEGIN\nToken: 258 (begin)\nNewLine\nWhiteSpaces\nPOINT_START\nToken: 262 (point)\nWhiteSpaces\nPOINT_DEFINITIONS 15.6\nToken: 266 (15.6)\nWhiteSpaces\nPOINT_DEFINITIONS 78.96\nToken: 266 (78.96)\nSemicolon in POINT_DEFINITION state\nToken: 59 (;)\nNewLine\nWhiteSpaces\nTOKEN_END\nToken: 259 (end)\npunctuation: yytext = ;\nToken: 59 (;)\nNewLine\nTOKEN_END\nToken: 259 (end)\npunctuation: yytext = ;\nToken: 59 (;)\nNewLine\nRun Code Online (Sandbox Code Playgroud)\n