2015-07-04 61 views
0

我一直在編寫一段業餘愛好編譯器,現在使用lex和yacc作爲解析階段。這對於大多數情況都可以正常工作,但是當我在if語句中添加時,符號的生成規則現在將堆棧中的前一個(或下一個?)項目替換爲所需的符號值。下面Yacc語法生成不正確的終端

語法給出取出希望無關的規則:

%{ 
     ... 
%} 


    %define parse.error verbose 


    %token ... 

    %% 


    Program: 
      Function           { root->addChild($1);}  
      ; 


    Function: 
      Type Identifier '|' ArgumentList '|' StatementList END 
                   { $$ = new FunctionDef($1, $2, $4, $6); } 


    /******************************************/ 
    /* Statements and control flow ************/ 
    /******************************************/ 

    Statement: 
      Expression Delimiter 
      | VariableDeclaration Delimiter 
      | ControlFlowStatement Delimiter 
      | Delimiter 
      ; 

    ControlFlowStatement: 
      IfStatement 
      ; 

    IfStatement: 
      IF Expression StatementList END      { $$ = new IfStatement($2, $3); } 
      | IF Expression StatementList ELSE StatementList END { $$ = new IfStatement($2, $3, $5);} 
      ; 

    VariableDeclaration: 
      Type Identifier          { $$ = new VariableDeclaration($1, $2);} 
      | Type Identifier EQUALS Expression     { $$ = new VariableDeclaration($1, $2, $4);} 
      ; 

    StatementList: 
      StatementList Statement        { $1->addChild($2);    } 
      | Statement           { $$ = new GenericList($1);  } 
      ; 


    Delimiter: 
      ';' 
      | NEWLINE 
      ; 
    Type: 
      ... 
Expression: 
    ... 

    PostfixExpression: 
      Value '[' Expression ']'       { std::cout << "TODO: indexing operators ([ ])" << std::endl;} 
      | Value '.' SYMBOL         { std::cout << "TODO: member access" << std::endl;} 
      | Value INCREMENT         { $$ = new UnaryExpression(UNARY_POSTINC, $1); } 
      | Value DECREMENT         { $$ = new UnaryExpression(UNARY_POSTDEC, $1); } 
      | Value '(' ')'          { $$ = new FunctionCall($1, NULL); } 
      | Value '(' ExpressionList ')'      { $$ = new FunctionCall($1, $3);    } 
      | Value 
      ; 


    Value: 
      BININT            { $$ = new Integer(yytext, 2);     } 
      | HEXINT           { $$ = new Integer(yytext, 16);     } 
      | DECINT           { $$ = new Integer(yytext);      } 
      | FLOAT            { $$ = new Float(yytext);      } 
      | SYMBOL           { $$ = new Symbol(yytext);      } 
      | STRING           { $$ = new String(yytext);      } 
      | LambdaFunction 
      | '(' Expression ')'        { $$ = $2;          } 
      | '[' ExpressionList ']'       { $$ = $2;} 
      ; 

    LambdaFunction: 
      ... 


    %% 

我不能工作了怎麼樣的控制流代碼可以使符號: 規則匹配的東西是不列爲從符號在lex定義:

symbol      [a-zA-Z_]+(alpha|digit)* 
... 
{symbol}     {return SYMBOL;} 

從別人的任何幫助誰知道YACC和語法一般會非常讚賞。如果需要,也可以顯示它解析語法的示例文件。

謝謝!

+0

[TL; DR](https://en.wikipedia.org/wiki/TL;DR)!將語法縮小到支持有問題的規則所需的最低限度。例如,您可能不需要完整的表達式層次結構或大多數其他語句或聲明。如果它工作,然後再爲表達式添加一個級別,並繼續,直到出現錯誤。如果即使使用最小的語法也會遇到錯誤,至少您排除了許多可能的來源,並且可以編輯您的問題以僅包含最小語法。 –

+0

我自己也在想同樣的事情,可能過了很長時間才發佈,但我決定在謹慎的一面犯錯,不知道錯誤在哪裏!你說的沒錯,儘管我沒有表達堆棧等。 –

+0

關於剝離語法以找到問題的根源,我確實這樣做了,並發現它是控制流代碼,但我無法弄清楚如何或爲什麼。 –

回答

1

您不能指望彈性操作之外的值爲yytext

野牛語法通常在決定如何繼續前先讀取一個先行令牌,因此在野牛行動中,yytext已經被替換爲先行令牌的令牌值。 (但是,你也不能指望:有時不需要預覽標記)

因此,您需要在flex動作返回之前製作yytext的副本,並將該副本放置到野牛語法中進入yylval語義聯合。

看到這個​​


順便說一句,從你的Flex文件中的以下片段是不正確的:

symbol      [a-zA-Z_]+(alpha|digit)* 

在這個正則表達式,alphadigit只是普通字符串,所以它與[a-zA-Z_]+("alpha"|"digit")*相同,這意味着它將與例如a_digitdigitdigit匹配,但不匹配a_123。 (這本來匹配a_digitdigitdigit不按+的一部分,所以我猜想這是不是你的意願。)

就整體而言,我認爲這是更好地使用POSIX字符類比任何手寫字符類或定義符號,所以我會寫,隨着

symbol [[:alpha:]_]([[:alnum:]_]*[[:alnum:]])? 

假設你的意圖是,一個符號可以開始,但不以下劃線結束,最後卻不能以數字開頭。使用Posix字符類需要用正確的語言環境執行flex - 幾乎可以肯定是C語言環境 - 但所以字符範圍也是如此,所以使用自我記錄的Posix類沒有什麼可以丟失的。

(當然,我不知道你的{alpha}{digit}定義,但在我看來,他們不是一樣[[:alpha:]][[:digit:]],在這種情況下,他們是多餘的,或不同的Posix類在這種情況下,他們對讀者感到困惑。)

+0

我沒有意識到yytext的值有時在lex規則之外是不正確的,我認爲這可能是問題,很快就會測試。謝謝你非常詳細的回答,我想你可能剛剛救了我的愛好項目!我正準備投入毛巾!我會牢記lex規則,這可能會導致問題。謝謝。 –