| 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 */...С помощью правила для аргсписок (список аргументов) подсчитывается число аргументов. На первый взгляд может показаться, что нужно каким-то образом собирать аргументы, но это не так, поскольку каждое выражение (выраж) из списка аргументов вырабатывает значение в стеке как раз там, где оно необходимо.
Правило для опред вводит новое свойство языка
yaccbegindefnonlydefnonlydefnonly(s) /* warn if illegal definition */ char *s;{ if (!indef) execerror(s, "used outside definition");}Переменная
indefhoc.yК лексическому анализатору добавлены средства проверки аргументов: символ
$\nbackslashyylex() /* 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;}Лексический анализатор является примером конечного автомата независимо от того, написан ли он на Си или получен с помощью порождающей программы типа
lexlexОстальные изменения сосредоточены главным образом в файле
code.choc.hcode.c