Восстановление множественных ошибок Bison C++ с отсутствующей точкой с запятой

Я разрабатываю свой собственный компилятор, и у меня есть проблема с дизайном восстановления после ошибок в режиме паники для грамматики Java.

Я думал о нескольких решениях, но реальный вопрос:

Как я мог сделать это с Bison C++?

Я это сделал:

пакет 2

импорт java.lang.*;

ошибка должна указывать на первую точку с запятой, и это правильно работает с правилом

package_rule: ошибка PACKAGE ';'

но если бы я написал этот код:

пакет 2

импорт java.lang. *

class y {void method () {int m}

}

что мне нужно от парсера как стандартный компилятор, чтобы сообщать об ошибках:

Ожидается идентификатор в строке пакета. отсутствует ';' укажите один для пакета в строке инструкции по импорту. mssing ';' в строке м.

Я имею в виду, что мне нужно после ошибки пакета использовать токен до первой точки с запятой или остановиться, когда найти объявление класса или интерфейса в последней строке перед тем, как объявить их! и сообщать о любых других ошибках, найденных после строки:

int m // missing ';'

Пожалуйста, помогите мне, на мой взгляд, несколько решений, но как это сделать с Bison C++ для Java грамматики?

2 ответа

Ну, ваша основная проблема в том, как вы хотите, чтобы он пытался восстановиться после синтаксических ошибок. Когда у вас есть входная последовательность, как

package x import

Вы хотите, чтобы он предполагал, что там должна быть точка с запятой, или вы хотите, чтобы он предполагал, что что-то еще застряло перед точкой с запятой, и оно должно выбрасывать вещи, пока не достигнет точки с запятой?

Последнее то, что у вас есть - правило package: PACKAGE error ';' делает именно это - всякий раз, когда он видит ключевое слово PACKAGE но то, что последует за ним, не соответствует остальным package Правило, он должен выбросить ввод, пока не увидит ';' и попытаться продолжить оттуда.

Если вы хотите первое, вы бы использовали правило как package: PACKAGE name error - если он видит PACKAGE с чем-то, похожим на правильное имя пакета, но без точки с запятой, обработайте его, как если бы там была точка с запятой, и попробуйте продолжить.

Сделать так, чтобы ОБА из вышеперечисленных вещей было чрезвычайно сложно. Наиболее близким было бы, чтобы грамматика выглядела примерно так:

package: PACKAGE name ';'  /* normal package decl */
       | PACKAGE name      /* missing semicolon -- treat this as a semantic error */
       | PACKAGE error ';' /* no name -- skip up to the next semicolon to recover */

Однако такого рода вещи, вероятно, дадут вам грамматические конфликты, которые трудно разрешить.

Вы не будете возражать, чтобы решить эту проблему способом C++ ООП, а не бизоном, не так ли?

Предположим, у вас есть определенные типы узлов AST

struct BaseExpression {
    virtual std::string toIdentifier() = 0;
    // other member. remember to declare a virtual destructor
};

struct IntLiteral : BaseExpression {
    std::string toIdentifier() {
        error::toAnIdentifier();
        return "";
    }
};

struct Identifier: BaseExpression {
    std::string ident;

    explicit Identifier(std::string id) : ident(id) {}

    std::string toIdentifer() {
        return ident;
    }
};

Определите такое правило

%union {
    BaseExpression* expr_type;
}

%type <expr_type> simple_expr

package_expr: simple_expr
{
    $1->toIdentifer(); // thus integers or float numbers would generate errors
    // do sth with that identifer
}
;

package_expr: package_rule '.' simple_expr
{
    $3->toIdentifer(); // same trick
    // do sth with that identifer
}
;

где simple_expr является

simple_expr: int_literal { return new IntLiteral; }
           | ...
           | identifier { return new Identifier(yytext); }
;
Другие вопросы по тегам