215bed1996-09-28Fredrik Hübinette (Hubbe) /*\ ||| This file a part of Pike, and is copyright by Fredrik Hubinette ||| Pike is distributed as GPL (General Public License) ||| See the files COPYING and DISCLAIMER for more information. \*/ %pure_parser /* * These values are used by the stack machine, and can not be directly * called from Pike. */ %token F_ADD_256 F_ADD_512 F_ADD_768 F_ADD_1024 F_ADD_256X %token F_PREFIX_256 F_PREFIX_512 F_PREFIX_768 F_PREFIX_1024 %token F_PREFIX_CHARX256 F_PREFIX_WORDX256 F_PREFIX_24BITX256 %token F_POP_VALUE F_POP_N_ELEMS F_MARK F_MARK2 %token F_CALL_LFUN F_CALL_LFUN_AND_POP %token F_BRANCH F_BRANCH_WHEN_ZERO F_BRANCH_WHEN_NON_ZERO %token F_BRANCH_WHEN_LT F_BRANCH_WHEN_GT %token F_BRANCH_WHEN_LE F_BRANCH_WHEN_GE %token F_BRANCH_WHEN_EQ F_BRANCH_WHEN_NE %token F_INC_LOOP F_DEC_LOOP %token F_INC_NEQ_LOOP F_DEC_NEQ_LOOP %token F_INDEX F_INDIRECT F_STRING_INDEX F_LOCAL_INDEX %token F_POS_INT_INDEX F_NEG_INT_INDEX %token F_LTOSVAL F_LTOSVAL2 %token F_PUSH_ARRAY %token F_RANGE F_COPY_VALUE /* * Basic value pushing */ %token F_LFUN F_GLOBAL F_LOCAL %token F_GLOBAL_LVALUE F_LOCAL_LVALUE %token F_CLEAR_LOCAL %token F_CONSTANT F_FLOAT F_STRING %token F_NUMBER F_NEG_NUMBER F_CONST_1 F_CONST0 F_CONST1 F_BIGNUM /* * These are the predefined functions that can be accessed from Pike. */ %token F_INC F_DEC F_POST_INC F_POST_DEC F_INC_AND_POP F_DEC_AND_POP %token F_INC_LOCAL F_INC_LOCAL_AND_POP F_POST_INC_LOCAL %token F_DEC_LOCAL F_DEC_LOCAL_AND_POP F_POST_DEC_LOCAL %token F_RETURN F_DUMB_RETURN F_RETURN_0 F_THROW_ZERO %token F_ASSIGN F_ASSIGN_AND_POP %token F_ASSIGN_LOCAL F_ASSIGN_LOCAL_AND_POP %token F_ASSIGN_GLOBAL F_ASSIGN_GLOBAL_AND_POP %token F_ADD F_SUBTRACT %token F_MULTIPLY F_DIVIDE F_MOD %token F_LT F_GT F_EQ F_GE F_LE F_NE %token F_NEGATE F_NOT F_COMPL %token F_AND F_OR F_XOR %token F_LSH F_RSH %token F_LAND F_LOR %token F_SWITCH F_SSCANF F_CATCH %token F_CAST %token F_FOREACH %token F_SIZEOF F_SIZEOF_LOCAL /* * These are token values that needn't have an associated code for the * compiled file */ %token F_MAX_OPCODE %token F_ADD_EQ %token F_AND_EQ %token F_APPLY %token F_ARG_LIST %token F_ARRAY_ID %token F_ARROW %token F_BREAK %token F_CASE %token F_CLASS %token F_COLON_COLON %token F_COMMA %token F_CONTINUE %token F_DEFAULT %token F_DIV_EQ %token F_DO %token F_DOT_DOT %token F_DOT_DOT_DOT %token F_PREDEF %token F_EFUN_CALL %token F_ELSE %token F_FLOAT_ID %token F_FOR %token F_FUNCTION_ID %token F_GAUGE %token F_IDENTIFIER %token F_IF %token F_INHERIT %token F_INLINE %token F_INT_ID %token F_LAMBDA %token F_MULTISET_ID %token F_MULTISET_END %token F_MULTISET_START %token F_LOCAL %token F_LSH_EQ %token F_LVALUE_LIST %token F_MAPPING_ID %token F_MIXED_ID %token F_MOD_EQ %token F_MULT_EQ %token F_NO_MASK %token F_OBJECT_ID %token F_OR_EQ %token F_PRIVATE %token F_PROGRAM_ID %token F_PROTECTED %token F_PUBLIC %token F_RSH_EQ %token F_STATIC %token F_STATUS %token F_STRING_ID %token F_SUBSCRIPT %token F_SUB_EQ %token F_TYPEOF %token F_VAL_LVAL %token F_VARARGS %token F_VOID_ID %token F_WHILE %token F_XOR_EQ %token F_ALIGN %token F_POINTER %token F_LABEL %token F_MAX_INSTR %right '=' %right '?' %left F_LOR %left F_LAND %left '|' %left '^' %left '&' %left F_EQ F_NE %left '>' F_GE '<' F_LE /* nonassoc? */ %left F_LSH F_RSH %left '+' '-'
413c8e1996-11-01Fredrik Hübinette (Hubbe) %left '*' '%' '/'
215bed1996-09-28Fredrik Hübinette (Hubbe) %right F_NOT '~' %nonassoc F_INC F_DEC %{ /* This is the grammar definition of Pike. */ #include "global.h" #ifdef HAVE_MEMORY_H #include <memory.h> #endif #include "interpret.h" #include "array.h" #include "object.h" #include "stralloc.h" #include "las.h" #include "interpret.h" #include "lex.h" #include "program.h" #include "pike_types.h" #include "constants.h" #include "macros.h" #include "error.h" #include "docode.h" #define YYMAXDEPTH 600 static void push_locals(); static void pop_locals(); void free_all_local_names(); void add_local_name(struct pike_string *,struct pike_string *); /* * The names and types of arguments and auto variables. */ struct locals *local_variables; static int varargs; static INT32 current_modifiers; void fix_comp_stack(int sp) { if(comp_stackp>sp) { yyerror("Compiler stack fixed."); comp_stackp=sp; }else if(comp_stackp<sp){ fatal("Compiler stack frame underflow."); } } %} %union { int number; FLOAT_TYPE fnum; unsigned int address; /* Address of an instruction */ struct pike_string *string; char *str; unsigned short type; struct node_s *n; struct efun *efun; } %type <fnum> F_FLOAT %type <number> modifiers modifier optional_dot_dot_dot %type <number> assign F_NUMBER F_LOCAL arguments arguments2 %type <number> optional_stars modifier_list %type <string> F_IDENTIFIER F_STRING string_constant low_string %type <string> optional_identifier cast simple_type %type <string> optional_rename_inherit %type <number> F_ARRAY_ID F_BREAK F_CASE F_CATCH F_CONTINUE F_DEFAULT F_DO %type <number> F_PREDEF F_ELSE F_FLOAT_ID F_FOR F_FOREACH F_FUNCTION_ID F_GAUGE %type <number> F_IF F_INHERIT F_INLINE F_INT_ID F_LAMBDA F_MULTISET_ID F_MAPPING_ID %type <number> F_MIXED_ID F_NO_MASK F_OBJECT_ID F_PRIVATE F_PROGRAM_ID %type <number> F_PROTECTED F_PUBLIC F_RETURN F_SSCANF F_STATIC %type <number> F_STRING_ID F_SWITCH F_VARARGS F_VOID_ID F_WHILE /* The following symbos return type information */ %type <n> string expr01 expr00 comma_expr comma_expr_or_zero %type <n> expr2 expr1 expr3 expr0 expr4 catch lvalue_list %type <n> lambda for_expr block assoc_pair new_local_name %type <n> expr_list2 m_expr_list m_expr_list2 statement gauge sscanf %type <n> for do cond optional_else_part while statements %type <n> local_name_list class catch_arg comma_expr_or_maxint %type <n> unused2 foreach unused switch case return expr_list default %type <n> continue break block_or_semi typeof %% all: program; program: program def optional_semi_colon | /* empty */ ; optional_semi_colon: /* empty */ | ';' { yyerror("Extra ';'. Ignored."); }; string_constant: low_string | string_constant '+' low_string { $$=add_shared_strings($1,$3); free_string($1); free_string($3); } ; optional_rename_inherit: ':' F_IDENTIFIER { $$=$2; } | { $$=0; } ; inheritance: modifiers F_INHERIT string_constant optional_rename_inherit ';' { simple_do_inherit($3,$1,$4); }; block_or_semi: block { $$ = mknode(F_ARG_LIST,$1,mknode(F_RETURN,mkintnode(0),0)); } | ';' { $$ = NULL;} ; type_or_error: simple_type { if(local_variables->current_type) free_string(local_variables->current_type); local_variables->current_type=$1; } | /* empty */ { yyerror("Missing type."); copy_shared_string(local_variables->current_type, mixed_type_string); } def: modifiers type_or_error optional_stars F_IDENTIFIER '(' arguments ')' { int e; /* construct the function type */ push_finished_type(local_variables->current_type); while($3--) push_type(T_ARRAY); if(local_variables->current_return_type) free_string(local_variables->current_return_type); local_variables->current_return_type=pop_type(); push_finished_type(local_variables->current_return_type); e=$6-1; if(varargs) { push_finished_type(local_variables->variable[e].type); e--; varargs=0; pop_type_stack(); }else{ push_type(T_VOID); } push_type(T_MANY); for(; e>=0; e--) { push_finished_type(local_variables->variable[e].type); if($1 & ID_VARARGS) { push_type(T_VOID); push_type(T_OR); } } push_type(T_FUNCTION); $<string>$=pop_type(); define_function($4, $<string>$, $1, IDENTIFIER_PIKE_FUNCTION, 0); } block_or_semi { int e; if($9) { union idptr tmp; int args, vargs; for(e=0; e<$6; e++) { if(!local_variables->variable[e].name || !local_variables->variable[e].name->len) { my_yyerror("Missing name for argument %d",e); } } tmp.offset=PC; args=count_arguments($<string>8); if(args < 0) { args=~args; vargs=IDENTIFIER_VARARGS; }else{ vargs=0; } ins_byte(local_variables->max_number_of_locals, A_PROGRAM); ins_byte(args, A_PROGRAM); dooptcode($4, $9, $6); define_function($4, $<string>8, $1, IDENTIFIER_PIKE_FUNCTION | vargs, &tmp); } if(local_variables->current_return_type) { free_string(local_variables->current_return_type); local_variables->current_return_type=0; } free_all_local_names(); free_string($4); free_string($<string>8); } | modifiers type_or_error name_list ';' {} | inheritance {} | error { reset_type_stack(); if(num_parse_error>5) YYACCEPT; } ; optional_dot_dot_dot: F_DOT_DOT_DOT { $$=1; } | /* empty */ { $$=0; } ; optional_identifier: F_IDENTIFIER | /* empty */ { $$=make_shared_string(""); } ; new_arg_name: type optional_dot_dot_dot optional_identifier { if(varargs) yyerror("Can't define more arguments after ..."); if($2) { push_type(T_ARRAY); varargs=1; } if(islocal($3) >= 0) my_yyerror("Variable '%s' appear twice in argument list.", $3->str); add_local_name($3, pop_type()); }; arguments: /* empty */ optional_comma { $$=0; } | arguments2 optional_comma { $$=$1; } ; arguments2: new_arg_name { $$ = 1; } | arguments2 ',' new_arg_name { $$ = $1 + 1; } ; modifier: F_NO_MASK { $$ = ID_NOMASK; } | F_STATIC { $$ = ID_STATIC; } | F_PRIVATE { $$ = ID_PRIVATE; } | F_PUBLIC { $$ = ID_PUBLIC; } | F_VARARGS { $$ = ID_VARARGS; } | F_PROTECTED { $$ = ID_PROTECTED; } | F_INLINE { $$ = ID_INLINE | ID_NOMASK; } ; modifiers: modifier_list { $$=current_modifiers=$1; } modifier_list: /* empty */ { $$ = 0; } | modifier modifier_list { $$ = $1 | $2; } ; optional_stars: optional_stars '*' { $$=$1 + 1; } | /* empty */ { $$=0; } ; cast: '(' type ')' { $$=pop_type(); } ; type: type '*' { push_type(T_ARRAY); } | type2 ; simple_type: type2 { $$=pop_type(); } type2: type2 '|' type3 { push_type(T_OR); } | type3 ; type3: F_INT_ID { push_type(T_INT); } | F_FLOAT_ID { push_type(T_FLOAT); } | F_STRING_ID { push_type(T_STRING); } | F_OBJECT_ID { push_type(T_OBJECT); } | F_PROGRAM_ID { push_type(T_PROGRAM); } | F_VOID_ID { push_type(T_VOID); } | F_MIXED_ID { push_type(T_MIXED); } | F_MAPPING_ID opt_mapping_type { push_type(T_MAPPING); } | F_ARRAY_ID opt_array_type { push_type(T_ARRAY); } | F_MULTISET_ID opt_array_type { push_type(T_MULTISET); } | F_FUNCTION_ID opt_function_type { push_type(T_FUNCTION); } ; opt_function_type: '(' { type_stack_mark(); type_stack_mark(); } function_type_list optional_dot_dot_dot ':' { if ($4) { push_type(T_MANY); type_stack_reverse(); }else{ type_stack_reverse(); push_type(T_MANY); push_type(T_VOID); } type_stack_mark(); } type ')' { type_stack_reverse(); type_stack_reverse(); } | { push_type(T_MIXED); push_type(T_MIXED); push_type(T_MANY); }; function_type_list: /* Empty */ optional_comma | function_type_list2 optional_comma ; function_type_list2: type | function_type_list2 ',' { type_stack_reverse(); type_stack_mark(); } type ; opt_array_type: '(' type ')' | { push_type(T_MIXED); } ; opt_mapping_type: '(' { type_stack_mark(); type_stack_mark(); } type ':' { type_stack_reverse(); type_stack_mark(); } type { type_stack_reverse(); type_stack_reverse(); } ')' | { push_type(T_MIXED); push_type(T_MIXED); } ; name_list: new_name | name_list ',' new_name; new_name: optional_stars F_IDENTIFIER { struct pike_string *type; push_finished_type(local_variables->current_type); while($1--) push_type(T_ARRAY); type=pop_type(); define_variable($2, type, current_modifiers); free_string(type); free_string($2); } | optional_stars F_IDENTIFIER '=' { struct pike_string *type; push_finished_type(local_variables->current_type); while($1--) push_type(T_ARRAY); type=pop_type(); $<number>$=define_variable($2, type, current_modifiers); free_string(type); } expr0 { init_node=mknode(F_ARG_LIST,init_node, mkcastnode(void_type_string, mknode(F_ASSIGN,$5,mkidentifiernode($<number>4)))); free_string($2); } ; new_local_name: optional_stars F_IDENTIFIER { push_finished_type(local_variables->current_type); while($1--) push_type(T_ARRAY); add_local_name($2, pop_type()); $$=mkcastnode(void_type_string, mknode(F_ASSIGN,mkintnode(0), mklocalnode(islocal($2)))); } | optional_stars F_IDENTIFIER '=' expr0 { push_finished_type(local_variables->current_type); while($1--) push_type(T_ARRAY); add_local_name($2, pop_type()); $$=mkcastnode(void_type_string, mknode(F_ASSIGN,$4, mklocalnode(islocal($2)))); }; block:'{' { $<number>$=local_variables->current_number_of_locals; } statements '}' { while(local_variables->current_number_of_locals > $<number>2) { int e; e=--(local_variables->current_number_of_locals); free_string(local_variables->variable[e].name); free_string(local_variables->variable[e].type); } $$=$3; } ; local_name_list: new_local_name | local_name_list ',' new_local_name { $$=mknode(F_ARG_LIST,$1,$3); } ; statements: { $$=0; } | statements statement { $$=mknode(F_ARG_LIST,$1,mkcastnode(void_type_string,$2)); } ; statement: unused2 ';' { $$=$1; } | simple_type { if(local_variables->current_type) free_string(local_variables->current_type); local_variables->current_type=$1; } local_name_list ';' { $$=$3; } | cond | while | do | for | switch | case | default | return ';' | block {} | foreach | break ';' | continue ';' | error ';' { $$=0; } | ';' { $$=0; } ; break: F_BREAK { $$=mknode(F_BREAK,0,0); } ; default: F_DEFAULT ':' { $$=mknode(F_DEFAULT,0,0); } ; continue: F_CONTINUE { $$=mknode(F_CONTINUE,0,0); } ; lambda: F_LAMBDA { push_locals(); $<number>$=comp_stackp; if(local_variables->current_return_type) free_string(local_variables->current_return_type); copy_shared_string(local_variables->current_return_type,any_type_string); } '(' arguments ')' block { struct pike_string *type; char buf[40]; int f,e,args,vargs; union idptr func; struct pike_string *name; setup_fake_program(); fix_comp_stack($<number>2); push_type(T_MIXED); e=$4-1; if(varargs) { push_finished_type(local_variables->variable[e].type); e--; varargs=0; pop_type_stack(); }else{ push_type(T_VOID); } push_type(T_MANY); for(; e>=0; e--) push_finished_type(local_variables->variable[e].type); push_type(T_FUNCTION); type=pop_type(); func.offset=PC; args=count_arguments(type); if(args < 0) { args=~args; vargs=IDENTIFIER_VARARGS; }else{ vargs=0; } ins_byte(local_variables->max_number_of_locals, A_PROGRAM); ins_byte(args, A_PROGRAM); sprintf(buf,"__lambda_%ld", (long)fake_program.num_identifier_references); name=make_shared_string(buf); dooptcode(name,mknode(F_ARG_LIST,$6,mknode(F_RETURN,mkintnode(0),0)),$4); f=define_function(name, type, 0, IDENTIFIER_PIKE_FUNCTION | vargs, &func); free_string(name); free_string(type); pop_locals(); $$=mkidentifiernode(f); } ; class: F_CLASS '{' { start_new_program(); } program '}' { struct svalue s; s.u.program=end_program(); if(!s.u.program) { yyerror("Class definition failed."); s.type=T_INT; s.subtype=0; } else { s.type=T_PROGRAM; s.subtype=0; } $$=mksvaluenode(&s); free_svalue(&s); } ; cond: F_IF '(' comma_expr ')' statement optional_else_part { $$=mknode('?',$3,mknode(':',$5,$6)); $$->line_number=$1; $$=mkcastnode(void_type_string,$$); $$->line_number=$1; } ; optional_else_part: { $$=0; } | F_ELSE statement { $$=$2; } ; foreach: F_FOREACH '(' expr0 ',' expr4 ')' statement { $$=mknode(F_FOREACH,mknode(F_VAL_LVAL,$3,$5),$7); $$->line_number=$1; } ; do: F_DO statement F_WHILE '(' comma_expr ')' ';' { $$=mknode(F_DO,$2,$5); $$->line_number=$1; } ; for: F_FOR '(' unused ';' for_expr ';' unused ')' statement { int i=current_line; current_line=$1; $$=mknode(F_ARG_LIST,mkcastnode(void_type_string,$3),mknode(F_FOR,$5,mknode(':',$9,$7))); current_line=i; } ; while: F_WHILE '(' comma_expr ')' statement { int i=current_line; current_line=$1; $$=mknode(F_FOR,$3,mknode(':',$5,NULL)); current_line=i; } ; for_expr: /* EMPTY */ { $$=mkintnode(1); } | comma_expr; switch: F_SWITCH '(' comma_expr ')' statement { $$=mknode(F_SWITCH,$3,$5); $$->line_number=$1; } ; case: F_CASE comma_expr ':' { $$=mknode(F_CASE,$2,0); } | F_CASE comma_expr F_DOT_DOT comma_expr ':' { $$=mknode(F_CASE,$2,$4); } ; return: F_RETURN { if(!match_types(local_variables->current_return_type, void_type_string)) { yyerror("Must return a value for a non-void function."); } $$=mknode(F_RETURN,mkintnode(0),0); } | F_RETURN comma_expr { $$=mknode(F_RETURN,$2,0); }; unused: { $$=0; } | unused2 ; unused2: comma_expr { $$=mkcastnode(void_type_string,$1); } ; comma_expr: expr0 | unused2 ',' expr0 { $$ = mknode(F_ARG_LIST,mkcastnode(void_type_string,$1),$3); } ; expr00: expr0 | '@' expr0 { $$=mknode(F_PUSH_ARRAY,$2,0); }; expr0: expr01 | expr4 '=' expr0 { $$=mknode(F_ASSIGN,$3,$1); } | expr4 assign expr0 { $$=mknode($2,$1,$3); } | error assign expr01 { $$=0; }; expr01: expr1 { $$ = $1; } | expr1 '?' expr01 ':' expr01 { $$=mknode('?',$1,mknode(':',$3,$5)); }; assign: F_AND_EQ { $$=F_AND_EQ; } | F_OR_EQ { $$=F_OR_EQ; } | F_XOR_EQ { $$=F_XOR_EQ; } | F_LSH_EQ { $$=F_LSH_EQ; } | F_RSH_EQ { $$=F_RSH_EQ; } | F_ADD_EQ { $$=F_ADD_EQ; } | F_SUB_EQ { $$=F_SUB_EQ; } | F_MULT_EQ{ $$=F_MULT_EQ; } | F_MOD_EQ { $$=F_MOD_EQ; } | F_DIV_EQ { $$=F_DIV_EQ; } ; optional_comma: | ',' ; expr_list: { $$=0; } | expr_list2 optional_comma { $$=$1; } ; expr_list2: expr00 | expr_list2 ',' expr00 { $$=mknode(F_ARG_LIST,$1,$3); } ; m_expr_list: { $$=0; } | m_expr_list2 optional_comma { $$=$1; } ; m_expr_list2: assoc_pair | m_expr_list2 ',' assoc_pair { $$=mknode(F_ARG_LIST,$1,$3); } ; assoc_pair: expr0 ':' expr1 { $$=mknode(F_ARG_LIST,$1,$3); } ; expr1: expr2 | expr1 F_LOR expr1 { $$=mknode(F_LOR,$1,$3); } | expr1 F_LAND expr1 { $$=mknode(F_LAND,$1,$3); } | expr1 '|' expr1 { $$=mkopernode("`|",$1,$3); } | expr1 '^' expr1 { $$=mkopernode("`^",$1,$3); } | expr1 '&' expr1 { $$=mkopernode("`&",$1,$3); } | expr1 F_EQ expr1 { $$=mkopernode("`==",$1,$3); } | expr1 F_NE expr1 { $$=mkopernode("`!=",$1,$3); } | expr1 '>' expr1 { $$=mkopernode("`>",$1,$3); } | expr1 F_GE expr1 { $$=mkopernode("`>=",$1,$3); } | expr1 '<' expr1 { $$=mkopernode("`<",$1,$3); } | expr1 F_LE expr1 { $$=mkopernode("`<=",$1,$3); } | expr1 F_LSH expr1 { $$=mkopernode("`<<",$1,$3); } | expr1 F_RSH expr1 { $$=mkopernode("`>>",$1,$3); } | expr1 '+' expr1 { $$=mkopernode("`+",$1,$3); } | expr1 '-' expr1 { $$=mkopernode("`-",$1,$3); } | expr1 '*' expr1 { $$=mkopernode("`*",$1,$3); } | expr1 '%' expr1 { $$=mkopernode("`%",$1,$3); } | expr1 '/' expr1 { $$=mkopernode("`/",$1,$3); } ; expr2: expr3 | cast expr2 { $$=mkcastnode($1,$2); free_string($1); } | F_INC expr4 { $$=mknode(F_INC,$2,0); } | F_DEC expr4 { $$=mknode(F_DEC,$2,0); } | F_NOT expr2 { $$=mkopernode("`!",$2,0); } | '~' expr2 { $$=mkopernode("`~",$2,0); } | '-' expr2 { $$=mkopernode("`-",$2,0); } ; expr3: expr4 | expr4 F_INC { $$=mknode(F_POST_INC,$1,0); } | expr4 F_DEC { $$=mknode(F_POST_DEC,$1,0); } ; expr4: string | F_NUMBER { $$=mkintnode($1); } | F_FLOAT { $$=mkfloatnode($1); } | catch | gauge | typeof | sscanf | lambda | class | F_IDENTIFIER { int i; struct efun *f; if((i=islocal($1))>=0) { $$=mklocalnode(i); }else if((i=isidentifier($1))>=0){ $$=mkidentifiernode(i); }else if((f=lookup_efun($1))){ $$=mkconstantsvaluenode(&f->function); }else{ my_yyerror("'%s' undefined.",$1->str); $$=0; } free_string($1); } | F_PREDEF F_COLON_COLON F_IDENTIFIER { struct efun *f; f=lookup_efun($3); if(!f) { my_yyerror("Unknown efun: %s.",$3->str); $$=mkintnode(0); }else{ $$=mksvaluenode(&f->function); } free_string($3); } | expr4 '(' expr_list ')' { $$=mkapplynode($1,$3); } | expr4 '[' expr0 ']' { $$=mknode(F_INDEX,$1,$3); } | expr4 '[' comma_expr_or_zero F_DOT_DOT comma_expr_or_maxint ']' { $$=mknode(F_RANGE,$1,mknode(F_ARG_LIST,$3,$5)); } | '(' comma_expr ')' { $$=$2; } | '(' '{' expr_list '}' ')' { $$=mkefuncallnode("aggregate",$3); } | '(' '[' m_expr_list ']' ')' { $$=mkefuncallnode("aggregate_mapping",$3); }; | F_MULTISET_START expr_list F_MULTISET_END { $$=mkefuncallnode("aggregate_multiset",$2); } | expr4 F_ARROW F_IDENTIFIER { $$=mknode(F_INDEX,$1,mkstrnode($3)); free_string($3); } | F_IDENTIFIER F_COLON_COLON F_IDENTIFIER { int f; struct reference *idp; setup_fake_program(); f=reference_inherited_identifier($1,$3); idp=fake_program.identifier_references+f; if (f<0 || ID_FROM_PTR(&fake_program,idp)->func.offset == -1) { my_yyerror("Undefined identifier %s::%s", $1->str,$3->str); $$=mkintnode(0); } else { $$=mkidentifiernode(f); } free_string($1); free_string($3); } | F_COLON_COLON F_IDENTIFIER { int e,i; $$=0; setup_fake_program(); for(e=1;e<(int)fake_program.num_inherits;e++) { if(fake_program.inherits[e].inherit_level!=1) continue; i=low_reference_inherited_identifier(e,$2); if(i==-1) continue; if($$) { $$=mknode(F_ARG_LIST,$$,mkidentifiernode(i)); }else{ $$=mkidentifiernode(i); } } if(!$$) { $$=mkintnode(0); }else{ if($$->token==F_ARG_LIST) $$=mkefuncallnode("aggregate",$$); } free_string($2); } ; comma_expr_or_zero: /* empty */ { $$=mkintnode(0); } | comma_expr ; comma_expr_or_maxint: /* empty */ { $$=mkintnode(0x7fffffff); } | comma_expr ; gauge: F_GAUGE catch_arg { $$=mkopernode("`-", mkopernode("`-", mknode(F_INDEX,mkefuncallnode("rusage",0), mkintnode(GAUGE_RUSAGE_INDEX)), mknode(F_ARG_LIST,$2, mknode(F_INDEX,mkefuncallnode("rusage",0), mkintnode(GAUGE_RUSAGE_INDEX)))),0); } ; typeof: F_TYPEOF '(' expr0 ')' { node *tmp; tmp=mknode(F_ARG_LIST,$3,0); $$=mkstrnode(describe_type($3->type)); free_node(tmp); } ; catch_arg: '(' comma_expr ')' { $$=$2; } | block ; catch: F_CATCH catch_arg { $$=mknode(F_CATCH,$2,NULL); } ; sscanf: F_SSCANF '(' expr0 ',' expr0 lvalue_list ')' { $$=mknode(F_SSCANF,mknode(F_ARG_LIST,$3,$5),$6); } lvalue_list: /* empty */ { $$ = 0; } | ',' expr4 lvalue_list { $$ = mknode(F_LVALUE_LIST,$2,$3); } ; low_string: F_STRING | low_string F_STRING { $$=add_shared_strings($1,$2); free_string($1); free_string($2); } ; string: low_string { $$=mkstrnode($1); free_string($1); } ; %% void yyerror(char *str) { extern int num_parse_error; if (num_parse_error > 5) return; num_parse_error++; if ( get_master() ) { sp->type = T_STRING; copy_shared_string(sp->u.string, current_file); sp++; sp->type = T_INT; sp->u.integer = current_line; sp++; sp->type = T_STRING; sp->u.string = make_shared_string(str); sp++; SAFE_APPLY_MASTER("compile_error",3); pop_stack(); }else{ (void)fprintf(stderr, "%s:%ld: %s\n", current_file->str, (long)current_line, str); fflush(stderr); } } /* argument must be a shared string (no need to free it) */ void add_local_name(struct pike_string *str, struct pike_string *type) { if (local_variables->current_number_of_locals == MAX_LOCAL) { yyerror("Too many local variables"); }else { local_variables->variable[local_variables->current_number_of_locals].type = type; local_variables->variable[local_variables->current_number_of_locals].name = str; local_variables->current_number_of_locals++; if(local_variables->current_number_of_locals > local_variables->max_number_of_locals) { local_variables->max_number_of_locals= local_variables->current_number_of_locals; } } } /* argument must be a shared string */ int islocal(struct pike_string *str) { int e; for(e=local_variables->current_number_of_locals-1;e>=0;e--) if(local_variables->variable[e].name==str) return e; return -1; } void free_all_local_names() { int e; for (e=0; e<local_variables->current_number_of_locals; e++) { if(local_variables->variable[e].name) { free_string(local_variables->variable[e].name); free_string(local_variables->variable[e].type); } local_variables->variable[e].name=0; local_variables->variable[e].type=0; } local_variables->current_number_of_locals = 0; local_variables->max_number_of_locals = 0; } static void push_locals() { struct locals *l; l=ALLOC_STRUCT(locals); l->current_type=0; l->current_return_type=0; l->next=local_variables; l->current_number_of_locals=0; l->max_number_of_locals=0; local_variables=l; } static void pop_locals() { struct locals *l; free_all_local_names(); l=local_variables->next; if(local_variables->current_type) free_string(local_variables->current_type); if(local_variables->current_return_type) free_string(local_variables->current_return_type); free((char *)local_variables); local_variables=l; /* insert check if ( local->next == parent locals ) here */ }