C++ 如何构建递归下降解析器

C++ 如何构建递归下降解析器,c++,parsing,type-inference,C++,Parsing,Type Inference,我一直在为一个简单的计算器开发递归下降解析器。当某个东西被声明时,它要么被声明为int,要么被声明为float。目前,我正在将字符串保存到两个不同的向量中,一个用于int,另一个用于float。此时,我不关心关联的数字是什么,我只关心在使用字符串之前声明它 我的问题是,如果在诸如float+int这样的操作中使用int和float,我必须能够输出警告消息 所以如果表达式是term+表达式或者term表达式或者term。在递归下降中,我怎么可能检查int是否正在浮点操作中使用。对不起,如果解释不清

我一直在为一个简单的计算器开发递归下降解析器。当某个东西被声明时,它要么被声明为int,要么被声明为float。目前,我正在将字符串保存到两个不同的向量中,一个用于int,另一个用于float。此时,我不关心关联的数字是什么,我只关心在使用字符串之前声明它

我的问题是,如果在诸如float+int这样的操作中使用int和float,我必须能够输出警告消息

所以如果表达式是term+表达式或者term表达式或者term。在递归下降中,我怎么可能检查int是否正在浮点操作中使用。对不起,如果解释不清楚的话。我觉得有点难以解释。我已经添加了一些代码,如果必要的话,我只是不想用代码淹没这个问题

编辑: 还有一堆代码丢失,我想我只是抓住了重要的部分,但如果需要,我可以上传整个东西。我看到有些人不明白主要问题是什么。其中一个要求是“当整数和浮点值在+、-、*和/中混合时,整数将转换为浮点。打印一条消息,指示行号以及需要进行转换。”此时程序从文件中读取。如果你说“int x;”,程序当前将把x保存在int向量中,那么当你说x=5;它将确认x已声明,分配将通过。我的问题是如果你说int x;浮动y;intz;x=5;y=7.5;z=x+y;我怎样才能检查它,因为目前我的程序只保存变量的类型,而不保存值。本质上,我想知道是否有可能像扫描一个字符串一样扫描完成的解析,或者使用int和float从一个操作中找出其他方法

lex扫描器是用flex创建的

class Token {
Tokentype   type;
string      value;
int     linenum;

public:
Token(Tokentype t, string v="") {
    type = t;
    value = v;
}
Tokentype getType() { return type; }
string getValue() { return value; }
int getLinenum() { return linenum; }
};

vector<string> int_list;  
vector<string> float_list; 

class PTree {
PTreeNodetype   type;
PTree *left;
PTree *right;
public:
PTree(PTreeNodetype t, PTree *l=0, PTree *r=0) {
    type = t;
    left = l;
    right = r;
}
PTreeNodetype getType(){ return type;}
};

// expr ::= term PLUS expr | term MINUS expr | term 
PTree *
Expr() {

PTree *term = Term();
Token *t;

if (!term)
    return 0;

t = getToken();

if (t == NULL){
    delete t;
    return 0;
}
if(t->getType() != T_SC)
{
    if (t->getType() == T_RPAREN){
        pushbacktoken(t);
        return new PTree(EXPR, term);
    }

    if (t->getType() != T_PLUS && t->getType() != T_MINUS)
    {
        cout << t->getLinenum() <<  ":" << "Error:    expected + or -" << endl;
        pushbacktoken(t);
        delete t;
        return 0; 
    }



    delete t;
    PTree *expr = Expr();

    if (!expr)
        return 0;

    return new PTree(EXPR, term, expr);
}

pushbacktoken(t);
return new PTree(EXPR, term);
  }
类令牌{
标记类型;
字符串值;
int-linenum;
公众:
令牌(令牌类型t,字符串v=“”){
类型=t;
值=v;
}
Tokentype getType(){return type;}
字符串getValue(){返回值;}
int getLinenum(){return linenum;}
};
向量整数表;
向量浮点数表;
类树{
PTreeNodetype型;
p树*左;
PTree*对;
公众:
PTree(PTreeNodetype t,PTree*l=0,PTree*r=0){
类型=t;
左=l;
右=r;
}
PTreeNodetype getType(){return type;}
};
//expr::=术语加上expr |术语减去expr |术语
树*
Expr(){
PTree*term=term();
令牌*t;
如果(!术语)
返回0;
t=getToken();
如果(t==NULL){
删除t;
返回0;
}
如果(t->getType()!=t_SC)
{
如果(t->getType()==t_rpare){
pushbacktoken(t);
返回新的PTree(EXPR,term);
}
如果(t->getType()!=t\u加号和&t->getType()!=t\u减号)
{

cout getLinenum()我看到的两个选项,取决于您正在做什么

首先。在构建解析树时,不要担心它。稍后,在遍历树时,您可以轻松地检查它并抛出错误

第二个。
int
float
使用不同的规则。因此,您将有一个添加两个int的规则和一个添加两个float的规则。这也意味着您将不会有一个混合int和float的
数字
规则,我猜您是这样做的


我绝对推荐第一种方法。

我看到两种选择,这取决于你在做什么

首先。在构建解析树时,不要担心它。稍后,在遍历树时,您可以轻松地检查它并抛出错误

第二个。
int
float
使用不同的规则。因此,您将有一个添加两个int的规则和一个添加两个float的规则。这也意味着您将不会有一个混合int和float的
数字
规则,我猜您是这样做的


我绝对推荐第一种方法。

传统上,计算器不会“声明”事物,因此不清楚您的计算器在解析表达式时知道什么

如果我假设您在解析表达式“I*r”之前“声明I int,r real”,您似乎有几个问题:

a) 解析时如何知道i和r是否已声明?技术上的答案是,在解析过程中,您不必知道;您可以解析、建立树,然后再进行此类检查。在实际层面上,人们通常在解析过程中编织符号查找(随着您的语言变得越来越大,这会变得越来越混乱,因此不建议将其用于计算器以外的其他用途[您会发现,大多数C编译器都会这样做,这会增加它们的混乱程度])。答案很简单:保留一个已定义符号字符串的列表,当您遇到标识符时,查看其是否在列表中

b) 如何知道“i”或“r”的类型?很简单。与符号字符串关联,声明的类型,例如,关联的声明集通常称为符号表


c) 如何知道操作是否在相同(“右侧”)类型的值上运行?这里需要与每个操作数及其“类型”关联。常量具有明显的类型;1.0为实数,1为整数。“i”为整数,您的解析器知道它,因为它查找了类型(如上);与“r”类似。然后,每个表达式项必须检查其操作数的兼容性。可能不明显的是,每个表达式必须计算其结果类型,例如,3*4.0是实数,而不是整数。因此,与解析机制并行,您需要传播一个类型。

计算器传统上不会“声明”因此,不清楚您的计算器在解析表达式时知道什么

如果我假设您在解析表达式“I*r”之前“声明I int,r real”,您似乎有几个问题:

a) 在解析时,您如何知道我和