2017-08-15 304 views
0

我想了解創建編譯器的基本概念。我試圖寫一個非常基本的C編譯器,我遇到了一些問題。當我試圖打印變量yylineno發生語法錯誤的地方時,我得到一些行號錯誤。有誰知道爲什麼?我搜索了互聯網,但找不到明確的答案,謝謝。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,期待';'在第6行

錯誤:語法錯誤,意外的'}',期待';'在第7行

回答

1

在C代碼示例中,錯誤的行號是正確的。沒有要求在第2行的int a之後丟失的;在該行上,而不是在第4,5行或甚至第6行上,如;int o

int o第6行也具有缺失;}上線7

無論那些缺少;的需要是在同一行作爲其定義滿足其僅顯露,所以第一行號可能已經出現沒有報告。報告必須已出現的最後一行數。

粘貼到MSVC程序中的示例報告錯誤的行號碼模式。

+0

有沒有更好的方式來打印像gcc或clang編譯器那樣的錯誤行號? –

+0

@ omn_1我不使用它們。請在問題中發佈您期望編譯器報告的內容。 –

+1

@ omn_1:gcc使用手工構建的詞法分析器,這使得它比在lex中更容易,但技術非常簡單:使用源代碼行標記每個詞法(和/或附加的重新定位信息)。然後,在錯誤恢復期間發生錯誤時,使用保存的信息打印比「當前行」更有趣的行。 – torek