Yacc,第1行中的语法错误总是在空白输入时除外

时间:2018-02-20 23:10:51

标签: parsing compiler-construction bison yacc lex

我试图在lex和yacc的帮助下制作一个迷你c编译器

以下是yacc / bison代码:

%{
#include <stdio.h>
#include <stdlib.h>

extern FILE *fp;

extern int line;
extern int yylex();
int yyerror(char *);
%}

%token FOR WHILE IF ELSE PRINTF NUM ID STR ROP LOG INC RETURN STRUCT INT      FLOAT CHAR DOUBLE VOID LT GT LE GE NE EQ

%right '='
%left LOG
%left AND OR
%left LT GT LE GE NE EQ
%left '+' '-'   
%left '*' '/' '%'
%left INC

%nonassoc XYZ
%nonassoc ELSE

%%

start: Function start
  | Declaration start
  |
  ;

Declaration: Type Ass ';'
   | Ass ';'
   | Type Arr ';'
   | Arr ';'
   | StructStmt ';'
   | FunctionCall ';'

   ;

Ass: ID1 '=' Ass
| ID1 '=' FunctionCall
| ID1 '=' Arr
| Arr '=' Ass
| ID1 ',' Ass
|  NUM ',' Ass
| ID1 '+' Ass
| ID1 '-' Ass
| ID1 '*' Ass
| ID1 '/' Ass
| ID1 '%' Ass
| NUM '+' Ass
| NUM '-' Ass
| NUM '*' Ass
| NUM '/' Ass
| NUM '%' Ass
| RETURN Ass
| '\'' Ass '\''
| '\"' Ass '\"'
| '(' Ass ')'
| '-' ID1
| '-' NUM
| INC ID1
| ID1 INC
| INC NUM
| NUM INC
| ID1
| NUM
;

ID1: ID
;

FunctionCall: ID1 '(' Ass ')' 
    | ID1 '(' ')'
    ;

Function: Type ID1 '(' ArgListOpt ')' Stmt
 ;

ArgListOpt: ArgList Arg
  |
  ;

ArgList: ArgList ',' Arg
   | Arg
   ;

Arg: Type ID1
 ;

CompoundStmt: '{' StmtList '}'
      ;

StmtList: StmtList Stmt
|
;

Stmt: WhileStmt
| ForStmt
| IfStmt
| CompoundStmt
| Declaration
| PrintFunc
| ';'
;

PrintFunc: PRINTF '(' STR ',' Ass ')' ';'
 | PRINTF '(' STR ')' ';'
 ;

WhileStmt: WHILE '(' Expr ')' Stmt
 ;

ForStmt: FOR '(' Expr1 ';' Expr1 ';' Expr1 ')' Stmt
   ;

Expr1: Expr
 | 
 ;

IfStmt: IF '(' Expr ')' Stmt %prec XYZ
  | IF '(' Expr ')' Stmt ELSE Stmt
  ;

StructStmt: STRUCT ID1 '{' Type Ass '}' 
  ;

Expr: Expr LE Expr 
| Expr GE Expr
| Expr NE Expr
| Expr EQ Expr
| Expr GT Expr
| Expr LT Expr
| Expr LOG Expr
| Ass
| Arr
;

Arr: Type ID1 '[' Ass ']'
; 

Type: INT
| FLOAT
| CHAR
| DOUBLE
| VOID
;

%%

#include <ctype.h>
#include "lex.yy.c"

int main(int argc, char *argv[])
{
    yyin = fopen("tests/test1.c", "r");  
    if (!yyparse())
    {
        printf("Success\n");
    }
    else
    {
         printf("Error\n");
    }
    return 0;
}

int yyerror (char *s)
{
    printf("%d : %s %s\n", line, s, yytext);
    return 0;
}

以下是我用来收集令牌的lex文件

%{
#include <stdio.h>
int line = 1;
%}

L [a-zA-Z_]
D [0-9]

%x mcomment  
%x slcomment

%%

"/*"    BEGIN(mcomment);
"//"    BEGIN(slcomment);


<mcomment>"/*"  printf("Error Mcomment");
<mcomment>. ;
<mcomment>\n    line++;
<mcomment>"*/"  BEGIN(INITIAL);
<slcomment>.    ;
<slcomment>\n   {line++; BEGIN(INITIAL);}

"printf"    return PRINTF;
"for"   return FOR;
"while" return WHILE;
"if"    return IF;
"else"  return ELSE;
"return" return RETURN;
"struct" return STRUCT;
"int" return INT;
"float" return FLOAT;
"char" return CHAR;
"double" return DOUBLE;
"void" return VOID;

{L}({L}|{D})*   {return ID;}
{D}+([^{L};])*  {return NUM;}
"+"|"-"|"*"|"/"|"%" {;}
"=" {;} 
"<="    return LE;
">="    return GE;
"=="    return EQ;
"!="    return NE;
">" return GT;
"<" return LT;
"!" ; 
"&&"|"||"   {return LOG;}
"++"|"--"   {return INC;}
\"(\\.|[^\\"])*\"   {return STR;}
^"#include ".+  ;
^"#include".+   ;
"("|")"|"["|"]"|"{"|"}" {;}
[ \t]   return yytext[0];
";" ;
\n  {line++;}
.   return yytext[0];

%%

无论我输入哪个文件作为输入,它总是在第1行显示语法错误。它仅在我提供空白输入文件时显示成功解析,这是无用的。 语法有问题吗? 或者是lex代码错了吗?

2 个答案:

答案 0 :(得分:1)

你的词法分析器会返回所有空格字符,除了它吃掉的换行符(不返回)。

您的语法接受空格字符。因此,如果输入流中有空格,则会出现语法错误。

您的语法通常需要使用分号终结符,但您的词法分析器会使用分号(不会返回分号)。因此,如果您有任何必须以分号结尾的作品,那么此处也会出现语法错误。

答案 1 :(得分:1)

您的语法期望忽略空格,并将分号作为';'标记发送。你的词霸,另一方面:

[ \t]   return yytext[0]; // Send every soace and tab as a token
";" ;                       // Ignore semicolons

您也忽略算术运算符。毫无疑问,还有其他问题。

建议:因为这是你的第一个bison / flex项目,所以从更简单的东西开始,一次完成一个完整的语法。广泛使用flex的跟踪工具(只需将-d添加到处理lex文件的命令行。)

祝你好运。