YACC中的错误处理

qua*_*ela 3 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;
}
Run Code Online (Sandbox Code Playgroud)

所以这块我添加错误声明.

single_assignment:
    IDENTIFIER ASSIGNOP double SEMICOLON
    |
    IDENTIFIER ASSIGNOP IDENTIFIER SEMICOLON
    |
    error ';' { printf("You made en error"); }  
    ;
Run Code Online (Sandbox Code Playgroud)

所以我在一行中写了一个= 7(没有';')syntax error Error at line:7.那我的错误信息在哪里?如果你能帮我解决这个问题,我将非常高兴.无论如何,谢谢

Kaz*_*Kaz 5

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

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

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

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

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

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

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

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