Литмир - Электронная Библиотека
Содержание  
A
A

%token <sym> NUMBER PRINT VAR BLTIN UNDEF WHILE IF ELSE

%type <inst> stmt asgn expr stmtlist cond while if end

%right '='

%left OR

%left AND

%left GT GE LT LE EQ NE

%left '+'

%left '*' '/'

%left UNARYMINUS NOT

%right '^'

%%

list: /* nothing */

 | list '\n'

 | list asgn '\n' { code2(pop, STOP); return 1; }

 | list stmt '\n' { code(STOP); return 1; }

 | list expr '\n' { code2(print, STOP); return 1; }

 | list error '\n' { yyerrok; }

 ;

asgn: VAR '=' expr { $$=$3; code3(varpush, (Inst)$1, assign); }

 ;

stmt: expr { code(pop); }

 | PRINT expr { code(prexpr); $$ = $2; }

 | while cond stmt end {

  ($1)[1] = (Inst)$3; /* body of loop */

  ($1)[2] = (Inst)$4; } /* end, if cond fails */

 | if cond stmt end { /* else-less if */

  ($1)[1] = (Inst)$3; /* thenpart */

  ($1)[3] = (Inst)$4; } /* end, if cond fails */

 | if cond stmt end ELSE stmt end { /* if with else */

  ($1)[1] = (Inst)$3; /* thenpart */

  ($1)[2] = (Inst)$6; /* elsepart */

  ($1)[3] = (Inst)$7; } /* end, if cond fails */

 | '{' stmtlist '}' { $$ = $2; }

 ;

cond: '(' expr ')' { code(STOP); $$ = $2; }

 ;

while: WHILE { $$ = code3(whilecode, STOP, STOP); }

 ;

if: IF { $$=code(ifcode); code3(STOP, STOP, STOP); }

 ;

end: /* nothing */ { code(STOP); $$ = progp; }

 ;

stmtlist: /* nothing */ { $$ = progp; }

 | stmtlist '\n'

 | stmtlist stmt

 ;

expr: NUMBER { $$ = code2(constpush, (Inst)$1); }

 | VAR { $$ = code3(varpush, (Inst)$1, eval); }

 | asgn

 | BLTIN '(' expr ')'

  { $$ = $3; code2(bltin, (Inst)$1->u.ptr); }

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

 | expr '+' expr { code(add); }

 | expr '-' expr { code(sub); }

 | expr '*' expr { code(mul); }

 | expr '/' expr { code(div); }

 | expr '^' expr { code (power); }

 | '-' expr %prec UNARYMINUS { $$ = $2; code(negate); }

 | expr GT expr { code(gt); }

 | expr GE expr { code(ge); }

 | expr LT expr { code(lt); }

 | expr LE expr { code(le); }

 | expr EQ expr { code(eq); }

 | expr NE expr { code(ne); }

 | expr AND expr { code(and); }

 | expr OR expr { code(or); }

 | NOT expr { $$ = $2; code(not); }

%%

/* end of grammar */

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

hoc3
.

Обратите внимание на то, что команды

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

Команды, создаваемые для операторов

if
и
while
, требуют особого рассмотрения. Когда встречается ключевое слово
while
, порождается операция
whilecode
, и адрес этой команды возвращается в качестве значения правила

пока: WHILE

Но в то же самое время резервируются два следующих машинных слова, которые будут определены ниже. Далее создаются команды для выражения, которое образует условие в операторе

while
. Значение, возвращаемое правилом
cond
, является адресом начала команд для условия. После распознавания всего оператора
while
в два зарезервированных слова, вводимых за командой
whilecode
, заносится адрес начала тела цикла и адрес оператора, следующего за циклом. (Команда по этому адресу будет создана позднее.)

| пока усл опер все {

 ($1)[1] = (Inst) $3 /* тело цикла */

 ($1)[2] = (Inst) $4 /* все, если условие неверно */

}

Здесь

$1
обозначает адрес команды
whilecode
, таким образом,
($1)[1]
и
($1)[2]
обозначают два следующих слова.

Рисунок, приведенный ниже, может прояснить ситуацию:

UNIX — универсальная среда программирования - img_6.jpeg

С оператором

if
дело обстоит аналогично, но резервируются три слова: для частей
then
и
else
, а также для оператора, следующего за
if
. Мы вскоре рассмотрим этот случай.

115
{"b":"248117","o":1}