从未在柠檬生成的解析器中声明自定义 class 成员导致编译错误

Never declared custom class members in lemon-generated parser cause compile errors

我正在尝试学习如何使用 Lemon 解析器生成器,并且我构建了一个学习项目。但是,当我尝试编译源代码时,我从 GCC 得到了一些奇怪的错误。看起来可能存在一些文本转录问题或拼写错误,但我找不到它。 我正在使用 C++11 标准进行编译。文件 "log" 包含编译器输出。

我用

编译
flex lexicon.l
lemon grammar.y
g++ -std=c++11 -o parser lex.yy.c grammar.c main.cpp 2> log

AST.h

#ifndef AST_H
#define AST_H

#include <string>
#include <sstream>
#include <iostream>
#include <unordered_map>
using namespace std;

string itos(int i) {
    stringstream ss;
    ss << i;
    return ss.str();
}

class Identifier {
    string name;
public:
    Identifier()
    : name("") {
        cerr << "This initializer should never be called!" << endl;
    }

    Identifier(string _name)
    : name(_name) {
    }
    string getName() {
        return name;
    }
};

unordered_map<string, Identifier> identifiers;

class ASTNode {
public:
    virtual string toString() = 0;
};

class StatementNode: public ASTNode {
public:
    virtual string toString() = 0;
};

class AssignmentNode: public StatementNode {
    Identifier *id;
    int newValue;
public:
    AssignmentNode(Identifier *_id, int _newValue)
    : id(_id),
      newValue(_newValue) {
    }

    string toString() {
        return id->getName() + " is now " + itos(newValue);
    }
};

class ExpressionNode: public StatementNode {
public:
    virtual string toString() = 0;
};

class ValueExpressionNode: public ExpressionNode {
    int value;
public:
    ValueExpressionNode(int _value)
    : value(_value) {
    }

    string toString() {
        return string("value: ") + itos(value);
    }
};

class IdentifierExpressionNode: public ExpressionNode {
    Identifier *id;
public:
    IdentifierExpressionNode(Identifier *_id)
    : id(_id) {
    }

    string toString() {
        return string("id : ") + id->getName();
};

class PlusExpressionNode: public ExpressionNode {
    ExpressionNode *lexp;
    ExpressionNode *rexp;
public:
    PlusExpressionNode(ExpressionNode *_lexp, ExpressionNode *_rexp)
    : lexp(_lexp),
      rexp(_rexp) {
    }

    string toString() {
        return string("(") + lexp->toString() + " + " + rexp->toString() + ")";
    }
};

class MinusExpressionNode: public ExpressionNode {
    ExpressionNode *lexp;
    ExpressionNode *rexp;
public:
    MinusExpressionNode(ExpressionNode *_lexp, ExpressionNode *_rexp)
    : lexp(_lexp),
      rexp(_rexp) {
    }

    string toString() {
        return string("(") + lexp->toString() + " - " + rexp->toString() + ")";
    }
};

class TimesExpressionNode: public ExpressionNode {
    ExpressionNode *lexp;
    ExpressionNode *rexp;
public:
    TimesExpressionNode(ExpressionNode *_lexp, ExpressionNode *_rexp)
    : lexp(_lexp),
      rexp(_rexp) {
    }

    string toString() {
        return string("(") + lexp->toString() + " * " + rexp->toString() + ")";
    }
};

class DividedByExpressionNode: public ExpressionNode {
    ExpressionNode *lexp;
    ExpressionNode *rexp;
public:
    DividedByExpressionNode(ExpressionNode *_lexp, ExpressionNode *_rexp)
    : lexp(_lexp),
      rexp(_rexp) {
    }

    string toString() {
        return string("(") + lexp->toString() + " / " + rexp->toString() + ")";
    }
};

#endif

grammar.y:

%include {
#include <vector>
#include <iostream>
#include <cassert>
#include <sstream>
#include "AST.h"

int atoi (char * a) {
    std::stringstream ss;
    ss << a;
    int i;
    ss >> i;
    return i;
}

Identifier* idForName(string name) {
    if (identifiers.find(name) == identifiers.end()) {
        identifiers[name] = Identifier(name);
    }
    return &(identifiers.at(name));
}
}

%token_type {char *}
%extra_argument {std::vector<StatementNode*>* statements}

start ::= statements.

statements ::= statement(stmt).
{
    statements->push_back(stmt);
}

statements ::= statements NEWLINE statement(stmt).
{
    statements->push_back(stmt);
}

%type statement {StatementNode*}

statement(stmt) ::= assignment(asgn).
{
    stmt = asgn;
}

%type assignment {AssignmentNode*}

assignment(asgn) ::= IDENTIFIER(id) EQUALS NUMBER(num).
{

    asgn = new AssignmentNode(idForName(id)), atoi(num));
}

statement(stmt) ::= expression(expr).
{
    stmt = expr;
}

%type expression {ExpressionNode*}

expression(expr) ::= NUMBER(num).
{
    expr = new ValueExpressionNode(atoi(num));
}

expression(expr) ::= IDENTIFIER(id).
{
    expr = IdentifierExpression(idForName(id));
}

expression(expr) ::= LROUNDPAREN expression(pexpr) RROUNDPAREN.
{
    expr = pexpr;
}

expression(expr) ::= expression(lexp) PLUS expression(rexp).
{
    expr = new PlusExpressionNode(lexp, rexp);
}

expression(expr) ::= expression(lexp) MINUS expression(rexp).
{
    expr = new MinusExpressionNode(lexp, rexp);
}

expression(expr) ::= expression(lexp) TIMES expression(rexp).
{
    expr = new TimesExpressionNode(lexp, rexp);
}

expression(expr) ::= expression(lexp) DIVIDEDBY expression(rexp).
{
    expr = new DividedByExpressionNode(lexp, rexp);
}

%left PLUS MINUS.
%left TIMES DIVIDEDBY.
%nonassoc LROUNDPAREN RROUNDPAREN.

lexicon.l:

%{
#include "grammar.h"
%}

%option noyywrap

%%

[A-Za-z_][A-Za-z0-9]*   return IDENTIFIER;
[0-9]+                  return NUMBER;
"="                     return EQUALS;
"+"                     return PLUS;
"-"                     return MINUS;
"*"                     return TIMES;
"/"                     return DIVIDEDBY;
"("                     return LROUNDPAREN;
")"                     return RROUNDPAREN;
\n                      return NEWLINE;
%%

main.cpp

#include <iostream>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstring>

#include "AST.h"

using namespace std;

void* ParseAlloc(void* (*allocProc)(size_t));
void Parse(void*, int, char *, vector<StatementNode*>*);
void ParseFree(void*, void(*freeProc)(void*));

int yylex();
extern char * yytext;

int main() {
    vector<StatementNode*> statements;
    vector<char*> strpointers;
    void* parser = ParseAlloc(malloc);
    while (int lexcode = yylex()) {
        char *tmp = (char*)malloc((strlen(yytext)+1)*sizeof(char));
        strcpy(tmp, yytext);
        Parse(parser, lexcode, tmp, &statements);
        strpointers.push_back(tmp);
    }

    for (vector<StatementNode*>::iterator i = statements.begin(); i != statements.end(); i++) {
        cout << (*i)->toString() << endl;
    }

    Parse(parser, 0, NULL, &identifiers);
    ParseFree(parser, free);
    for (vector<char*>::iterator i=strpointers.begin(); i != strpointers.end(); i++) {
        free(*i);
    }

    return 0;
}

日志:

grammar.c:105:44: error: ‘constexpr’ needed for in-class initialization of static data member ‘const IdentifierExpressionNode::YYMINORTYPE IdentifierExpressionNode::yyzerominor’ of non-integral type [-fpermissive]
grammar.c:173:1: error: in-class initialization of static data member ‘const unsigned char IdentifierExpressionNode::yy_action []’ of incomplete type
grammar.c:179:1: error: in-class initialization of static data member ‘const unsigned char IdentifierExpressionNode::yy_lookahead []’ of incomplete type
grammar.c:187:1: error: in-class initialization of static data member ‘const signed char IdentifierExpressionNode::yy_shift_ofst []’ of incomplete type
grammar.c:194:1: error: in-class initialization of static data member ‘const signed char IdentifierExpressionNode::yy_reduce_ofst []’ of incomplete type
grammar.c:199:1: error: in-class initialization of static data member ‘const unsigned char IdentifierExpressionNode::yy_default []’ of incomplete type
grammar.c:257:28: error: ‘constexpr’ needed for in-class initialization of static data member ‘FILE* IdentifierExpressionNode::yyTraceFILE’ of non-integral type [-fpermissive]
grammar.c:258:30: error: ‘constexpr’ needed for in-class initialization of static data member ‘char* IdentifierExpressionNode::yyTracePrompt’ of non-integral type [-fpermissive]
grammar.c:296:1: error: in-class initialization of static data member ‘const char* const IdentifierExpressionNode::yyTokenName []’ of incomplete type
grammar.c:316:1: error: in-class initialization of static data member ‘const char* const IdentifierExpressionNode::yyRuleName []’ of incomplete type
grammar.c:642:1: error: in-class initialization of static data member ‘const IdentifierExpressionNode::<anonymous struct> IdentifierExpressionNode::yyRuleInfo []’ of incomplete type
grammar.c:842:13: error: ‘static void IdentifierExpressionNode::yy_accept(IdentifierExpressionNode::yyParser*)’ cannot be overloaded
grammar.c:644:13: error: with ‘static void IdentifierExpressionNode::yy_accept(IdentifierExpressionNode::yyParser*)’
grammar.c:1025:1: error: expected ‘}’ at end of input
grammar.y: In static member function ‘static void IdentifierExpressionNode::yy_reduce(IdentifierExpressionNode::yyParser*, int)’:
grammar.y:51:69: error: cannot call member function ‘Identifier* IdentifierExpressionNode::idForName(std::string)’ without object
grammar.y:51:96: error: cannot call member function ‘int IdentifierExpressionNode::atoi(char*)’ without object
grammar.y:51:97: error: expected ‘;’ before ‘)’ token
grammar.y:63:68: error: cannot call member function ‘int IdentifierExpressionNode::atoi(char*)’ without object
grammar.y:68:70: error: cannot call member function ‘Identifier* IdentifierExpressionNode::idForName(std::string)’ without object
grammar.y:68:71: error: ‘IdentifierExpression’ was not declared in this scope
grammar.c: At global scope:
grammar.c:1025:1: error: expected unqualified-id at end of input
main.cpp:9:7: error: expected nested-name-specifier before ‘namespace’
main.cpp:9:7: error: expected unqualified-id before ‘namespace’
main.cpp:9:7: error: expected ‘;’ before ‘namespace’
main.cpp:9:7: error: expected unqualified-id before ‘namespace’
main.cpp:16:15: error: storage class specified for ‘yytext’
main.cpp:40:1: error: expected ‘}’ at end of input
main.cpp: In member function ‘int IdentifierExpressionNode::main()’:
main.cpp:33:37: error: no matching function for call to ‘IdentifierExpressionNode::Parse(void*&, int, NULL, std::unordered_map<std::basic_string<char>, Identifier>*)’
main.cpp:33:37: note: candidate is:
main.cpp:12:6: note: void IdentifierExpressionNode::Parse(void*, int, char*, std::vector<StatementNode*>*)
main.cpp:12:6: note:   no known conversion for argument 4 from ‘std::unordered_map<std::basic_string<char>, Identifier>*’ to ‘std::vector<StatementNode*>*’
main.cpp: At global scope:
main.cpp:40:1: error: expected unqualified-id at end of input

您在 AST.h 中缺少一个大括号。

您收到的第一条错误消息表明不允许给定声明 "in-class"。这是你需要的线索。看起来它不应该在 class 中,那么为什么编译器认为它是?这应该使您强烈怀疑之前某处缺少右括号。实际上,如果您查看 AST.h 文件,您会发现:

class IdentifierExpressionNode: public ExpressionNode {
    Identifier *id;
public:
    IdentifierExpressionNode(Identifier *_id)
    : id(_id) {
    }

    string toString() {
        return string("id : ") + id->getName();
};

您需要向 toString 添加一个缺少的右括号。

一般来说,当您收到像这样的一长串错误消息时,您应该只仔细查看第一个错误或前几个错误,而忽略其余错误。它们很可能都是由同一个原因引起的,并且您越是从事情开始出错的那一点开始阅读,更多的错误消息就越没用。