Как получить всю входную строку в Lex и Yacc? - PullRequest
0 голосов
/ 06 августа 2009

ОК, вот сделка.

На моем языке у меня есть несколько команд, скажем

XYZ 3 5
GGB 8 9
HDH 8783 33

И в моем файле Lex

XYZ { return XYZ; }
GGB { return GGB; }
HDH { return HDH; }
[0-9]+ { yylval.ival = atoi(yytext); return NUMBER; }
\n  { return EOL; }

В моем файле yacc

start : commands
    ;

commands : command
         | command EOL commands
    ;

    command : xyz
            | ggb
            | hdh
    ;

    xyz : XYZ NUMBER NUMBER { /* Do something with the numbers */ }
       ;

    etc. etc. etc. etc.

У меня вопрос, как я могу получить весь текст

XYZ 3 5
GGB 8 9
HDH 8783 33

В команды при возврате НОМЕРОВ?

Также, когда мой Lex возвращает STRING [0-9a-zA-Z] +, и я хочу выполнить проверку его длины, я должен сделать это как

rule: STRING STRING { if (strlen($1) < 5 ) /* Do some shit else error */ }

или на самом деле в моем Lex есть токен, который возвращает разные токены в зависимости от длины?

Ответы [ 3 ]

1 голос
/ 06 августа 2009

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

1 голос
/ 06 августа 2009

Если я правильно понял ваш первый вопрос, у вас могут быть такие семантические действия, как

{ $$ = makeXYZ($2, $3); }

, который позволит вам построить значение команды, как вы хотите.

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

0 голосов
/ 06 августа 2009

Когда вы используете yylval.ival, у вас уже есть union с полем ival в вашем источнике YACC, например:

%union {
    int ival;
}

Теперь вы указываете тип токена, например:

%token <ival> NUMBER

Так что теперь вы можете получить доступ к полю ival просто для токена NUMBER как $1 в ваших правилах, например

xyz : XYZ NUMBER NUMBER { printf("XYZ %d %d", $2, $3); }

Для вашего второго вопроса я бы определил союз следующим образом:

%union {
    char*   strval;
    int     ival;
}

и в вашем LEX-источнике указываются типы токенов

%token <strval> STRING;
%token <ival> NUMBER;

Так что теперь вы можете делать такие вещи, как

foo : STRING NUMBER { printf("%s (len %d) %d", $1, strlen($1), $2); }
...