[英]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.