Я пытаюсь использовать сгенерированный ANTLR v3.2 синтаксический анализатор в проекте C ++, используя C в качестве языка вывода. Сгенерированный парсер теоретически может быть скомпилирован как C ++, но у меня возникают проблемы при работе с типами C ++ внутри действий парсера. Вот заголовочный файл C ++, определяющий несколько типов, которые я хотел бы использовать в парсере:
/* expr.h */
enum Kind {
PLUS,
MINUS
};
class Expr { // stub
};
class ExprFactory {
public:
Expr mkExpr(Kind kind, Expr op1, Expr op2);
Expr mkInt(std::string n);
};
А вот простое определение синтаксического анализатора:
/* Expr.g */
grammar Expr;
options {
language = 'C';
}
@parser::includes {
#include "expr.h"
}
@members {
ExprFactory *exprFactory;
}
start returns [Expr expr]
: e = expression EOF { $expr = e; }
;
expression returns [Expr e]
: TOK_LPAREN k=builtinOp op1=expression op2=expression TOK_RPAREN
{ e = exprFactory->mkExpr(k,op1,op2); }
| INTEGER { e = exprFactory->mkInt((char*)$INTEGER.text->chars); }
;
builtinOp returns [Kind kind]
: TOK_PLUS { kind = PLUS; }
| TOK_MINUS { kind = MINUS; }
;
TOK_PLUS : '+';
TOK_MINUS : '-';
TOK_LPAREN : '(';
TOK_RPAREN : ')';
INTEGER : ('0'..'9')+;
Грамматика проходит через ANTLR просто отлично. Когда я пытаюсь скомпилировать ExprParser.c, я получаю сообщения об ошибках типа
conversion from ‘long int’ to non-scalar type ‘Expr’ requested
no match for ‘operator=’ in ‘e = 0l’
invalid conversion from ‘long int’ to ‘Kind’
В каждом случае оператор является инициализацией значения Expr
или Kind
равным NULL
.
Я могу решить проблему с Expr
, изменив все на Expr*
. Это работоспособно, хотя вряд ли идеально. Но показ указателей для простого перечисления типа Kind
кажется нелепым. Один уродливый обходной путь, который я нашел, состоит в создании второго возвращаемого значения, которое помещает значение Kind
в структуру и подавляет инициализацию до NULL
. Т.е. builtinOp
становится
builtinOp returns [Kind kind, bool dummy]
: TOK_PLUS { $kind = PLUS; }
| TOK_MINUS { $kind = MINUS; }
;
и первая expression
альтернатива становится
TOK_LPAREN k=builtinOp op1=expression op2=expression TOK_RPAREN
{ e = exprFactory->mkExpr(k.kind,*op1,*op2); }
Должен быть лучший способ сделать что-то? Мне не хватает опции конфигурации для бэкэнда языка C? Есть ли другой способ устроить мою грамматику, чтобы избежать этой неловкости? Можно ли использовать чистый бэкэнд C ++?