Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
УМК по СПО.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
1.79 Mб
Скачать

11.4.Пример простейшего интерпретатора формул

%token NAME

%left '+' '-'

%left '*' '/'

%%

s : e { printf( "%d\n", $1 ); }

e : e '+' e { $$ = $1 + $3; }

| e '-' e { $$ = $1 - $3; }

| e '*' e { $$ = $1 * $3; }

| e '/' e { $$ = $1 / $3; }

| '(' e ')'{ $$ = $2; }

| NAME ;

%%

#include

#include

int yylex() {

register int c, v;

while ((c = getchar()) == ' ');

if (isdigit(c)) {

for( v=c-'0'; isdigit( c=getchar() ); ) v=v*10+c-'0';

ungetc( c, stdin );

yylval = v;

return( NAME );

} else if( c=='\n' ) {

return( 0 );

} else {

yylval = c;

return( yylval=c );

}

}

int main() { for(;;) yyparse(); return 0; }

int yyerror(char *mes) { printf( "%s\n", mes ); return 0; }

11.5.Простой пример

Этот пример - полная yacc-спецификация, реализующая небольшой калькулятор; калькулятор имеет 26 регистров, помеченных буквами от a до z, и обрабатывает арифметические выражения, построенные при помощи операций

+, -, *, /, % (остаток от деления), & (побитное и), |

(побитное или)

и присваиваний. Если на вход калькулятору дается присваивание, оно выполняется; в противном случае выводится значение выражения. Как и в языке C, целая константа, если она начинается с 0 (нуль), трактуется как восьмеричная, иначе - как десятичная.

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

%{

#include

#include

int regs [26];

int base;

%}

%start list

%token DIGIT LETTER

%left '|'

%left '&'

%left '+' '-'

%left '*' '/' '%'

%left UMINUS /* устанавливает приоритет унарного минуса */

%% /* начало секции правил */

list : /* пусто */

| list stat '\n'

| list error '\n'

{

yyerrok;

}

;

stat : expr

{

(void) printf ("%d\n", $1);

}

| LETTER '=' expr

{

regs [$1] = $3;

}

;

expr : '(' expr ')'

{

$$ = $2;

}

expr '+' expr

{

$$ = $1 + $3;

}

expr '-' expr

{

$$ = $1 - $3;

}

expr '*' expr

{

$$ = $1 * $3;

}

expr '/' expr

{

$$ = $1 / $3;

}

expr '/' expr

{

$$ = $1 / $3;

}

expr '%' expr

{

$$ = $1 % $3;

}

expr '&' expr

{

$$ = $1 & $3;

}

expr '|' expr

{

$$ = $1 | $3;

}

'-' expr %prec UMINUS

{

$$ = - $2;

}

LETTER

{

$$ = regs[$1];

}

number

;

number : DIGIT

{

$$ = $1; base = ($1==0) ? 8 : 10;

}

number DIGIT

{

$$ = base * $1 + $2;

}

;

%% /* начало секции подпрограмм */

int yylex () /* процедура лексического анализа */

{ /* возвращает значение LETTER для */

/* строчной буквы, yylval = от 0 до 25, */

/* возвращает значение DIGIT для цифры, */

/* yylval = от 0 до 9, для остальных */

/* символов возвращается их значение */

int c;

/* пропуск пробелов */

while ((c = getchar ()) == ' ')

;

/* c - не пробел */

if (islower (c)) {

yylval = c - 'a';

return (LETTER);

}

if (isdigit (c)) {

yylval = c - '0';

return (DIGIT);

}

return (c);

}