1

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

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

因此,如果表达式是术语+表达式或术语-表达式或术语。在递归下降中,我怎么可能检查一个 int 是否被用于带有浮点数的操作中。对不起,如果解释不清楚。我觉得解释起来有点困难。如果有必要,我已经添加了一些代码,我只是不想用代码淹没这个问题。

编辑:仍然缺少一堆代码,我想抓住重要的部分,但如果需要,我可以上传整个东西。我看到有些人不明白主要问题是什么。要求之一是“当整数和浮点值混合在 +、-、* 和 / 中时,整数将转换为浮点数。打印一条消息,指示行号并且需要进行转换。” 目前程序从文件中读取。如果你说“int x;” 程序当前会将 x 保存在 int 向量中,然后当您说诸如 x=5 之类的内容时;它将承认 x 已被声明并且分配将通过。我的问题是如果你说 int x; 浮动y; 诠释z; x=5;y=7.5;z=x+y;我如何能够检查这一点,因为目前我的程序只保存变量的类型而不是值。

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);
  }
4

5 回答 5

2

我认为您需要多解释一下代码的结构。

在像您通常所说的口译员中,会发生三件事:

  1. 词法分析器/扫描器正在生成令牌流
  2. 解析器正在获取令牌并构建语义对象
  3. 解释器正在使用语义对象树并执行它们

第 1 阶段不需要关心您添加的是 int 和 float。第 2 阶段可以在您的语义对象/结构中填充一个警告字段,解释器在看到填充时将打印该警告字段,或者解释器本身可以识别此警告条件。

为了向您提供更多细节或使用更具体的术语,我们需要了解您如何表示操作。

于 2013-11-12T18:28:35.927 回答
1

我看到的两个选项,取决于你在做什么。

第一的。 在构建解析树时不要担心它。稍后,当您遍历树时,您可以轻松地检查这一点并抛出错误。

第二。int和 使用不同的规则float。所以你会有一个添加两个整数的规则和一个添加两个浮点数的规则。这也意味着你不会有一个number规则,我猜你会这样做,它混合了整数和浮点数。

我绝对推荐第一种方式。

于 2013-11-12T18:24:00.070 回答
1

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

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

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

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

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

于 2013-11-12T18:28:11.943 回答
0

这本书可能会有所帮助:

  • 编译器:A. Aho、M. Lam 和 R. Sethi 的《原则、技术和工具》(“Dragon Book”)。

以下是一组可以帮助您的工具:

  • GNU 弹性
  • GNU 野牛
于 2013-11-28T03:50:07.250 回答
0

+1 虚空逻辑。他的回答应该让您对如何构建递归下降解析器有一个基本的了解。如果您的某个部分遇到问题,最好能更详细地了解您是如何构建代码的。

如果您想查看其中的示例,请查看此实现

于 2013-11-28T02:40:02.760 回答