Чтение онлайн

ЖАНРЫ

UNIX — универсальная среда программирования
Шрифт:

func fac {

 if ($1 <= 0) return 1 else return $1 * fac($1-1)

}

$ hoc6 fac -

fac(0)

 1

fac(7)

 5040

fac(10)

 3628800

...

Внутри процедуры или функции к параметрам можно обращаться с помощью

$1
и т.д., как в командных файлах, но, кроме того, допустимо
присваивание параметрам. Функции и процедуры рекурсивны, но в качестве локальных переменных можно использовать только параметры; остальные переменные являются глобальными, т.е. доступными во всей программе.

В языке

hoc
функции и процедуры различаются, что дает возможность проверки, ценной для освобождения стека. (Ведь так легко забыть выполнить возврат или записать липшее выражение и получить несбалансированный стек!)

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

hoc5
к
hoc6
, но все они локальные. Нужны новые лексемы и нетерминальные символы, а в описание
%union
необходимо ввести новый элемент для хранения числа аргументов:

$cat hoc.y

...

%{

#include "hoc.h"

#define code2(c1,c2) code(c1); code(c2)

#define code3(c1,c2,c3) code(c1); code(c2); code(c3)

%}

%union {

 Symbol *sym; /* symbol table pointer */

 Inst *inst; /* machine instruction */

 int narg; /* number of arguments */

}

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

%token <sym> FUNCTION PROCEDURE RETURN FUNC PROC READ

%token <narg> ARG

%type <inst> expr stmt asgn prlist stmtlist

%type <inst> cond while if begin end

%type <sym> procname

%type <narg> arglist

%right '='

%left OR

%left AND

%left GT GE LT LE EQ NE

%left '+'

%left '*' '/'

%left UNARYMINUS NOT

%right '^'

%%

list: /* nothing */

 | list '\n'

 | list defn '\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 { code3(varpush,(Inst)$1,assign); $$=$3; }

 | ARG '=' expr

{ defnonly("$"); code2(argassign,(Inst)$1); $$=$3;}

 ;

stmt: expr { code(pop); }

 | RETURN { defnonly("return"); code(procret); }

 | RETURN expr

{ defnonly("return"); $$=$2; code(funcret); }

 | PROCEDURE begin '(' arglist ')'

{ $$ = $2; code3(call, (Inst)$1, (Inst)$4); }

 | PRINT prlist { $$ = $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); }

 ;

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

 ;

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

 ;

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

 | stmtlist '\n'

 | stmtlist stmt

 ;

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

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

 | ARG { defnonly("$"); $$ = code2(arg, (Inst)$1); }

 | asgn

 | FUNCTION begin '(' arglist ')'

{ $$ = $2; code3(call,(Inst)$1,(Inst)$4); }

 | READ '(' VAR ')' { $$ = code2(varread, (Inst)$3); }

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

Поделиться с друзьями: