1

我希望我的代码打印输入文件中出现的语法错误的数量。这是我的代码:

%{
#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 个!!!!!!有任何想法吗??????

4

3 回答 3

2

生产:

error "\n" {yyerrok; errors++;  yyclearin;}

可能不符合您的预期。

error作品与正常作品没有特别的不同;主要区别在于error生产与以下令牌(通常是终端)同步。[1] 对于 bison,双引号字符串 ( "foo") 是有效的终结符,但没有简单的方法来获取相应的标记号,这让词法分析器很困难。[2] 这与单引号字符串 ( 'a') 不同,单引号字符串必须是单个字符,并且表示其编号为与单个字符对应的整数的标记。这类似于 C 语言中单引号和双引号字符串之间的区别。

因此,您的error作品将尝试与令牌“'\n'”同步,其令牌编号由bison. 但是你的词法分析器不太可能产生这个标记号,首先是因为它不知道这个数字是什么,其次是因为我怀疑你的词法分析器忽略了空格。[3] 没有看到词法分析器,很难说,但这些似乎是合理的假设。

因此,第一个error生产将丢弃令牌,直到它到达文件末尾,此时它将失败并且解析将终止,并报告一个错误。


笔记。

  1. 更准确地说,它确保可以移动前瞻令牌。所以它会丢弃标记,直到它找到一个可能是由其余错误产生产生的字符串中的第一个终端。这并不能保证产量是可减少的,但这可能是野牛能做的最好的事情。

  2. 您可以通过将它们(按该顺序)放入%token声明(或任何优先声明)中来声明标记名称和标记文字。我认为这就是您打算使用的"then",但是您编写它的方式行不通;你需要:(
        %right THEN "then" ELSE
    或者,更好)
        %right THEN "then" ELSE "else"
    这将声明标记号THEN(这是一个由野牛生成的整数常量)也可以像"then"语法一样编写。显然,它不会神奇地改变词法分析器以使其自动识别字符串。那仍然是你的责任。以这种形式声明标记的主要优点是它使您的语法更具可读性,并且如果您启用它们,bison 可以产生更好的错误消息%error-verbose

  3. 如果您的词法分析器返回换行标记,我希望它们作为标记'\n'(即 10)返回,但这绝不是一个好主意,因为必须以明确允许换行的方式编写语法。有些语言会这样做(例如 Python),但是对于换行符几乎可以出现在任何地方的语言,它会使语法变得非常复杂。

于 2013-09-25T15:16:30.857 回答
1

只需将它们计算在内yyerror(),然后为您自己的语义错误调用不同的方法。

于 2013-09-28T01:31:13.967 回答
0

变量 yynerrs 包含到目前为止遇到的语法错误的数量。通常这个变量是全局的;但是如果你请求一个纯解析器,那么它是一个只有操作可以访问的局部变量。

参考链接

于 2015-03-12T13:47:12.597 回答