pike.git / src / language.y

version» Context lines:

pike.git/src/language.y:1: + %pure_parser    -  + /* +  * These values are used by the stack machine, and can not be directly +  * called from LPC. +  */ + %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_CALL_LFUN +  + %token F_BRANCH F_BRANCH_WHEN_ZERO F_BRANCH_WHEN_NON_ZERO + %token F_INC_LOOP F_DEC_LOOP + %token F_INC_NEQ_LOOP F_DEC_NEQ_LOOP +  + %token F_INDEX F_INDIRECT + %token F_LTOSVAL F_LTOSVAL2 + %token F_WRITE_OPCODE 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_CONSTANT F_FLOAT F_STRING + %token F_NUMBER F_NEG_NUMBER F_CONST_1 F_CONST0 F_CONST1 +  + /* +  * These are the predefined functions that can be accessed from LPC. +  */ +  + %token F_INC F_DEC F_POST_INC F_POST_DEC F_INC_AND_POP F_DEC_AND_POP + %token F_RETURN F_DUMB_RETURN F_RETURN_0 +  + %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 +  + /* +  * 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_CALL_OTHER + %token F_CASE + %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_EFUN + %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_LIST_ID + %token F_LIST_END + %token F_LIST_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_VAL_LVAL + %token F_VARARGS + %token F_VOID_ID + %token F_WHILE + %token F_XOR_EQ +  + %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 '+' '-' + %left '*' '%' '/' + %right F_NOT '~' + %nonassoc F_INC F_DEC +  +  + %{ + /* This is the grammar definition of LPC. */ +  + #include "global.h" + #ifdef HAVE_MEMORY_H + #include <memory.h> + #endif +  + #include <setjmp.h> + #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 "lpc_types.h" + #include "add_efun.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 lpc_string *,struct lpc_string *); +  + /* +  * The names and types of arguments and auto variables. +  */ + struct locals *local_variables; +  + static int varargs; + static struct lpc_string *current_type; + 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 lpc_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> type_or_error 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_EFUN 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_LIST_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 F_CALL_OTHER +  + /* The following symbos return type information */ +  + %type <n> string expr01 expr00 comma_expr + %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 call_other expr_list3 + %type <n> unused2 foreach unused switch case return expr_list default + %type <n> continue break block_or_semi + %% +  + 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(current_type) free_string(current_type); +  current_type=$1; +  } +  | /* empty */ +  { +  yyerror("Missing type."); +  copy_shared_string($$, mixed_type_string); +  } +  +  + def: modifiers type_or_error optional_stars F_IDENTIFIER '(' arguments ')' +  { +  int e; +  /* construct the function type */ +  push_finished_type(current_type); +  while($3--) push_type(T_ARRAY); +  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_LPC_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->current_number_of_locals, A_PROGRAM); +  ins_byte(args, A_PROGRAM); +  dooptcode($4, $9, $6); +  +  define_function($4, +  $<string>8, +  $1, +  IDENTIFIER_LPC_FUNCTION | vargs, +  &tmp); +  } +  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; } +  ; +  + 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_LIST_ID opt_array_type { push_type(T_LIST); } +  | F_FUNCTION_ID +  { +  push_type(T_TRUE); +  push_type(T_MIXED); +  push_type(T_MANY); +  push_type(T_FUNCTION); +  } +  ; +  + 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 lpc_string *type; +  push_finished_type(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 lpc_string *type; +  push_finished_type(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(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(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 '}' +  { +  int e; +  for(e=($<number>2)+1;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; +  } +  $$=$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(current_type) free_string(current_type); +  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; +  } +  '(' arguments ')' block +  { +  struct lpc_string *type; +  char buf[40]; +  int f,e,args,vargs; +  union idptr func; +  struct lpc_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->current_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_LPC_FUNCTION | vargs, +  &func); +  free_string(name); +  free_string(type); +  pop_locals(); +  $$=mkidentifiernode(f); +  } ; +  +  + 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 +  { +  $$=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 { $$=mknode(F_OR,$1,$3); } +  | expr1 '^' expr1 { $$=mknode(F_XOR,$1,$3); } +  | expr1 '&' expr1 { $$=mknode(F_AND,$1,$3); } +  | expr1 F_EQ expr1 { $$=mknode(F_EQ,$1,$3); } +  | expr1 F_NE expr1 { $$=mknode(F_NE,$1,$3); } +  | expr1 '>' expr1 { $$=mknode(F_GT,$1,$3); } +  | expr1 F_GE expr1 { $$=mknode(F_GE,$1,$3); } +  | expr1 '<' expr1 { $$=mknode(F_LT,$1,$3); } +  | expr1 F_LE expr1 { $$=mknode(F_LE,$1,$3); } +  | expr1 F_LSH expr1 { $$=mknode(F_LSH,$1,$3); } +  | expr1 F_RSH expr1 { $$=mknode(F_RSH,$1,$3); } +  | expr1 '+' expr1 { $$=mknode(F_ADD,$1,$3); } +  | expr1 '-' expr1 { $$=mknode(F_SUBTRACT,$1,$3); } +  | expr1 '*' expr1 { $$=mknode(F_MULTIPLY,$1,$3); } +  | expr1 '%' expr1 { $$=mknode(F_MOD,$1,$3); } +  | expr1 '/' expr1 { $$=mknode(F_DIVIDE,$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 { $$=mknode(F_NOT,$2,0); } +  | '~' expr2 { $$=mknode(F_COMPL,$2,0); } +  | '-' expr2 { $$=mknode(F_NEGATE,$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 +  | sscanf +  | call_other +  | lambda +  | 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))){ +  $$=mksvaluenode(&f->function); +  }else{ +  my_yyerror("'%s' undefined.",$1->str); +  $$=0; +  } +  free_string($1); +  } +  | F_EFUN 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 F_DOT_DOT comma_expr ']' +  { +  $$=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_LIST_START expr_list F_LIST_END +  { $$=mkefuncallnode("aggregate_list",$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); +  +  free_string($1); +  free_string($3); +  $$=mkidentifiernode(f); +  } +  | F_COLON_COLON F_IDENTIFIER +  { +  int e,i; +  +  $$=0; +  setup_fake_program(); +  for(e=1;e<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); +  } +  ; +  + expr_list3: { $$=0; } +  | ',' expr_list { $$=$2; } +  ; +  + call_other: F_CALL_OTHER '(' expr0 ',' expr0 expr_list3 ')' +  { +  $$=mkapplynode(mknode(F_INDEX, +  mkcastnode(object_type_string,$3), +  $5),$6); +  } +  + gauge: F_GAUGE '(' unused ')' +  { +  $$=mknode(F_NEGATE, +  mknode(F_SUBTRACT, +  mknode(F_INDEX,mkefuncallnode("rusage",0), +  mkintnode(GAUGE_RUSAGE_INDEX)), +  mknode(F_ARG_LIST,$3, +  mknode(F_INDEX,mkefuncallnode("rusage",0), +  mkintnode(GAUGE_RUSAGE_INDEX)))),0); +  } ; +  + catch: F_CATCH '(' unused ')' +  { +  $$=mknode(F_CATCH,$3,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,current_line,str); +  fflush(stderr); +  } + } +  + /* argument must be a shared string (no need to free it) */ + void add_local_name(struct lpc_string *str, +  struct lpc_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++; +  } + } +  + /* argument must be a shared string */ + int islocal(struct lpc_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; + } +  +  + #ifdef DEBUG + void dump_program_desc(struct program *p) + { +  int e,d,q; + /* fprintf(stderr,"Program '%s':\n",p->name->str); */ +  + /* +  fprintf(stderr,"All inherits:\n"); +  for(e=0;e<p->num_inherits;e++) +  { +  fprintf(stderr,"%3d:",e); +  for(d=0;d<p->inherits[e].inherit_level;d++) fprintf(stderr," "); +  fprintf(stderr,"%s\n",p->inherits[e].prog->name->str); +  } + */ +  +  fprintf(stderr,"All identifiers:\n"); +  for(e=0;e<p->num_identifier_references;e++) +  { +  fprintf(stderr,"%3d:",e); +  for(d=0;d<INHERIT_FROM_INT(p,e)->inherit_level;d++) fprintf(stderr," "); +  fprintf(stderr,"%s;\n",ID_FROM_INT(p,e)->name->str); +  } +  fprintf(stderr,"All sorted identifiers:\n"); +  for(q=0;q<p->num_identifier_indexes;q++) +  { +  e=p->identifier_index[q]; +  fprintf(stderr,"%3d (%3d):",e,q); +  for(d=0;d<INHERIT_FROM_INT(p,e)->inherit_level;d++) fprintf(stderr," "); +  fprintf(stderr,"%s;\n", ID_FROM_INT(p,e)->name->str); +  } + } + #endif +  +  + static void push_locals() + { +  struct locals *l; +  push_explicit((int)current_type); +  current_type=0; +  l=ALLOC_STRUCT(locals); +  l->next=local_variables; +  local_variables=l; +  local_variables->current_number_of_locals=0; + } +  + static void pop_locals() + { +  struct locals *l; +  free_all_local_names(); +  l=local_variables->next; +  free((char *)local_variables); +  +  local_variables=l; +  /* insert check if ( local->next == parent locals ) here */ +  if(current_type) free_string(current_type); +  current_type=(struct lpc_string *)pop_address(); + }   Newline at end of file added.