Бизон, производящий последовательность после неправильной линии

Вход

 1  -- Narrowing Variable Initialization  
 2  
 3  function main a: integer returns integer;  
 4      b: integer is a * 2.;  
 5  begin  
 6      if a <= 0 then  
 7          b + 3;  
 8      else  
 9          b * 4;  
10      endif;  
11  end;  

приводит к продукции

  1  -- Narrowing Variable Initialization
  2  
  3  function main a: integer returns integer;
  4      b: integer is a * 2.;
  5  begin
Narrowing Variable Initialization
  6      if a <= 0 then
  7          b + 3;
  8      else
  9          b * 4;
 10      endif;
 11  end;

Вместо того, чтобы поместить то сообщение об ошибке под линией 4, который является, где ошибка на самом деле происходит. Я смотрел на него в течение многих часов и не могу понять его.

%union
{
    char* ident;
    Types types;
}

%token  IDENTIFIER
%token  INTEGER_LITERAL
%token  REAL_LITERAL
%token  BEGIN_
%token  FUNCTION
%token  IS
%token   INTEGER
%token   REAL
%token  RETURNS

%type   expression
%type   factor
%type   literal
%type   term
%type   statement
%type   type
%type   variable

%%

program:
    /* empty */ |
    functions ;

functions:
    function_header_recovery body ; |
    function_header_recovery body functions ;

function_header_recovery:
    function_header ';' |
    error ';' ;

function_header:
    FUNCTION {locals = new Locals();} IDENTIFIER optional_parameters RETURNS type {globals->insert($3,locals->tList);} ;

optional_parameters:
    /* empty */ |
    parameters;

parameters:
    IDENTIFIER ':' type {locals->insert($1, $3); locals->tList.push_back($3); } |
    IDENTIFIER ':' type {locals->insert($1, $3); locals->tList.push_back($3); } "," parameters;

type:
    INTEGER | REAL ;

body:
    optional_variables BEGIN_ statement END ';' ;

optional_variables:
    /* empty */ |
    variables ;

variables:
    variable IS statement {checkTypes($1, $3, 2);} |
    variable IS statement {checkTypes($1, $3, 2);} variables ;

variable:
    IDENTIFIER ':' type {locals->insert($1, $3);} {$$ = $3;} ;

statement:
    expression ';' |

...

Types checkTypes(Types left, Types right, int flag)
{
    if (left == right)
    {
        return left;
    }
    if (flag == 1)
    {
        Listing::appendError("Conditional Expression Type Mismatch", Listing::SEMANTIC);
    }
    else if (flag == 2)
    {
        if (left < right)
        {
            Listing::appendError("Narrowing Variable Initialization", Listing::SEMANTIC);
        }
    }
    return REAL_TYPE;
}

печать, обрабатываемая:

void Listing::nextLine()
{
printf("\n");
if (error == "")
{
    lineNo++;
    printf("%4d%s",lineNo,"  ");
}
else
{
    printf("%s", error.c_str());
error = "";
nextLine();
}
}

void Listing::appendError(const char* errText, int errEnum)
{
error = error + errText;

if (errEnum == 997)
{
    lexErrCount++;
}
else if (errEnum == 998)
{
    synErrCount++;
}
else if (errEnum == 999)
{
    semErrCount++;
}
}

void Listing::display()
{
printf( "\b\b\b\b\b\b    " );

if (lexErrCount + synErrCount + semErrCount > 0)
{
    printf("\n\n%s%d","Lexical Errors ",lexErrCount);
    printf("\n%s%d","Syntax Errors ",synErrCount);
    printf("\n%s%d\n","Semantic Errors ",semErrCount);
}
else
{
    printf("\nCompiled Successfully\n");
}
}
1
nl ja de

2 ответы

Это - просто путь бизон работы. Это производит предварительный анализатор с одним символом, таким образом, ваши производственные действия не становятся вызванными, пока это не прочитало символ после производство. Следовательно, начинаются должен быть прочитан перед действием, связанным с происходят переменные . (, бизон никогда не пытается объединить действия, даже если они дословно идентичны. Таким образом, это действительно не может знать, какой переменные производство применяет и какое действие выполнить, пока это не видит следующий символ.)

Есть различные способы связать номер строки и/или позицию столбцов с каждым символом, и использовать ту информацию, когда сообщение об ошибке должно быть написано. Вкрапление ошибок и/или предупреждений с входным текстом, в целом, требует буферизования входа; для синтаксических ошибок только необходимо буферизовать до следующего символа, но это не общее решение; в некоторых случаях, например, можно хотеть связать ошибку с оператором, например, но ошибка не будет обнаружена, пока перемещение оператора аргумента не было разобрано.

Простая техника, чтобы правильно вкрапить ошибки/предупреждения источником должна написать все ошибки/предупреждения временному файлу, поместив файловое смещение впереди каждой ошибки. Этот файл может тогда быть сортирован, и вход может тогда быть перечитан, вставив сообщения об ошибках в соответствующих пунктах. Хорошая вещь об этой стратегии состоит в том, что она избегает необходимости поддерживать номера строки для каждой ошибки, которая заметно замедляет лексический анализ. Конечно, это не будет работать так легко, если вы позволите конструкции как К #include .

Поскольку создание хороших сообщений об ошибках трудно, и даже местоположения отслеживания могут замедлить парсинг вполне немного, я иногда использовал стратегию парсинга входа дважды, если ошибка обнаружена. Первый разбор только обнаруживает ошибки и терпит неудачу рано, если он не может сделать ничего более разумного; если ошибка обнаружена, вход повторно разобран с более тщательно продуманным анализатором, который тщательно отслеживает расположение файлов и возможно даже использует эвристику как глубина углубления, чтобы попытаться написать лучшие сообщения об ошибках.

1
добавлено

Как rici примечания, бизон производит LALR (1) анализатор, таким образом, это использует один символ предвидения, чтобы знать что действие взять. Однако это не ВСЕГДА использует символ предвидения - в некоторых случаях (где есть только одна возможность независимо от предвидения), это использует сокращения по умолчанию, которые могут уменьшить правило (и управлять связанным действием) БЕЗ предвидения.

В вашем случае можно использовать в своих интересах это, чтобы заставить действие бежать без предвидения, если вы действительно должны. Конкретное рассматриваемое правило (который вызывает требование для предвидения):

variables:
    variable IS statement {checkTypes($1, $3, 2);} |
    variable IS statement {checkTypes($1, $3, 2);} variables ;

в этом случае после наблюдения переменная - заявление , это должно видеть следующий символ, чтобы решить, есть ли больше объявлений переменной, чтобы знать который действие (первое или второе) бежать. Но поскольку эти два действия - действительно то же самое, вы могли объединить их в единственное действие:

variables: vardecl | vardecl variables ;
vardecl: variable IS statement {checkTypes($1, $3, 2);}

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

Note that the above depends on being able to find the end of a statement without lookahead, which should be the case as long as all statements end unambiguously with a ;

0
добавлено
Все верные, но это кажется хрупким мне. По-видимому, есть другие возможные ошибки, и, вероятно, не будет возможно быть соглашением со всеми ними, управляя грамматикой.
добавлено автор rici, источник
pro.cxx
pro.cxx
3 049 участник(ов)

C/C++ chat 0. Простые вопросы, лабы и о IDE — в чат новичков @supapro 1. Не хамим, не переходим на личности, не вбрасываем утверждения без доказательств 2. No Ads, offtop, flood Объявления о вакансиях и евенты - в лс @AlexFails https://t.me/ProCxx/259155

Linux Help
Linux Help
2 686 участник(ов)

Правила: https://telegra.ph/Pravila-Linux-Help-10-15

supapro.cxx
supapro.cxx
1 925 участник(ов)

Чат для тех, кто немного знает C++, простые вопросы по реализации, синтаксису и ide – сюда, а для другого есть: /Главный чат по серьезным вопросам — @ProCxx /Чат по обсуждению всего — @fludpac

Linux Security
Linux Security
652 участник(ов)

Данная группа принципиально про безопасность и в частности про безопасность Linux. Прочие темы просим обсуждать в профильных чатах.

C++ Russia
C++ Russia
384 участник(ов)

Сообщество разработчиков C++ в Telegram.

cxx.Дискуссионная
cxx.Дискуссионная
298 участник(ов)

это не двач, общайтесь вежливо; разговор на почти любые темы; Не согласны с баном? В лс @AlexFails, @ivario

C++ для маленьких и тупых
C++ для маленьких и тупых
105 участник(ов)

Лоу левел (по среднему IQ участников) чатик ExtremeCode @extremecode Флудилка @extremecode_rest

Linux Gaming RUS
Linux Gaming RUS
28 участник(ов)

Русскоязычный чатик, посвящённый играм на различных дистрибутивах Linux, а также wine, proton Arch Linux RU @ArchLinuxChatRU Gnome RU @gnome_ru