Использование типов C ++ в ANTLR-генерируемом синтаксическом анализаторе C - PullRequest
1 голос
/ 24 февраля 2010

Я пытаюсь использовать сгенерированный 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, я получаю сообщения об ошибках типа

  1. conversion from ‘long int’ to non-scalar type ‘Expr’ requested
  2. no match for ‘operator=’ in ‘e = 0l’
  3. 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 ++?

1 Ответ

3 голосов
/ 25 февраля 2010

Вот решения, которые я нашел для этой проблемы.Суть проблемы в том, что ANTLR хочет инициализировать все возвращаемые значения и атрибуты.Для непримитивных типов ANTLR просто предполагает, что он может инициализироваться с NULL.Так, например, вышеприведенное правило expression будет преобразовано в нечто вроде

static Expr
expression(pExprParser ctx)
{   
    Expr e = NULL; // Declare and init return value
    Kind k; // declare attributes
    Expr op1, op2;
    k = NULL; // init attributes
    op1 = NULL;
    op2 = NULL;
    ...
}

Варианты, как я их вижу, таковы:

  1. Giveзначения примитивных типов, которые могут быть юридически инициализированы до NULL.Например, используйте Expr* и Kind* вместо Expr и Kind.

  2. Используйте «фиктивный» трюк, как указано выше, чтобы вставить значение в структуру, гдеоно не будет инициализировано.

  3. Использовать ссылочные параметры вместо возвращаемых значений.Например,

    builtinOp[Kind& kind]
      : TOK_PLUS { kind = PLUS; }
      | TOK_MINUS { kind = MINUS; }
      ;
    
  4. Дополните классы, используемые в качестве типов значений, операциями, которые делают указанные выше объявления и инициализации легальными.Т.е. для Expr возвращаемого значения вам нужен конструктор, который может принимать NULL:

    Expr(long int n);
    

    Для атрибута Expr вам нужен конструктор без аргументов и operator=, которыйможет взять NULL:

    Expr();
    Expr operator=(long int n);
    

Я знаю, что это довольно забавно, но я собираюсь пока # 4Просто так получилось, что мой класс Expr имеет довольно естественное определение этих операций.

PS В списке ANTLR , сопровождающий бэкэнда C намекает, что эта проблема может быть решенав будущих выпусках.

...