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

 | 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); }

 ;

prlist: expr { code(prexpr); }

 | STRING { $$ = code2(prstr, (Inst)$1); }

 | prlist ',' expr { code(prexpr); }

 | prlist ',' STRING { code2(prstr, (Inst)$3); }

 ;

defn: FUNC procname { $2->type=FUNCTION; indef=1; }

  '(' ')' stmt { code(procret); define($2); indef=0; }

 | PROC procname { $2->type=PROCEDURE; indef=1; }

  '(' ')' stmt { code(procret); define($2); indef=0; }

 ;

procname: VAR

 | FUNCTION

 | PROCEDURE

 ;

arglist: /* nothing */ { $$ = 0; }

 | expr { $$ = 1; }

 | arglist expr { $$ = $1 + 1; }

 ;

%%

/* end of grammar */

...

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

Правило для опред вводит новое свойство языка

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

defnonly(s) /* warn if illegal definition */

 char *s;

{

 if (!indef)

  execerror(s, "used outside definition");

}

Переменная

indef
определена в
hoc.y
и принимает значения в действиях для опред.

К лексическому анализатору добавлены средства проверки аргументов: символ

$
, за которым следует чисто для строки в кавычках. Последовательности в строках, начинающиеся с обратной дробной черты, например
\n
, обрабатываются функцией
backslash
:

yylex() /* hoc6 */

 ...

 if (c == '$') { /* argument? */

  int n = 0;

  while (isdigit(c=getc(fin)))

   n = 10 * n + c — '0';

  ungetc(с, fin);

  if (n == 0)

   execerror("strange $...", (char*)0);

  yylval.narg = n;

  return ARG;

 }

 if (c == '"') { /* quoted string */

  char sbuf [100], *p, *emalloc();

  for (p = sbuf; (c=getc(fin)) != '"'; p++) {

   if (с == '\n' || c == EOF)

    execerror("missing quote", "");

   if (p >= sbuf + sizeof (sbuf) - 1) {

    *p = '\0';

    execerror("string too long", sbuf);

   }

   *p = backslash(c);

  }

  *p = 0;

  yylval.sym = (Symbol*)emalloc(strlen(sbuf)+1);

  strcpy(yylval.sym, sbuf);

  return STRING;

 }

 ...

backslash(c) /* get next char with \'s interpreted */

 int c;

{

 char *index(); /* 'strchr()' in some systems */

 static char transtab[] = "b\bf\fn\nr\rt\t";

 if (c != '\\')

  return c;

 c = getc(fin);

 if (islower(c) && index(transtab, c))

  return index(transtab, с)[1];

 return c;

}

Лексический анализатор является примером конечного автомата независимо от того, написан ли он на Си или получен с помощью порождающей программы типа

lex
. Наша первоначальная версия Си программы стала весьма сложной, и поэтому для всех программ, больших ее по объему, лучше использовать
lex
, чтобы максимально упростить внесение изменений.

Остальные изменения сосредоточены главным образом в файле

code.c
, хотя несколько имен функций добавляется к файлу
hoc.h
. Машина остается той же, но с дополнительным стеком для хранения последовательности вложенных вызовов функций и процедур (проще ввести второй стек, чем загружать больший объем информации в существующий). Начало файла
code.c
выглядит так:

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