簡體   English   中英

野牛語法分解重復的標記/表達式?

[英]Bison Grammar breaks down on repeated tokens / expressions?

借助基本的Bison / Flex語法,我試圖將標記/表達式拉入C ++對象,以從中生成三個操作碼(即內部表示形式)。 我這樣做是因為這個特定的解析器代表了較大解析器的較小子集。 我的問題來自重復的表達式/標記。

例如:

10 + 55將解析為10 + 10。

10 + VARIABLLENAME可以很好地解析,因為INT和VARIABLE是不同的標記。

55-HELLOWORLD / 100將再次解析正常,大概是因為表達式的兩邊永遠不會有兩個相同的標記。

55-HELLOWORLD-100段故障。 重復操作令牌(即-,+,/等會導致解析器崩潰)。

TLDR:當重復值類型(即INT,FLOAT,VARIABLE)時,相同的令牌將返回兩次。 重復操作時,解析器seg錯誤。

我的推論是將$ 1 / $ 3值加載到類對象中,然后將它們添加到解析器堆棧中時出現的問題。 我試過檢查我生成的每個變量+指針的內存地址,它們看上去都和我期望的一樣(即,不覆蓋同一對象)。 我已經嘗試確保值作為其值標記INT |正確加載。 和變量| 都將它們各自的變量正確加載到類中。

當使用兩個相同類型的值時,表達式似乎是相同的,因此問題似乎是針對表達式OPERATION表達式語句。 要使用先前的示例:

10 + 55->表達式加表達式-> $ 1 = 10,$ 3 = 10

當將變量加載為INT時,兩者均符合預期嗎?

這是我各自的parser.y,以及我正在嘗試將值加載到的對象。

%{
  #include <cstdio>
  #include <iostream>
  #include "TOC/Operation.h"
  #include "TOC/Value.h"
  #include "TOC/Variable.h"
  #include "TOC.h"

  using namespace std;

  extern int yylex();
  extern int yyparse();
  extern FILE *yyin;

  void yyerror(const char *s);
%}

%code requires {
    // This is required to force bison to include TOC before the preprocessing of union types and YYTYPE.
    #include "TOC.h"
}

%union {
  int ival;
  float fval;
  char *vval;
  TOC * toc_T;
}

%token <ival> INT
%token <fval> FLOAT
%token <vval> VARIABLE

%token ENDL PLUS MINUS MUL DIV LPAREN RPAREN

%type <toc_T> expression1
%type <toc_T> expression

%right PLUS MINUS
%right MUL DIV

%start start
%%
start:
        expressions;
expressions:
    expressions expression1 ENDL
    | expression1 ENDL;
expression1:
    expression { 
        TOC* x = $1;
        cout<<x->toTOCStr()<<endl; 
    }; 
expression: 
    expression PLUS expression { 
        TOC *a1 = $1;
        TOC *a2 = $3;
        Operation op(a1, a2, OPS::ADD);
        TOC *t = &op;
        $$ = t;
    }
    |expression MINUS expression { 
        TOC *a1 = $1;
        TOC *a2 = $3;
        Operation op(a1, a2, OPS::SUBTRACT);
        TOC *t = &op;
        $$ = t;    
    }
    |expression MUL expression {
        TOC *a1 = $1;
        TOC *a2 = $3;
        Operation op(a1, a2, OPS::MULTIPLY);
        TOC *t = &op;
        $$ = t;
    }
    |expression DIV expression { 
        TOC *a1 = $1;
        TOC *a2 = $3;
        Operation op(a1, a2, OPS::DIVIDE);
        TOC *t = &op;
        $$ = t;
    }
    |LPAREN expression RPAREN { 
        TOC *t = $2; 
        $$ =  t;
    }
    | INT { 
        Value<int> v = $1;
        TOC *t = &v; 
        $$ =  t;
    }
    | FLOAT { 
        Value<float> v = $1;
        TOC *t = &v;
        $$ = t; 
    }
    | VARIABLE {
        char* name = $1;
        Variable v(name);
        TOC *t = &v;
        $$ = t;
    }
%%

void yyerror(const char *s) {
  cout << "Parser Error:  Message: " << s << endl;
  exit(-1);
}

而我正在嘗試加載的值(為了清晰起見,被串聯為一個文件)。

Operation.h

enum OPS {
    SUBTRACT,
    ADD,
    MULTIPLY,
    DIVIDE,
    EXPONENT
};

class Operation : public TOC{

    OPS op;
    public:
        TOC* arg1;
        TOC* arg2;
        Operation(TOC* arg1_in, TOC* arg2_in, OPS operation){
            tt = TOC_TYPES::OPERATION_E;
            arg1 = arg1_in;
            arg2 = arg2_in;
            op = operation;
        };


        std::string toOPType(OPS e){
            switch (e){
                case SUBTRACT:
                    return "-";
                case ADD:
                    return "+";
                case MULTIPLY:
                    return "*";
                case DIVIDE:
                    return "/";
                case EXPONENT:
                    return "^";
                default:
                    return "[Operation Error!]";
            }
        }

        std::string toTOCStr(){
            return arg1->toTOCStr() + toOPType(op) + arg2->toTOCStr();
        }
};

Value.h

template <class T> class Value : public TOC {
    public:
        T argument;
        Value(T arg){
            tt = TOC_TYPES::VALUE_E;
            argument = arg;
        }

        std::string toTOCStr(){
            std::string x = std::to_string(argument);
            return x;
        }
};

Variable.H

class Variable : public TOC {
    public:
        char *name;
        Variable(char* name_in){
            tt = TOC_TYPES::VARIABLE_E;
            name = name_in;
        }
        std::string toTOCStr(){
            std::string x = name;
            return x;
        }
};

TOC.h,如果需要的話

enum TOC_TYPES { 
    VARIABLE_E, 
    VALUE_E,
    OPERATION_E
};

class TOC{
    public:
        TOC_TYPES tt;   
        virtual std::string toTOCStr() = 0;
};

我的主文件只是加載到文件中,然后在調用yyparse之前將yyin設置為其內容。 我沒有包括它,但是如果需要可以(不是很令人興奮)。

理想情況下,我想將整個RD解析樹加載到TOC *中,然后可以向下迭代以在每個級別生成三個操作代碼。 但是,打破重復標記和操作的錯誤確實讓我感到困擾。

這是問題的示例:

    Operation op(a1, a2, OPS::ADD);
    TOC *t = &op;
    $$ = t;

t是不必要的;您也可以編寫$$ = &op;但這只是一個旁注。)

op這里是一個自動變量,其生存期在退出該塊時結束。 在地址保存為$$后立即發生這種情況。 這使得生產的語義價值成為懸空的指針。

使用一個壽命已結束的變量的地址為Undefined Behaviour,但您可能可以猜測正在發生的情況:下一次進入該塊時,堆棧位於同一位置,新的op與舊的op具有相同的地址。 (不能保證會發生這種情況:未定義的行為是未定義的。但是,此特定結果與您的觀察一致。)

簡而言之,請熟悉new操作符:

$$ = new Operation(a1, a2, OPS::ADD);

並且不要忘記在適當的時候delete它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM