C语言 野牛:尝试分析多行表达式时出现意外的标记错误

camsedfj  于 2023-04-29  发布在  其他
关注(0)|答案(1)|浏览(121)

我用Flex和野牛做了一个Visual Basic解析器,用于uni赋值。除了多行表达式的解析外,大多数似乎都能正常工作。下面是一个不起作用的代码示例:

A = A +
1

有趣的是,删除A =可以使它正确解析。如果我将=替换为优先级高于或等于+的运算符,同样适用。
解析器似乎优先考虑单行表达式而不是多行表达式。我知道这是一个优先级问题,但我不知道如何解决这个问题。
截断Flex代码:

%option nounistd
%option noyywrap
%option case-insensitive

%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "parcer-mini.tab.h"

#pragma warning(disable : 4996)
#define YY_DECL int yylex()

int result = 0;

%}
%x STRING_LITERAL

%%
%{
    char buf[100000];
    memset(buf, '\0', 100000);
%}

"+"                 { return '+'; }
"-"                 { return '-'; }
"*"                 { return '*'; }
"/"                 { return '/'; }
"="                 { return '='; }
"<"                 { return '<'; }
">"                 { return '>'; }
"^"                 { return '^'; }

([0-9]([0-9]+)?)  {yylval.int_val = atoi(yytext); return INT_VALUE;}

([a-zA-Z_])([a-zA-Z_0-9])* {yylval.id_var_name = (char *) malloc(strlen(yytext)+1); strcpy(yylval.id_var_name, yytext); return IDENTIFIER;}

\n+  {return END_OF_LINE;}

<<EOF>> { static int once = 0; return once++ ? 0 : END_OF_LINE;}
%%

截断野牛代码:

%define parse.error verbose
%{
#pragma warning(disable : 4996)
#include <stdio.h>
#include <stdlib.h>

extern int yylineno;
extern FILE* yyin;

extern int yyparse();
extern int yylex();

void yyerror(const char* s);
%}

%union {
    int int_val;
    char* id_var_name;
}

%type <expression> expr_singleline expr_multiline basic_literal_value;
%type <statement> stmt root;
%type stmt_ends;

%token<int_val> INT_VALUE

%token<id_var_name> IDENTIFIER

%token END_OF_LINE

%left '='
%left '>' '<'

%left '+' '-'
%left '*' '/'
%right UNARY_MINUS UNARY_PLUS
%left '^'

%precedence IDENTIFIER

%start root

%%

root: stmt {printf("root 1\n");}
    ;
    
stmt: expr_multiline stmt_ends {printf("stmt 1\n");}
    | expr_singleline stmt_ends {printf("stmt 2\n");}
    ;          
    
stmt_ends: END_OF_LINE {printf("stmt_ends 1\n");}
    | stmt_ends END_OF_LINE {printf("stmt_ends 2\n");}
    ;
    
expr_singleline: basic_literal_value {printf("expr_single 0\n");}
    | '-' expr_singleline   %prec UNARY_MINUS {printf("expr_single 1\n");}
    | '+' expr_singleline   %prec UNARY_PLUS {printf("expr_single 2\n");}
    | expr_singleline '+' expr_singleline {printf("expr_single 3\n");}
    | expr_singleline '-' expr_singleline {printf("expr_single 4\n");}
    | expr_singleline '*' expr_singleline {printf("expr_single 5\n");}
    | expr_singleline '/' expr_singleline {printf("expr_single 6\n");}
    | expr_singleline '=' expr_singleline {printf("expr_single 8\n");}
    | expr_singleline '<' expr_singleline {printf("expr_single 9\n");}
    | expr_singleline '>' expr_singleline {printf("expr_single 10\n");}
    | expr_singleline '^' expr_singleline {printf("expr_single 11\n");}
    | IDENTIFIER {printf("expr_single 17\n");}
    ;

expr_multiline: expr_singleline '+' END_OF_LINE expr_singleline {printf("expr_multi 1\n");}
              | expr_singleline '-' END_OF_LINE expr_singleline {printf("expr_multi 2\n");}
              | expr_singleline '*' END_OF_LINE expr_singleline {printf("expr_multi 3\n");}
              | expr_singleline '/' END_OF_LINE expr_singleline {printf("expr_multi 4\n");}
              | expr_singleline '=' END_OF_LINE expr_singleline {printf("expr_multi 6\n");}
              | expr_singleline '<' END_OF_LINE expr_singleline {printf("expr_multi 7\n");}
              | expr_singleline '>' END_OF_LINE expr_singleline {printf("expr_multi 8\n");}
              | expr_singleline '^' END_OF_LINE expr_singleline {printf("expr_multi 9\n");}
              ;

basic_literal_value: INT_VALUE {printf("basic_literal_value int\n");}
                   ;                   
%%
int main(int argc, char** argv) {
    if (argc > 1) {
        yyin = fopen(argv[1], "r");
        yyparse();
    }
    else {
        yyerror("not found file");
    }
}

void yyerror(const char* s) {
    fprintf(stderr, "Parse error: %s\n", s);
    exit(1);    
}
bihw5rsg

bihw5rsg1#

我不知道如何解决上述问题,但我找到了一个解决方案。通过创建一个可选的End of Line标记,我合并了expr_singleline和expr_multiline。这个方法非常有效。
修改的截断野牛代码:

%define parse.error verbose
%{
#pragma warning(disable : 4996)
#include <stdio.h>
#include <stdlib.h>

extern int yylineno;
extern FILE* yyin;

extern int yyparse();
extern int yylex();

void yyerror(const char* s);
%}

%union {
    int int_val;
    char* id_var_name;
}

%type <expression> expr basic_literal_value;
%type <statement> stmt root;
%type stmt_ends optEoL;

%token<int_val> INT_VALUE

%token<id_var_name> IDENTIFIER

%token END_OF_LINE

%left '='
%left '>' '<'

%left '+' '-'
%left '*' '/'
%right UNARY_MINUS UNARY_PLUS
%left '^'

%precedence IDENTIFIER

%start root

%%

root: stmt {printf("root 1\n");}
    ;
    
stmt: expr stmt_ends {printf("stmt 2\n");}
    ;          
    
stmt_ends: END_OF_LINE {printf("stmt_ends 1\n");}
    | stmt_ends END_OF_LINE {printf("stmt_ends 2\n");}
    ;
    
optEoL: /*empty*/
      | END_OF_LINE {printf("optEoL 1\n");}
      ;
    
expr: basic_literal_value {printf("expr_single 0\n");}
    | '-' expr %prec UNARY_MINUS {printf("expr_single 1\n");}
    | '+' expr %prec UNARY_PLUS {printf("expr_single 2\n");}
    | expr '+' optEoL expr_singleline {printf("expr_single 3\n");}
    | expr '-' optEoL expr_singleline {printf("expr_single 4\n");}
    | expr '*' optEoL expr_singleline {printf("expr_single 5\n");}
    | expr '/' optEoL expr_singleline {printf("expr_single 6\n");}
    | expr '=' optEoL expr_singleline {printf("expr_single 8\n");}
    | expr '<' optEoL expr_singleline {printf("expr_single 9\n");}
    | expr '>' optEoL expr_singleline {printf("expr_single 10\n");}
    | expr '^' optEoL expr_singleline {printf("expr_single 11\n");}
    | IDENTIFIER {printf("expr_single 17\n");}
    ;

basic_literal_value: INT_VALUE {printf("basic_literal_value int\n");}
                   ;                   
%%
int main(int argc, char** argv) {
    if (argc > 1) {
        yyin = fopen(argv[1], "r");
        yyparse();
    }
    else {
        yyerror("not found file");
    }
}

void yyerror(const char* s) {
    fprintf(stderr, "Parse error: %s\n", s);
    exit(1);    
}

相关问题