yylineno为错误报告提供意外结果

时间:2017-08-15 23:14:46

标签: c compiler-construction bison flex-lexer

我试图理解创建编译器的基本概念。我试过编写一个非常基本的c编译器,但遇到了一些问题。当我尝试打印变量yylineno发生语法错误的地方时,我得到一些错误的行号。有谁知道为什么?我已经在互联网上搜索了,但我找不到明确的答案,谢谢。

comp.l文件:

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


extern int yylineno;
extern FILE* yyin;
//extern char* yytext;
void yyerror(char *s);


%}


%union {char* var;} 

%token INT FLOAT CHAR DOUBLE VOID
%token FOR WHILE 
%token IF ELSE PRINTF 
%token STRUCT 
%token NUM 
%token INCLUDE
%token DOT
%token <var> ID
%right '='
%left AND OR
%left '<' '>' LE GE EQ NE LT GT
%error-verbose

%%

start:  Function 
    | Declaration
    ;

/* Declaration block */
Declaration: Type Assignment ';' 
    | Assignment ';'    
    | FunctionCall ';'  
    | ArrayUsage ';'    
    | Type ArrayUsage ';'   
    | StructStmt ';'    
    | Arg ';'
    | error {yyerrok;}
    ;

/* Assignment block */
Assignment: ID '=' Assignment 
    | ID '=' FunctionCall   
    | ID '=' ArrayUsage     
    | ArrayUsage '=' Assignment
    | ID ',' Assignment   
    | NUM ',' Assignment
    | ID '+' Assignment    
    | ID '-' Assignment    
    | ID '*' Assignment     
    | ID '/' Assignment     
    | NUM '+' Assignment   
    | NUM '-' Assignment
    | NUM '*' Assignment
    | NUM '/' Assignment
    | '\'' Assignment '\''  
    | '(' Assignment ')'
    | '-' '(' Assignment ')'
    | '-' NUM
    | '-' ID  
    |   NUM
    |   ID  
    ;

/* Function Call Block */
FunctionCall : ID'('')'
    | ID'('Assignment')'
    ;

/* Array Usage */
ArrayUsage : ID'['Assignment']'  
    | ID'['error ']' {yyerrok;}
    ;

/* Function block */
Function: Type ID '(' ArgListOpt ')' CompoundStmt  

ArgListOpt: ArgList
    |
    ;

ArgList:  ArgList ',' Arg
    | Arg
    ;

Arg:    Type ID
    ;

CompoundStmt:   CompoundStmt '{' StmtList '}'
    |  '{' StmtList '}'
    | '{' StmtList {yyerror("Missing '}'"); YYERROR;}
    |  StmtList '}' {yyerror("Missing '{'"); YYERROR;}
    ;

StmtList:   StmtList Stmt
    |
    ;

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

/* Type Identifier block */
Type: INT 
    | FLOAT
    | CHAR
    | DOUBLE
    | VOID 
    ;

/* Loop Blocks */ 
WhileStmt: WHILE '(' Expr ')' Stmt  
    | WHILE '(' Expr ')' CompoundStmt 
    ;

/* For Block */
ForStmt: FOR '(' Expr ';' Expr ';' Expr ')' Stmt 
       | FOR '(' Expr ';' Expr ';' Expr ')' CompoundStmt 
       | FOR '(' Expr ')' Stmt 
       | FOR '(' Expr ')' CompoundStmt 
    ;

/* IfStmt Block */
IfStmt : IF '(' Expr ')' Stmt 
    ;

/* Struct Statement */
StructStmt : STRUCT ID '{' Type Assignment '}'  
    ;

/* Print Function */
PrintFunc : PRINTF '(' Expr ')' ';'
    ;

/*Expression Block*/
Expr:   
    | Expr LE Expr 
    | Expr GE Expr
    | Expr NE Expr
    | Expr EQ Expr
    | Expr GT Expr
    | Expr LT Expr
    | Assignment
    | ArrayUsage
    ;

%%

int count = 0;







int main() {

    int i;

    for(i=0; i<100; i++) {

        variables[i] = " ";

     }

    yyin = stdin;

    do { 

        yyparse();

    } while(!feof(yyin));

    return 0;
}





void yyerror(char* s) {




    printf("Error : %s  at line %d \n", s, yylineno);

}   

comp.y文件:

alpha [a-zA-Z]
digit [0-9]

%{
#include "y.tab.h"
#include <stdio.h>

int line_n = 1;

%}

%option  nodefault yylineno



%%


[\t\n]+                      {;}
"int"                        {return INT;}
"float"                      {return FLOAT;}
"char"                       { return CHAR;}
"void"                       {return VOID;}
"double"                     {return DOUBLE;}
"for"                        {return FOR;}
"while"                      {return WHILE;}
"if"                         {return IF;}
"else"                       {return ELSE;}
"printf"                     {return PRINTF;}
"struct"                     {return STRUCT;}
^"#include ".+               {;}
{digit}+                     {return NUM;}
{alpha}({alpha}|{digit})*    {yylval.var = strdup(yytext);return ID;}
"<="                         {return LE;}
">="                         {return GE;}
"=="                         {return EQ;}
"!="                         {return NE;}
">"                          {return GT;}
"<"                          {return LT;}
"."                          {return DOT;}
\/\/.*                       {;}
\/\*(.*\n)*.*\*\/            {;}
[ \t\r\n]+                   {;}
.                            {return *yytext;}


%%



int yywrap (void) {return 1;}

例如,当我尝试检查以下代码时:

1.int main(){
2.   int a
3.
4. 
5. 
6.   int o 
7.}

我明白了:

错误:语法错误,意外的INT,期待&#39 ;;&#39;第6行

错误:语法错误,意外情况&#39;}&#39;,期待&#39 ;;&#39;第7行

1 个答案:

答案 0 :(得分:1)

在C代码示例中,错误的行号是正确的。第2行;之后的int a不需要在该行上,而不是第4行,第5行,甚至是第6行;int o

第6行的int o也缺少;,只有在第7行遇到}时才会显示。

缺少;的任何一个都不需要与其定义位于同一行,因此不会报告可能出现的第一个行号。而是报告必须出现的最后一个行号。

粘贴到MSVC程序中的示例报告错误的行号相同的模式。