FLEX/YACC 程序未按预期运行:无法从整数序列中获取整数值
FLEX/YACC program not behaving as expected : can't grab int value from sequence of ints
我正在尝试构建一个解析器,它采用以下格式的字符串列表并对所有元素执行加法或乘法运算:
prod 5-6_
sum _
sum 5_
sum 5-6-7_
$
应该将以下内容打印到屏幕上:
prod = 30
sum = 0
sum = 5
sum = 18
我实际得到的输出是这样的:
prod = 0
sum = 0
sum = 5
sum = 5
我的 lex 文件如下所示:
%{
#include <iostream>
#include "y.tab.h"
using namespace std;
extern "C" int yylex();
%}
%option yylineno
digit [0-9]
integer {digit}+
operator "sum"|"prod"
%%
{integer} { return number; }
{operator} { return oper; }
"-" { return '-'; }
"_" { return '_'; }
"$" { return '$'; }
\n { ; }
[\t ]+ { ; }
. { cout << "unknown char" << endl; }
%%
我的 yacc 文件如下所示:
%token oper
%token number
%token '-'
%token '_'
%token '$'
%start valid
%{
#include <iostream>
#include <string>
#include <cstdio>
#include <cstdlib>
using namespace std;
#define YYSTYPE int
extern FILE *yyin;
extern char yytext[];
extern "C" int yylex();
int yyparse();
extern int yyerror(char *);
char op;
%}
%%
valid : expr_seq endfile {}
| {}
;
expr_seq : expr {}
| expr_seq expr {}
;
expr : op sequence nl {if (op == '+') cout << "sum = " ; else cout << "prod = ";}
| op nl {if (op == '+') cout << "sum = 0"; else cout <<"prod = 1";}
;
op : oper { if (yytext[0] == 's') op = '+'; else op = '*';}
;
sequence : number { $$ = atoi(yytext);}
| sequence '-' number { if (op == '+') $$ = + ; else $$ = * ;}
;
nl : '_' { cout << endl;}
;
endfile : '$' {}
;
%%
int main(int argc, char *argv[])
{
++argv, --argc;
if(argc > 0) yyin = fopen(argv[0], "r");
else yyin = stdin;
yyparse();
return 0;
}
int yyerror(char * msg)
{
extern int yylineno;
cerr << msg << "on line # " << yylineno << endl;
return 0;
}
我对 yacc 逻辑的推理如下:
- 文件只有在包含一系列表达式后跟结束文件符号时才有效。
- 表达式序列是单个表达式或多个表达式。
- 表达式可以是运算符后跟换行符,也可以是运算符后跟数字列表,后跟换行符。
- 运算符是 'sum' 或 'prod'
- 数字列表可以是一个数字,也可以是用“-”符号分隔的多个数字。
从我的角度来看,这应该可行,但出于某种原因,它无法正确解释第一个元素之后的数字序列。任何提示都会有所帮助。
谢谢
您不得在 yacc 操作中使用 yytext
。 yytext
仅在扫描器操作期间有效,并且解析器通常会提前读取到下一个标记。 (事实上,yacc 总是读取下一个标记。Bison 有时不会,但它并不总是很容易预测。)
您可以将语义值与每个标记(和非终结符)相关联,并且可以在 yacc 操作中使用 </code>、<code>
等引用这些语义值。您甚至可以将不同类型的语义值关联到不同的语法符号。如果你使用 bison —— 你可能正在使用 bison —— 你可以给语法符号命名,以便更容易引用它们的语义值。
在 bison manual.
中通过示例对所有内容进行了深入解释
有效的解决方案只是更改以下几行:
sequence : number { $$ = atoi(yytext);}
| sequence '-' number { if (op == '+') $$ = + ; else $$ = * ;}
;
对此:
sequence : number { $$ = atoi(yytext);}
| sequence '-' number { if (op == '+') $$ = + atoi(yytext); else $$ = * atoi(yytext);}
;
我正在尝试构建一个解析器,它采用以下格式的字符串列表并对所有元素执行加法或乘法运算:
prod 5-6_
sum _
sum 5_
sum 5-6-7_
$
应该将以下内容打印到屏幕上:
prod = 30
sum = 0
sum = 5
sum = 18
我实际得到的输出是这样的:
prod = 0
sum = 0
sum = 5
sum = 5
我的 lex 文件如下所示:
%{
#include <iostream>
#include "y.tab.h"
using namespace std;
extern "C" int yylex();
%}
%option yylineno
digit [0-9]
integer {digit}+
operator "sum"|"prod"
%%
{integer} { return number; }
{operator} { return oper; }
"-" { return '-'; }
"_" { return '_'; }
"$" { return '$'; }
\n { ; }
[\t ]+ { ; }
. { cout << "unknown char" << endl; }
%%
我的 yacc 文件如下所示:
%token oper
%token number
%token '-'
%token '_'
%token '$'
%start valid
%{
#include <iostream>
#include <string>
#include <cstdio>
#include <cstdlib>
using namespace std;
#define YYSTYPE int
extern FILE *yyin;
extern char yytext[];
extern "C" int yylex();
int yyparse();
extern int yyerror(char *);
char op;
%}
%%
valid : expr_seq endfile {}
| {}
;
expr_seq : expr {}
| expr_seq expr {}
;
expr : op sequence nl {if (op == '+') cout << "sum = " ; else cout << "prod = ";}
| op nl {if (op == '+') cout << "sum = 0"; else cout <<"prod = 1";}
;
op : oper { if (yytext[0] == 's') op = '+'; else op = '*';}
;
sequence : number { $$ = atoi(yytext);}
| sequence '-' number { if (op == '+') $$ = + ; else $$ = * ;}
;
nl : '_' { cout << endl;}
;
endfile : '$' {}
;
%%
int main(int argc, char *argv[])
{
++argv, --argc;
if(argc > 0) yyin = fopen(argv[0], "r");
else yyin = stdin;
yyparse();
return 0;
}
int yyerror(char * msg)
{
extern int yylineno;
cerr << msg << "on line # " << yylineno << endl;
return 0;
}
我对 yacc 逻辑的推理如下:
- 文件只有在包含一系列表达式后跟结束文件符号时才有效。
- 表达式序列是单个表达式或多个表达式。
- 表达式可以是运算符后跟换行符,也可以是运算符后跟数字列表,后跟换行符。
- 运算符是 'sum' 或 'prod'
- 数字列表可以是一个数字,也可以是用“-”符号分隔的多个数字。
从我的角度来看,这应该可行,但出于某种原因,它无法正确解释第一个元素之后的数字序列。任何提示都会有所帮助。
谢谢
您不得在 yacc 操作中使用 yytext
。 yytext
仅在扫描器操作期间有效,并且解析器通常会提前读取到下一个标记。 (事实上,yacc 总是读取下一个标记。Bison 有时不会,但它并不总是很容易预测。)
您可以将语义值与每个标记(和非终结符)相关联,并且可以在 yacc 操作中使用 </code>、<code>
等引用这些语义值。您甚至可以将不同类型的语义值关联到不同的语法符号。如果你使用 bison —— 你可能正在使用 bison —— 你可以给语法符号命名,以便更容易引用它们的语义值。
在 bison manual.
中通过示例对所有内容进行了深入解释有效的解决方案只是更改以下几行:
sequence : number { $$ = atoi(yytext);}
| sequence '-' number { if (op == '+') $$ = + ; else $$ = * ;}
;
对此:
sequence : number { $$ = atoi(yytext);}
| sequence '-' number { if (op == '+') $$ = + atoi(yytext); else $$ = * atoi(yytext);}
;