YACC中的错误处理

时间:2012-03-20 23:34:58

标签: parsing yacc lex lexical-analysis

您好,我正在尝试制作一个简单的解析器并使用lex和yacc。问题是我想打印我自己的错误消息,而不是打印error的yacc使用的syntax error符号。例如,这是我的yacc代码;

%{
#include <stdio.h>
#include <string.h>
#include "y.tab.h"
extern FILE *yyin;
extern int linenum;
%}

%token INTRSW IDENTIFIER INTEGER ASSIGNOP SEMICOLON DOUBLEVAL DOUBLERSW COMMA 
%token IF ELSE WHILE FOR
%token CLOSE_BRA OPEN_BRA CLOSE_PARA OPEN_PARA EQ LE GE
%token SUM MINUS MULTIP DIV

%left OPEN_BRA OPEN_PARA
%left MULTIP DIV
%left SUM MINUS

%union 
{
        int number;
        char* string;
}

%token <number> INTEGER
%token <string> IDENTIFIER

%%
program: 
    statement_list
    ;

statement_list:
        statement_list statement
        |
        statement
        ;

statement:
    if_statement OPEN_BRA statement_list CLOSE_BRA
    |
    if_statement 
    |
    assignment_block
    |
    single_assignment 
    ;

if_statement:
    IF OPEN_PARA condition_statement CLOSE_PARA
    ;

condition_statement:
    logical_expression
    ;

logical_expression:
    expression EQ expression
    |
    expression LE expression
    |
    expression GE expression
    ;

expression:
    double
    |
    IDENTIFIER
    |
    OPEN_PARA expression CLOSE_PARA
    |
    expression MULTIP expression
    |
    expression DIV expression
    |
    expression SUM expression
    |
    expression MINUS expression
    ;

assignment_block:
    integer_assignment_block
    | 
    double_assignment_block
    ;

integer_assignment_block:
    INTRSW integer_assignment_list SEMICOLON
    ;

double_assignment_block:
    DOUBLERSW double_assignment_list SEMICOLON
    ;

integer_assignment_list:
    integer_assignment
    |
    integer_assignment_list COMMA integer_assignment
    ;

double_assignment_list:
    double_assignment
    |
    double_assignment_list COMMA double_assignment
    ;

single_assignment:
    IDENTIFIER ASSIGNOP double SEMICOLON
    |
    IDENTIFIER ASSIGNOP IDENTIFIER SEMICOLON
    |
    error ';' { printf("You made en error"); }  
    ;

integer_assignment:
    IDENTIFIER ASSIGNOP INTEGER
    |
    IDENTIFIER
    ;

double_assignment:
    IDENTIFIER ASSIGNOP double
    |
    IDENTIFIER
    ;

double:
    DOUBLEVAL
    |
    INTEGER 
    ;

%%
void yyerror(char *s){
    fprintf(stderr,"%s Error at line: %d\n",s, linenum);
}
int yywrap(){
    return 1;
}
int main(int argc, char *argv[])
{
    /* Call the lexer, then quit. */
    yyin=fopen(argv[1],"r");
    yyparse();
    fclose(yyin);
    return 0;
}

所以这个块我添加了错误声明。

single_assignment:
    IDENTIFIER ASSIGNOP double SEMICOLON
    |
    IDENTIFIER ASSIGNOP IDENTIFIER SEMICOLON
    |
    error ';' { printf("You made en error"); }  
    ;

所以我在一行中写了一个= 7(没有';'),只是说syntax error Error at line:7。那我的错误信息在哪里?如果你能帮我解决这个问题,我将非常高兴。并且还要感谢

1 个答案:

答案 0 :(得分:5)

  

所以我在一行中写了一个= 7(没有';')它只是说语法错误错误   在线:7。那么我的错误信息在哪里??

您的error操作告诉Yacc丢弃令牌,直到找到';'为止令牌。在此之前,它不能通过该规则减少。

此外,您应该在规则正文中的某处执行yyerrok;,以向解析器发出已恢复已完成的信号。或者,您也可以使用yyclearin;丢弃触发错误的令牌。这样做很棘手,因为您猜测令牌是不合适的。它实际上可能是正确的令牌,但在它丢失之前还有别的东西!例如,你看到一个分号,因为没有用括号括起来等等。

错误操作不会替换调用yyerror的行为。当发生语法错误时,解析器将使用消息(通常是“语法错误”)调用yyerror,然后考虑错误产生。错误产生不像“语法错误的自定义覆盖”。 (看起来您期望“语法错误”被替换为您自己的一般错误消息“您犯了错误”。)

在错误生成中,如果您能猜出错误的性质,则可以打印更有用的其他诊断。

有用的一件事是yychar变量,它告诉你前瞻标记。您可以在错误恢复规则中进行检查,并尝试根据其值猜测出错的地方。您不仅可以检查自己的令牌类型,还可以检查值YYEOF,这表示语法错误是由于未达到某些错误令牌而导致输入结束。

我编写了一个解析器,其中,在一些错误产品中,我只是从yychar获取了令牌并将其转换为其描述性名称并打印出“意外的”消息。这总比没有好;它告诉用户哪个令牌的语法偏离了预期。

此外,即使在正确的解析中,yacc解析器也可以生成诊断信息! (显然;例如,你如何实现一种语言的警告。)基本上你需要一些你可以自己调用的中央错误报告功能,以及yyerror也会调用。该函数应设置一个标志,指示是否发生致命错误(或保留错误,警告等数量)。例如,如果存在致命错误,即使解析器从任何语法错误中恢复,您也可能希望丢弃解析树并使用失败的终止状态保存程序。