我希望我的代码能够打印输入文件中出现的语法错误的数量。这是我的代码:
%{
#include <stdio.h>
#include <math.h>
void yyerror(char *);
extern int yylval;
extern FILE *yyin;
extern FILE *yyout;
extern yylineno;
extern int yyparse(void);
extern int yylex(void);
extern int yywrap() { return 1; }
extern char* yytext;
int errors;
%}
%debug
%start m_class
%token IF ELSE INT CHAR CLASS NEW GURISE VOID WHILE
%token PUBLIC PROTECTED PRIVATE STATIC FINAL ABSTRACT
%token PLUS MINUS MUL DIV MODULO
%token EQ NEQ GRT LT GREQ LEQ
%token OR AND NOT
%token AR_PAR DEK_PAR AR_AGK DEK_AGK AR_STRO DEK_STRO
%token SEMICOLON ANATHESI COMA
%token MY_INT SINT MY_CHAR ID
%right ANATHESI
%left OR AND
%nonassoc EQ NEQ GRT LT GREQ LEQ
%left PLUS MINUS MUL DIV MODULO
%right NOT
%right "then" ELSE
%%
m_class: m_class class_declaration
| class_declaration
| error "\n" {yyerrok; errors++; yyclearin;}
;
class_declaration: CLASS ID class_body
| error "\n" {yyerrok; errors++; yyclearin;}
;
class_body: AR_STRO variable_declaration constructor method_declaration DEK_STRO
| error "\n" {yyerrok; errors++; yyclearin;}
;
variable_declaration:variable variable_declaration
|variable
|array_declaration
|array_declaration variable_declaration
| error "\n" {yyerrok; errors++; yyclearin;}
;
variable: var_type ID SEMICOLON
| error "\n" {yyerrok; errors++; yyclearin;}
;
var_type: INT
|CHAR
| error "\n" {yyerrok; errors++; yyclearin;}
;
array_declaration: ID ANATHESI NEW var_type AR_AGK MY_INT DEK_AGK SEMICOLON
| error "\n" {yyerrok; errors++; yyclearin;}
;
constructor: modifier ID AR_STRO variable_declaration DEK_STRO
| error "\n" {yyerrok; errors++; yyclearin;}
;
modifier: PUBLIC
| PROTECTED
| PRIVATE
| STATIC
| FINAL
| ABSTRACT
| error "\n" {yyerrok; errors++; yyclearin;}
;
method_declaration: modifier meth_type ID parameters meth_body
| error "\n" {yyerrok; errors++; yyclearin;}
;
meth_type: VOID
| var_type
| error "\n" {yyerrok; errors++; yyclearin;}
;
parameters: AR_PAR par_body DEK_PAR
| error "\n" {yyerrok; errors++; yyclearin;}
;
par_body: var_type ID
| par_body COMA var_type ID
| error "\n" {yyerrok; errors++; yyclearin;}
;
meth_body: AR_STRO bodybuilder DEK_STRO
| error "\n" {yyerrok; errors++; yyclearin;}
;
bodybuilder: statement GURISE expression SEMICOLON
|statement bodybuilder
|statement
| error "\n" {yyerrok; errors++; yyclearin;}
;
statement: anathesh
| if_statement
| while_statement
| error "\n" {yyerrok; errors++; yyclearin;}
;
anathesh:atath SEMICOLON
| atath numeric_expression SEMICOLON
| error "\n" {yyerrok; errors++; yyclearin;}
;
atath: ID ANATHESI orisma
|ID AR_AGK MY_INT DEK_AGK ANATHESI orisma
| error "\n" {yyerrok; errors++; yyclearin;}
;
orisma: ID
|MY_INT
|SINT
|MY_CHAR
| error "\n" {yyerrok; errors++; yyclearin;}
;
expression: testing_expression
| numeric_expression
| logical_expression
| ID
| MY_INT
| SINT
| MY_CHAR
| error "\n" {yyerrok; errors++; yyclearin;}
;
numeric_expression: expression PLUS expression
| expression MINUS expression
| expression MUL expression
| expression DIV expression
| expression MODULO expression
| error "\n" {yyerrok; errors++; yyclearin;}
;
testing_expression: expression EQ expression
| expression NEQ expression
| expression GRT expression
| expression LT expression
| expression GREQ expression
| expression LEQ expression
| error "\n" {yyerrok; errors++; yyclearin;}
;
logical_expression: expression OR expression
| expression AND expression
| expression NOT expression
| error "\n" {yyerrok; errors++; yyclearin;}
;
if_statement: IF sin8iki statement %prec "then"
| IF sin8iki statement ELSE statement
| error "\n" {yyerrok; errors++; yyclearin;}
;
sin8iki: AR_PAR testing_expression DEK_PAR
| AR_PAR logical_expression DEK_PAR
| error "\n" {yyerrok; errors++; yyclearin;}
;
while_statement: WHILE sin8iki statement
| error "\n" {yyerrok; errors++; yyclearin;}
;
%%
void yyerror(char *s) {
errors++;
printf("\n------- ERROR AT LINE #%d.\n\n", yylineno);
fprintf(stderr, "%d: error: '%s' at '%s', yylval=%u\n", yylineno, s, yytext, yylval);
}
int main (int argc, char **argv) {
++argv;
--argc;
errors=0;
if (argc > 0)
yyin = fopen (argv[0], "r");
else
yyin = stdin;
yyout = fopen ("output","w");
yyparse();
if(errors==0)
printf("komple");
else
printf("la8oi: %d", errors);
return 0;
}
我试图修改yyerrok,但似乎我不能。 我也尝试将yyparse放入for循环中。 在输入文件中我有5个语法错误,但它只打印1 !!!!!! 任何想法??????
答案 0 :(得分:2)
制作:
error "\n" {yyerrok; errors++; yyclearin;}
可能没有达到预期效果。
error
制作与正常制作没有特别的不同;主要区别在于error
生产与以下令牌(通常是终端)同步。 [1]对于野牛,双引号字符串("foo"
)是有效的终端,但没有简单的方法来获取相应的令牌号,这使得词法分析者的生活变得困难。 [2]这与单引号字符串('a'
)不同,后者必须是单个字符,并且表示其编号是与单个字符对应的整数的标记。这类似于单引号和双引号字符串之间的差异。
因此,您的error
作品将尝试与令牌“'\ n'”同步,其令牌号由bison
自动生成。但是你的词法分析器不太可能产生这个令牌号码,首先是因为它不知道这个号码是什么,其次是因为我怀疑你的词法分析器忽略了空格。 [3]没有看到词法分析器,很难说,但这些似乎是合理的假设。
因此,第一个error
生产将丢弃令牌,直到它到达文件末尾,此时它将失败并且解析将终止,报告一个错误。
注释
更准确地说,它确保可以移动前瞻标记。所以它会丢弃令牌,直到它找到一个可能是其余错误产生的字符串中的第一个终端。这并不能保证产量可以减少,但它可能是最好的野牛可以做到的。
您可以通过将它们(按此顺序)放入%token
声明(或任何优先声明)中来声明令牌名称和令牌文字。我认为这是你打算用"then"
做的,但你写它的方式是行不通的;你需要:
%right THEN "then" ELSE
(或更好)
%right THEN "then" ELSE "else"
这将声明令牌编号THEN
(生成的整数常量) by bison)也可以在语法中写成"then"
。显然,它并没有神奇地改变词法分析器,因此它可以自动识别字符串;那仍然是你的责任。以这种形式声明令牌的主要优点是它使您的语法更具可读性,并且如果您使用%error-verbose
启用它们,则可以产生更好的错误消息。
如果你的词法分析器返回换行符,我希望它们作为标记'\n'
(即10)返回,但这几乎不是一个好主意,因为语法必须是以明确允许换行的方式编写。有些语言会这样做(例如Python),但对于一种新行可以出现在任何地方的语言,它会使语法变得非常复杂。
答案 1 :(得分:0)
只需在yyerror()中计算它们,并为您自己的语义错误调用另一种方法。
答案 2 :(得分:0)
变量yynerrs包含到目前为止遇到的语法错误的数量。通常这个变量是全局的;但是如果你请求一个纯解析器,那么它就是一个只有动作可以访问的局部变量。
参考link