我已经实现了一个解析器,但它不打印任何内容。如果给定的输入在语法上是错误的,它不会打印"错误",尽管我将其包含在yyerror()
例程中。此外,如果输入正确,则不会打印解析树。可能的原因是什么?我已将我的main()
放在.lex
文件中,而不是放在.y
文件中。这可能是原因吗?这是主要的方法:
int main( argc, argv )
int argc;
char **argv;
{
++argv, --argc;
if ( argc > 0 )
yyin = fopen( argv[0], "r" );
else
yyin = stdin;
yyparse();
}
语法文件为:
%{
#include "parser.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
%}
%union {
char* a_variable;
tree* a_tree;
}
%start file
%token <a_variable> TOKID TOKSEMICOLON TOLCOLON TOKCOMMA TOKUNRECOG TOKDOT TOKMINUS TOKCOLON
%type <a_tree> field file obj ID
%right TOKMINUS
%%
file : /*empty*/ { return NULL; }
| field file { printtree($1, 1); }
;
field : ID TOKCOLON field {$$ = make_op($1, ':', $3); }
| ID TOKCOMMA field {$$ = make_op($1, ',', $3); }
| obj { $$ = $1; }
;
obj : ID TOKSEMICOLON { $$ = make_op($1, ';', NULL); }
;
ID : TOKID { $$ = $1; }
%%
#include <stdio.h>
yyerror(char *str)
{
fprintf(stderr,"error FAIL: %sn",str);
}
int yywrap()
{
return 1;
}
这就是我的.lex
文件的样子:
%{
/* need this for the call to atof() below */
#include <math.h>
#include "parser.h"
#include "idf.tab.h"
%}
DIGIT [0-9]
ID [a-zA-Z]*
%option noyywrap
%%
{ID} |
-?{DIGIT}+"."{DIGIT}* |
-?{DIGIT}+ { yylval.a_variable = findname(yytext); return TOKID; }
";" return TOKSEMICOLON;
":" return TOKCOLON;
"," return TOKCOMMA;
"." return TOKDOT;
"-" return TOKMINUS;
. return TOKUNRECOG;
%%
int main( int argc, char** argv )
{
++argv, --argc;
if ( argc > 0 )
yyin = fopen( argv[0], "r" );
else
yyin = stdin;
yyparse();
}
我不太确定你能不能把多个规则组合成一个这样的规则:
{ID} | -?{DIGIT}+"."{DIGIT}* | -?{DIGIT}+ return TOKID;
lex对空格敏感;我认为应该是这样的:
{ID} |
-?{DIGIT}+"."{DIGIT}* |
-?{DIGIT}+ return TOKID;
|
字符被解释为一种特殊的动作,意思是"与下一行的动作相同"。在模式中,|
表示正则表达式分支。但你有所有这些空间。
你的评论匹配器看起来是假的:
"{"[^{}}n]*"}" /* eat up one-line comments */
我想你想要一个否定的字符类,但你在^
字符上放了一个转义符,这只会导致^
包含在字符类中。
这有什么意义:
"!"+"-"[n] return TOKCOMMENT;
后面跟着-和换行符的!
序列是某种注释,您不会忽略它,而是作为标记返回,wha?
这个解析规则无法正常工作,因为lexer:中的行为已损坏
ID : TOKID { $$ = $1; }
表达式$1
想要访问yystack[<whatever>].a_variable
,因为您将TOKID
定义为具有a_variable
语义类型。但是生成TOKID
的lex规则不会向a_variable
中放入任何内容。它只执行return TOKID;
,让指针包含垃圾。lexer规则必须分配给yylval.a_variable
。
Lex和Yacc远没有你想象的那么自动化。
yylex()
是词法扫描器,而不是语法分析器;解析器是CCD_ 20。因此,更新您的程序以调用yyparse()
而不是yylex()
,让yyparse()
在需要新令牌时调用yylex()
:
while (yyparse() != 0)
;
您可以打印解析树来代替空循环体,也可以在从语法本身的开始规则调用的函数中打印。
顺便说一句,我想不出有什么好的理由使用K&main()
的R声明。始终使用int main(int argc, char **argv)
。如果你使用K&R表示法,则必须从main()
返回一个值,通常成功时为零,失败时为零。尽管C99允许您省略main()
的最终返回(在main()
的唯一非常特殊的情况下,这相当于return 0;
),但我建议将其包括在内
后期注释
这是一个好主意,让人们更容易测试你寻求帮助的内容。提供足够的资源使其可编译。删除足够的源代码以最大限度地减少编译工作量。
中和语法中的各种动作功能并不难。parser.h
文件需要包含类似typedef struct tree tree;
的内容。语法需要是idf.y
,这样bison -d idf.y
就会生成idf.tab.h
和idf.tab.c
。
我对词法分析器做的第一件事是确保它打印出它正在做的事情。所以,我修改了规则,做了一些事情,比如:
{ID} |
-?{DIGIT}+"."{DIGIT}* |
-?{DIGIT}+ { printf("ID or number: %sn", yytext); /*yylval.a_variable = findname(yytext);*/ return TOKID; }
";" { printf("Semi-colonn"); return TOKSEMICOLON;}
":" { printf("Colonn"); return TOKCOLON;}
这很快就向我表明,你不会很优雅地处理空格或换行符。你可能需要规则来做到这一点(而这些规则可能不会回到语法中)。
[ t] { printf("White spacen"); }
当然,这需要出现在"吞噬点"规则之前。
有了这些,我就可以运行程序并获得词法输出:
$ ./idf
abc ;
ID or number: abc
White space
Semi-colon
$
我在上面输入了abc ;
,它确定了那些OK。由于语法在操作中没有代码,所以语法本身没有输出。可能值得使用-DYYDEBUG
进行编译,并在main()
函数中设置yydebug = 1;
—您可能需要在词法分析器源文件中添加extern int yydebug;
,因为main()
已经存在。
$ flex scanner.l
$ bison -d idf.y
$ gcc -DYYDEBUG -o idf idf.tab.c lex.yy.c
$ ./idf
Starting parse
Entering state 0
Reading a token: abc ;
ID or number: abc
Next token is token TOKID ()
Shifting token TOKID ()
Entering state 1
Reducing stack by rule 7 (line 32):
$1 = token TOKID ()
-> $$ = nterm ID ()
Stack now 0
Entering state 5
Reading a token: White space
Semi-colon
Next token is token TOKSEMICOLON ()
Shifting token TOKSEMICOLON ()
Entering state 8
Reducing stack by rule 6 (line 29):
$1 = nterm ID ()
$2 = token TOKSEMICOLON ()
-> $$ = nterm obj ()
Stack now 0
Entering state 4
Reducing stack by rule 5 (line 26):
$1 = nterm obj ()
-> $$ = nterm field ()
Stack now 0
Entering state 3
Reading a token:
Now at end of input.
Reducing stack by rule 1 (line 20):
$
现在,您的问题出现在尚未显示的函数中。这些都是你要解决的。