/* /local/src/master/nrn/src/oc/parse.y,v 1.29 1998/11/27 13:11:48 hines Exp */ %{ #include <../../nrnconf.h> /* changes as of 2-jan-89 */ /* version 7.2.1 2-jan-89 short form of the for statement */ #if AIX #pragma alloca #endif #include "hoc.h" #include "code.h" #include "equation.h" #if LINT Inst *inlint; #define code inlint = Code #else #define code Code #endif extern Inst* codei(int i); #define paction(arg) fprintf(stderr, "%s\n", arg) /* maintain a list of ierr addresses so we can clear them */ #define HOCERRSIZE 20 static int** hoc_err; static int hoc_errp; static int localcnt; static clean_err() { int i; for (i=0; i < hoc_errp; ++i) { *hoc_err[i] = 0; } hoc_errp = 0; } static pusherr(ip) int* ip; { if (!hoc_err) { hoc_err = (int**)ecalloc(HOCERRSIZE, sizeof(int*)); hoc_errp = 0; } if (hoc_errp >= HOCERRSIZE) { clean_err(); hoc_execerror("error stack full", (char*)0); } hoc_err[hoc_errp++] = ip; } #if YYBISON #define myerr(arg) static int ierr=0;\ if (!(ierr++)){pusherr(&ierr);yyerror(arg);} --yyssp; --yyvsp; YYERROR #else #define myerr(arg) static int ierr=0;\ if (!(ierr++)){pusherr(&ierr);yyerror(arg);} YYERROR #endif #define code2(c1,c2) code(c1); codein(c2) #define code3(c1,c2,c3) code(c1); codesym(c2); code(c3) #define relative(ip1,ip2,offset) ((ip1-ip2) - offset) #define CHECK 1 /* check syntactically the consistency of arrays */ #define NOCHECK 0 /* don't check syntactically. For object components */ #define PN pushi(NUMBER) /* for type checking. expressions are usually numbers */ #define TPD hoc_ob_check(NUMBER); #define TPDYNAM hoc_ob_check(0); extern int pipeflag; extern Symlist *symlist; /* This list is permanent */ extern Symlist *p_symlist; /* Constants, strings, auto variables */ extern Symbol* hoc_decl(); extern Symbol* hoc_which_template(); extern Symbol* hoc_table_lookup(); extern arayinstal(); extern int indef; static Inst *prog_error; /* needed for stmtlist loc if error */ static int ntab; /* auto indentation */ extern FILE *fin; /* input file pointer */ static Inst* argcode(), *argrefcode(); %} %union { /* stack type */ Symbol *sym; /* symbol table pointer */ Inst *inst; /* machine instruction */ int narg; /* number of arguments */ } %token EQNEQ %token NUMBER STRING PRINT DELETE VAR BLTIN UNDEF WHILE IF ELSE FOR %token FUNCTION PROCEDURE RETURN FUNC PROC HOCOBJFUNC READ DOUBLE %token DEBUG EDIT FUN_BLTIN DEPENDENT EQUATION LOCAL HOCOBJFUNCTION %token BREAK CONTINUE AUTO STRDEF STOPSTMT CSTRING PARALLEL HELP %token ITERATOR ITERKEYWORD ITERSTMT STRINGFUNC OBJECTFUNC %token LOCALOBJ AUTOOBJ %token ARG NUMZERO ARGREF %type expr stmt asgn prlist delsym stmtlist strnasgn %type cond while if begin end for_init for_st for_cond for_inc %type eqn_list dep_list varname wholearray array pointer %type doublelist strlist string1 string2 %type iterator %type procname newname function string ckvar %type anyname %type arglist arglist1 local local1 newarray numdimen procstmt %type localobj local2 /* NEWCABLE */ %token SECTIONKEYWORD SECTION CONNECTKEYWORD ACCESSKEYWORD %token RANGEVAR MECHANISM INSERTKEYWORD FORALL NRNPNTVAR FORSEC IFSEC %token UNINSERTKEYWORD SETPOINTERKEYWORD SECTIONREF %type sectiondecl sectionname %type rangevar rangevar1 section section_or_ob /* END NEWCABLE */ /* OOP */ %token BEGINTEMPLATE ENDTEMPLATE NEW OBJECTVAR TEMPLATE %token OBJVARDECL PUBLICDECL EXTERNALDECL OBFUNCTION STRFUNCTION %token OBJECTARG STRINGARG ROP %type template publiclist externallist %type obvarname %type ob ob1 objvarlist object %type func_or_range_array_case argrefdim /* END OOP */ %right '=' %right ROP %left OR %left AND %left GT GE LT LE EQ NE %left '+' '-' /* left associative, same precedence */ %left '*' '/' '%'/* left assoc., higher precedence */ %left UNARYMINUS NOT %right '^' /* exponentiation */ %% list: /* nothing */ { ntab = 0;} | list '\n' { return '\n';} | list defn '\n' { return '\n';} | list asgn '\n' { hoc_ob_check(-1); code2(nopop, STOP); return 1; } | list stmt '\n' { codein(STOP); return 1; } | list expr '\n' { TPDYNAM; code2(print, STOP); return 1; } | list DEBUG '\n' { debug(); return '\n';} | list EDIT '\n' { return 'e';} | list string1 '\n' {code3(prstr, hoc_newline, STOP); return 1; } /* OOP */ | list template '\n' { return '\n';} /* END OOP */ | list '' '\n' { plt(-3,0.,0.); return '\n';} | list HELP {hoc_help();} '\n' { return '\n'; } | list error {clean_err(); hoc_execerror("parse error", (char*)0); #if LINT if (0) { if(yydebug); goto yynewstate; } #endif } ; asgn: varname ROP expr {Symbol *s; TPD; s = spop(); hoc_obvar_declare(s, VAR, 1); code3(varpush, s, assign); codei($2); PN;} | ARG ROP expr { TPD; defnonly("$"); argcode(argassign, $1); codei($2); $$=$3; PN;} | ARGREF argrefdim ROP expr { TPD; defnonly("$&"); argrefcode(hoc_argrefasgn, $1, $2); codei($3); $$=$4; PN;} /* NEWCABLE */ | rangevar ROP expr { TPD; code(range_const); codesym(spop()); codei($2); PN;} /* END NEWCABLE */ /* OOP */ |ob1 ROP NEW anyname '(' arglist ')' { Inst* p; hoc_opasgn_invalid($2); code(hoc_newobj); codesym(hoc_which_template($4)); codei($6); p = (Inst*)spop(); if (p) { p->i += 2; } } | ob1 ROP expr {Inst* p; TPDYNAM; code(hoc_object_asgn); codei($2); p = (Inst*)spop(); if (p) { p->i += 2; } } /* END OOP */ | varname ROP error {myerr("assignment to variable, make sure right side is a number");} ; /* OOP */ object: OBJECTVAR {pushi(OBJECTVAR);pushs($1); pushi(CHECK);} wholearray {$$ = $3; code(hoc_objectvar); spop(); codesym($1);} | OBJECTARG {defnonly("$o"); $$ = argcode(hoc_objectarg, $1); pushi(OBJECTVAR);} | AUTOOBJ {$$ = code(hoc_autoobject); codesym($1); pushi(OBJECTVAR);} | TEMPLATE '[' expr ']' {TPD; $$ = $3; code(hoc_constobject); codesym($1); pushi(OBJECTVAR);} | OBJECTFUNC begin '(' arglist ')' { $$ = $2; code(call); codesym($1); codei($4); code(hoc_known_type); codei(OBJECTVAR); pushi(OBJECTVAR);} | HOCOBJFUNCTION begin '(' arglist ')' { $$ = $2; code(call); codesym($1); codei($4); code(hoc_known_type); codei(OBJECTVAR); pushi(OBJECTVAR);} ; ob: ob1 { spop(); } ; ob1: object { pushs((Symbol*)0); } | ob1 '.' anyname {pushs($3);pushi(NOCHECK);} wholearray func_or_range_array_case {int isfunc; Inst* p; isfunc = ipop(); code(hoc_object_component); codesym(spop()); codei(ipop()); codei($6); codei(0); codesym(0); p = codei(isfunc); /* for USE_PYTHON */ spop(); pushs((Symbol*)p); /* in case assigning to a PythonObject we will want to update isfunc to 2 */ } | OBJECTVAR error {myerr("object syntax is o1.o2.o3.");} ; func_or_range_array_case: /* nothing */ {$$ = 0; pushi(0);} | '(' arglist ')' {$$ = $2; pushi(1);} ; template: BEGINTEMPLATE anyname {hoc_begintemplate($2);} | publiclist | externallist | ENDTEMPLATE anyname {hoc_endtemplate($2);} | BEGINTEMPLATE error {myerr("begintemplate Name\npublic namelist\nexternal namelist\n...\nendtemplate Name");} ; objvarlist: OBJVARDECL begin objvarlst1 {$$ = $2;} ; objvarlst1: obvarname {code(hoc_objvardecl); codesym($1); codei(0);} | obvarname numdimen {code(hoc_objvardecl); codesym($1); codei($2);} | objvarlst1 ',' obvarname {code(hoc_objvardecl); codesym($3); codei(0);} | objvarlst1 ',' obvarname numdimen {code(hoc_objvardecl); codesym($3); codei($4);} ; obvarname: anyname { Symbol* s; s = hoc_decl($1); if (s->type != UNDEF && s->type != OBJECTVAR) { acterror(s->name, " already declared"); } $$ = s; } ; publiclist: PUBLICDECL anyname {hoc_add_publiclist($2);} | publiclist ',' anyname {hoc_add_publiclist($3);} ; externallist: EXTERNALDECL VAR {hoc_external_var($2);} | externallist ',' VAR {hoc_external_var($3);} ; /* END OOP */ strnasgn: string2 ROP string1 {hoc_opasgn_invalid($2); code(assstr);} | ob1 ROP string1 {Inst* p = (Inst*) spop(); pushi(STRING); TPDYNAM; code(hoc_object_asgn); hoc_opasgn_invalid($2); codei($2); hoc_ob_check(-1); code(nopop); if (p) { p->i += 2; } } | string2 ROP ob {code(hoc_asgn_obj_to_str); hoc_opasgn_invalid($2); } | string2 error {myerr("string assignment: both sides need to be a string");} ; string1: string2 | CSTRING {$$ = code(hoc_push_string); codesym($1);} | STRINGFUNC begin '(' arglist ')' { $$ = $2; code(call); codesym($1); codei($4);} ; string2: STRING {$$ = code(hoc_push_string); codesym($1);} | STRINGARG {defnonly("$s"); $$ = argcode(hoc_stringarg, $1);} ; strlist: STRDEF begin string { $$ = $2; } | strlist ',' string ; string: anyname { Symbol* s = hoc_decl($1); if (s->type == UNDEF) { hoc_obvar_declare(s, STRING, 0); OPSTR(s) = (char**)emalloc(sizeof(char*)); *OPSTR(s) = 0; }else if (s->type != STRING) { acterror(s->name, " already declared"); } hoc_assign_str(OPSTR(s), ""); } ; stmt: expr { code(nopop); hoc_ob_check(-1); /*don't check*/} | strlist | doublelist /* OOP */ | objvarlist /* END OOP */ | strnasgn | string1 { code(nopop); } | DELETE delsym { $$ = $2;} | RETURN begin { defnonly("return"); $$=$2; code(procret); } | RETURN expr { if (indef == 3) { TPDYNAM; $$ = $2; code(hocobjret); }else{ TPD; defnonly("return"); $$=$2; code(funcret); } } | RETURN NEW anyname '(' arglist ')' {$$ = code(hoc_newobj_ret); codesym(hoc_which_template($3)); codei($5); code(hocobjret); } | ITERSTMT begin { if (indef != 2) { acterror("iterator_statement used outside an iterator declaration", 0); } code(hoc_iterator_stmt); } | BREAK begin { code(Break); $$ = $2; } | STOPSTMT begin { code(Stop); $$ = $2; } | CONTINUE begin { code(Continue); $$ = $2; } | PROCEDURE begin '(' arglist ')' { $$ = $2; code(call); codesym($1); codei($4); code(nopop); } | PRINT prlist { $$ = $2; code(hoc_newline); } | FOR begin iterator stmt end { $$ = $2; ($3)[0].i = relative($4, $3, 0); /* body */ ($3)[1].i = relative($5, $3, 1); /* exit */ } | for_init for_st for_cond for_inc stmt end { ($2)[1].i =relative($5, $2, 1); /* body */ ($2)[2].i =relative($6, $2, 2); /* exit from the for */ ($2)[3].i =relative($4, $2, 3); /* increment */ $$ = $1; #if LINT if (0){YYERROR;} #endif } | FOR varname { Symbol *s; $$ = Code(varpush); codesym(s = spop()); hoc_obvar_declare(s, VAR, 1); } ROP expr ',' expr {TPD; TPD; hoc_opasgn_invalid($4); $$ = code(shortfor); codei(0); codei(0);} stmt end { $$ = $2; ($8)[1].i = relative($9, $8, 1); /* body */ ($8)[2].i = relative($10, $8, 2); /* exit */ } | PARALLEL FOR varname { Symbol *s; $$ = Code(varpush); codesym(s = spop()); hoc_obvar_declare(s, VAR, 1); } ROP expr ',' expr {TPD; TPD; hoc_opasgn_invalid($5); code(hoc_parallel_begin); $$ = code(shortfor); codei(0); codei(0);} stmt end { $$ = $3; ($9)[1].i = relative($10, $9, 1); /* body */ ($9)[2].i = relative($11, $9, 2); /* exit */ code(hoc_parallel_end); } | while cond stmt end { ($1)[1].i = relative($3, $1, 1); /* body of loop */ ($1)[2].i = relative($4, $1, 2); }/* end, if cond fails */ | if cond stmt end /* else-less if */ { ($1)[1].i = relative($3, $1, 1); /* thenpart */ ($1)[3].i = relative($4, $1, 3); }/* end, if cond fails */ | if cond stmt end ELSE stmt end /* if with else */ { ($1)[1].i = relative($3, $1, 1); /* thenpart */ ($1)[2].i = relative($6, $1, 2); /* elsepart */ ($1)[3].i = relative($7, $1, 3); }/* end, if cond fails */ | '{' { ntab++;} stmtlist '}' { ntab--; $$ = $3; } | eqn_list /* NEWCABLE */ | SECTIONKEYWORD begin sectiondecl { $$ = $2; } | CONNECTKEYWORD section_or_ob ',' expr { TPD; $$ = $2; code(connectsection);} | CONNECTKEYWORD section_or_ob ',' section '(' expr ')' { TPD; $$ = $2; code(simpleconnectsection);} | SETPOINTERKEYWORD rangevar '(' expr ')' ',' pointer { TPD; $$ = $2; code(connectpointer); codesym(spop());} | SETPOINTERKEYWORD begin {code(nrn_cppp);} ob ',' pointer { $$ = $2; code(connect_point_process_pointer); hoc_ob_check(-1);} | ACCESSKEYWORD section { $$ = $2; code(sec_access);} | ACCESSKEYWORD ob { $$ = $2; hoc_ob_check(SECTION); code(sec_access_object);} | INSERTKEYWORD MECHANISM { $$ = Code(mech_access); codesym($2);} | UNINSERTKEYWORD MECHANISM { $$ = Code(mech_uninsert); codesym($2);} | section stmt { code(sec_access_pop);} | ob stmt end { code(sec_access_pop); hoc_ob_check(-1); insertcode($2, $3, ob_sec_access);} | rangevar '(' expr ':' expr ')' ROP expr ':' expr { TPD; TPD; TPD; TPD; code(range_interpolate); codesym(spop()); codei($7); } | rangevar '(' expr ')' ROP expr { TPD; TPD; code(range_interpolate_single); codesym(spop()); codei($5); } | FOR '(' varname ')' {Symbol *s; code(varpush); codesym(s = spop()); hoc_obvar_declare(s, VAR, 1); $$ = code(for_segment); codei(0); codei(0);} stmt end { $$ = $3; ($5)[1].i = relative($6, $5, 1); /* body */ ($5)[2].i = relative($7, $5, 2); /* exit */ } | FOR '(' varname ',' {Symbol *s; code(varpush); codesym(s = spop()); hoc_obvar_declare(s, VAR, 1);} expr ')' { TPD; $$ = code(for_segment1); codei(0); codei(0);} stmt end { $$ = $3; ($8)[1].i = relative($9, $8, 1); /* body */ ($8)[2].i = relative($10, $8, 2); /* exit */ } | FORALL begin { code(hoc_push_string); codesym((Symbol*)0); $$ = code(forall_section); codei(0); codei(0);} stmt end { $$ = $2; ($3)[1].i = relative($4, $3, 1); /* body */ ($3)[2].i = relative($5, $3, 2); /* exit */ } | FORSEC begin string1 { $$ = code(forall_section); codei(0); codei(0);} stmt end { $$ = $2; ($4)[1].i = relative($5, $4, 1); /* body */ ($4)[2].i = relative($6, $4, 2); /* exit */ } | IFSEC begin string1 { $$ = code(hoc_ifsec); codei(0); codei(0);} stmt end { $$ = $2; ($4)[1].i = relative($5, $4, 1); /* body */ ($4)[2].i = relative($6, $4, 2); /* exit */ } | FORSEC begin ob {hoc_ob_check(-1); $$ = code(forall_sectionlist); codei(0); codei(0); } stmt end { $$ = $2; ($4)[1].i = relative($5, $4, 1); /* body */ ($4)[2].i = relative($6, $4, 2); /* exit */ } | IFSEC begin ob { hoc_ob_check(-1); $$ = code(hoc_ifseclist); codei(0); codei(0); } stmt end { $$ = $2; ($4)[1].i = relative($5, $4, 1); /* body */ ($4)[2].i = relative($6, $4, 2); /* exit */ } /* END NEWCABLE */ ; iterator: ITERATOR '(' arglist ')' { code(hoc_iterator); codesym($1); codei($3); $$ = progp; codein(STOP); codein(STOP); } | {code(hoc_push_current_object);} ob {codei(ITERATOR); $$ = progp; codein(STOP); codein(STOP); } ; /* NEWCABLE */ section: SECTION {pushs($1); pushi(CHECK);} wholearray {code(sec_access_push); codesym(spop()); $$ = $3;} ; section_or_ob: section '(' expr ')' {TPD;} | {$$ = progp; code(connect_obsec_syntax);} ob { #if 0 acterror("Sorry. The \"connect ob.sec...\" syntax ", "is not implemented"); #endif hoc_ob_check(SECTION); code(ob_sec_access); } ; sectiondecl: sectionname { code(add_section); codesym($1); codei(0);} | sectionname numdimen { code(add_section); codesym($1); codei($2);} | sectiondecl ',' sectionname {code(add_section); codesym($3); codei(0);} | sectiondecl ',' sectionname numdimen { code(add_section); codesym($3); codei($4);} ; sectionname:anyname { Symbol* s; s = hoc_decl($1); if (s->type != UNDEF && s->type != SECTION) acterror(s->name, " already declared"); } ; rangevar: rangevar1 { code(sec_access_push); codesym((Symbol *)0);} | section '.' rangevar1 ; rangevar1: RANGEVAR {pushs($1); pushi(CHECK);} wholearray {$$ = $3;} ; pointer: varname /*leave pointer on stack*/ { code3(varpush, spop(), hoc_evalpointer);} | rangevar '(' expr ')' { TPD; code(rangevarevalpointer); codesym(spop());} | ob {hoc_ipop(); code(hoc_ob_pointer);} | rangevar error {myerr("rangevariable needs explicit arc position,eg. v(.5)");} | ARGREF {$$ = argcode(hoc_argrefarg, $1);} ; /* END NEWCABLE */ for_init: FOR '(' stmt ';' { $$ = $3;} | FOR '(' ';' { $$ = progp; } ; for_st: /* nothing */ { $$ = code(forcode); codei(0); codei(0); codei(0); } ; for_cond: expr { TPD; $$ = $1; codein(STOP);} ; for_inc: ';' stmt ')' { $$ = $2; code(STOP);} | ';' ')' { $$ = progp; code(STOP);} ; cond: '(' expr ')' { TPD; codein(STOP); $$ = $2;} ; while: WHILE for_st { $$ = $2; } ; if: IF { $$=code(ifcode); codei(0); codei(0); codei(0); } ; begin: /* nothing */ { $$ = progp; } ; end: /* nothing */ { codein(STOP); $$ = progp; } ; stmtlist: /* nothing */ { $$ = progp; prog_error = $$; } | stmtlist '\n' { prog_parse_recover = progp; prog_error = $$; if (fin == stdin && !pipeflag) { int i; Printf(">"); for (i = 0; i < ntab; i++) Printf(" "); } } | stmtlist stmt | error {myerr("syntax error in compound statement");} ; expr: NUMBER { $$ = code(constpush); codesym($1); PN;} | NUMZERO { $$ = code(pushzero); PN;} | varname { code3(varpush, spop(), eval); PN;} | ARG { defnonly("$"); $$ = argcode(arg, $1); PN;} | ARGREF argrefdim { defnonly("$&"); $$ = argrefcode(hoc_argref, $1, $2); PN;} /* NEWCABLE */ | rangevar {code(rangepoint); codesym(spop()); PN;} | rangevar '(' expr ')' { TPD; code(rangevareval); codesym(spop()); PN;} /* END NEWCABLE */ /* OOP */ | ob {code(hoc_object_eval);} /* END OOP */ | asgn | function begin '(' arglist ')' { $$ = $2; code(call); codesym($1); codei($4); PN;} | varname '(' arglist ')' /* error will be flagged at runtime */ { code(call); codesym(spop()); codei($3); PN;} | READ '(' varname ')' { $$=$3; code(varread); codesym(spop()); PN;} | BLTIN '(' expr ')' { TPD; $$ = $3; code(bltin); codesym($1); PN;} | '(' expr ')' { $$ = $2; } | '(' error {myerr("syntax error in expression");} | expr '+' expr { TPD; TPD; code(add); PN; } | expr '-' expr { TPD; TPD;code(sub); PN;} | expr '*' expr { TPD; TPD; code(mul); PN;} | expr '/' expr { TPD; TPD; code(hoc_div); PN;} | expr '%' expr { TPD; TPD; code(hoc_cyclic); PN;} | expr '^' expr { TPD; TPD; code(power); PN;} | '-' expr %prec UNARYMINUS { TPD; $$ = $2; code(negate); PN;} | expr GT expr { TPD; TPD; code(gt); PN;} | expr GE expr { TPD; TPD; code(ge); PN;} | expr LT expr { TPD; TPD; code(lt); PN;} | expr LE expr { TPD; TPD; code(le); PN;} | expr EQ expr { hoc_ob_check(-1); hoc_ob_check(-1); code(eq); PN;} | expr NE expr { hoc_ob_check(-1); hoc_ob_check(-1); code(ne); PN;} | expr AND expr { TPD; TPD; code(hoc_and); PN;} | expr OR expr { TPD; TPD; code(hoc_or); PN;} | NOT expr { TPD; $$ = $2; code(hoc_not); PN;} ; function: FUNCTION | FUN_BLTIN | OBFUNCTION | STRFUNCTION ; doublelist: DOUBLE begin newarray {Symbol *s; code(varpush); codesym(s=spop()); $$ = $2; code(arayinstal); codei($3); hoc_obvar_declare(s, VAR, 0);} | doublelist ',' newarray {Symbol *s; code(varpush); codesym(s = spop()); code(arayinstal); codei($3); hoc_obvar_declare(s, VAR, 0);} ; newarray: newname numdimen {pushs($1); $$ = $2;} ; numdimen: '[' expr ']' { TPD; $$ = 1; } | numdimen '[' expr ']' { TPD;$$ = $$ + 1; } ; newname: ckvar ; varname: AUTO begin { pushs($1); $$ = $2; } | VAR begin { if ($1->subtype == USERPROPERTY) { code(sec_access_push); codesym((Symbol *)0); } pushs($1); pushi(CHECK); } wholearray {$$ = $2;} | section '.' VAR { if ($3->subtype != USERPROPERTY) { acterror($3->name, "not a section variable"); } $$ = $1; pushs($3); } ; wholearray:begin array /* using execution stack to get Symbol from array */ /* and whether to do syntactic check or not */ /* object component array may share a name with the current symbol table which is not an array. object component checking done dynamically */ /* numindices, checkflag=1, arraysym -> arraysym */ /* numindices, checkflag=0, arraysym -> arraysym numindices*/ { int d1, chk; Symbol *sym; d1 = ipop(); chk = ipop(); sym = spop(); if (chk) { if (!ISARRAY(sym)) { if (d1) acterror(sym->name, "not an array variable"); }else{ if ( d1 == 0 ) { /*fake index list with all 0's*/ int i; for (i=0; iarayinfo->nsub; i++) { code(pushzero); } } else if ( d1 != sym->arayinfo->nsub) { acterror("wrong # of subscripts",sym->name); } } }else { pushi(d1); /* must check dynamically */ } pushs(sym); } ; argrefdim: array { $$ = ipop(); } ; array: /* Nothing */ { pushi(0); } | array '[' expr ']' { TPD;pushi(ipop() + 1); } ; prlist: expr { TPDYNAM; code(prexpr);} | string1 { code(prstr); } | prlist ',' expr { TPDYNAM; code(prexpr);} | prlist ',' string1 { code(prstr); } ; delsym: VAR { $$ = code(hoc_delete_symbol); codesym($1); } ; defn: FUNC procname {$2->type=FUNCTION; indef=1; } '(' ')' procstmt { code(procret); hoc_define($2); $2->u.u_proc->nobjauto = $6 - localcnt; $2->u.u_proc->nauto=$6; indef=0; } | PROC procname { $2->type=PROCEDURE; indef=1; } '(' ')' procstmt { code(procret); hoc_define($2); $2->u.u_proc->nobjauto = $6 - localcnt; $2->u.u_proc->nauto=$6; indef=0; } | ITERKEYWORD procname { $2->type = ITERATOR; indef=2; } '(' ')' procstmt {code(procret); hoc_define($2); $2->u.u_proc->nobjauto = $6 - localcnt; $2->u.u_proc->nauto = $6; indef = 0; } | HOCOBJFUNC procname { $2->type=HOCOBJFUNCTION; indef=3; } '(' ')' procstmt { code(procret); hoc_define($2); $2->u.u_proc->nobjauto = $6 - localcnt; $2->u.u_proc->nauto=$6; indef=0; } ; procname: ckvar { Symbol *s; s=yylval.sym; if(s->type != UNDEF) acterror(s->name, "already defined"); s->u.u_proc = (Proc *)emalloc(sizeof(Proc)); s->u.u_proc->defn.in = STOP; s->u.u_proc->list = (Symlist *)0; } | FUNCTION | PROCEDURE | ITERATOR | HOCOBJFUNCTION ; procstmt: '{' local localobj {ntab++;} stmtlist '}' { ntab--; $$ = $2 + $3; } ; arglist: /* nothing */ { $$ = 0; } | arglist1 ; arglist1: arglist2 {$$ = 1;} | arglist1 ',' arglist2 {$$ = $1 + 1;} ; arglist2: string1 {} | expr { hoc_ob_check(-1);} | '&' pointer | NEW anyname '(' arglist ')' { code(hoc_newobj_arg); codesym(hoc_which_template($2)); codei($4); } ; eqn_list: DEPENDENT dep_list { $$ = $2; } | EQUATION varname ':' {code3(varpush, spop(), eqn_name); do_equation = 1; } equation { $$ = $2; do_equation = 0; } ; dep_list: varname {Symbol *s; code3(varpush,s= spop(), dep_make); hoc_obvar_declare(s, VAR, 0);} | dep_list ',' varname {Symbol *s; code3(varpush, s=spop(), dep_make); hoc_obvar_declare(s, VAR, 0);} ; equation: lhs EQNEQ | EQNEQ rhs | ':' { code(eqn_init); } lhs EQNEQ rhs ; lhs: { code(eqn_lhs); } expr { codein(STOP); TPD; } ; rhs: { code(eqn_rhs); } expr { codein(STOP); TPD; } ; local: /* nothing */ { $$ = 0; localcnt = $$;} | local1 ; local1: LOCAL anyname { Symbol *sp; $$ = 1; localcnt = $$; sp = install($2->name, AUTO, 0.0, &p_symlist); sp->u.u_auto = $$; } | local1 ',' anyname { Symbol *sp; $$ = $1 + 1; localcnt = $$; if (hoc_table_lookup($3->name, p_symlist)) { acterror($3->name, "already declared local"); } sp = install($3->name, AUTO, 0.0, &p_symlist); sp->u.u_auto = $$; } ; localobj: /* nothing */ { $$ = 0;} | local2 ; local2: LOCALOBJ anyname { Symbol *sp; $$ = 1; if (hoc_table_lookup($2->name, p_symlist)) { acterror($2->name, "already declared local"); } sp = install($2->name, AUTOOBJ, 0.0, &p_symlist); sp->u.u_auto = $$ + localcnt; } | local2 ',' anyname { Symbol *sp; $$ = $1 + 1; if (hoc_table_lookup($3->name, p_symlist)) { acterror($3->name, "already declared local"); } sp = install($3->name, AUTOOBJ, 0.0, &p_symlist); sp->u.u_auto = $$ + localcnt; } ; ckvar: VAR { Symbol* s; s = hoc_decl($1); if (s->subtype != NOTUSER) acterror("can't redeclare user variable", s->name); $$ = s; } ; anyname: STRING|VAR|UNDEF|FUNCTION|PROCEDURE|FUN_BLTIN|SECTION|RANGEVAR |NRNPNTVAR|OBJECTVAR|TEMPLATE|OBFUNCTION|AUTO|AUTOOBJ|SECTIONREF |MECHANISM|BLTIN|STRFUNCTION|HOCOBJFUNCTION|ITERATOR ; %% /* end of grammar */ yyerror(s) /* called for yacc syntax error */ char *s; { execerror(s, (char *)0); } acterror(s, t) /* recover from action error while parsing */ char *s, *t; { execerror(s,t); } static Inst* argrefcode(pfri, i, j) Pfri pfri; int i, j; { Inst* in; in = argcode(pfri, i); codei(j); return in; } static Inst* argcode(pfri, i) Pfri pfri; int i; { Inst* in; if (i == 0) { Symbol* si = hoc_lookup("i"); if (si->type != AUTO) { acterror("arg index used and i is not a LOCAL variable", 0); } in = code3(varpush, si, eval); Code(pfri); codei(0); }else{ in = Code(pfri); codei(i); } return in; } hoc_opasgn_invalid(op) int op; { if (op) { acterror("Invalid assignment operator.", "Only '=' allowed. "); } }