%{ %line /* The above line is to give proper line number references. Please mail me * if your compiler complains about it. */ /* * This is the grammar definition of LPC. The token table is built * automatically by make_func. The lang.y is constructed from this file and * the generated token list. The reason of this is that there is no * #include-statment that yacc recognizes. */ #include <stdio.h> #ifdef AMIGA #include <stdarg.h> #endif #define LANG #include "lint.h" #include "lex.h" #include "interpret.h" #include "object.h" #include "exec.h" #include "config.h" #include "instrs.h" #include "incralloc.h" #include "switch.h" #include "stralloc.h" #if defined(__GNUC__) && !defined(lint) && !defined(DEBUG) #define INLINE inline #else #define INLINE #endif #define YYMAXDEPTH 600 /* NUMPAREAS areas are saved with the program code after compilation. */ #define A_PROGRAM 0 #define A_STRINGS 1 #define A_VARIABLES 2 #define A_VIRTUAL_VAR 3 #define A_LINENUMBERS 4 #define A_INHERITS 5 #define A_ARGUMENT_TYPES 6 #define A_ARGUMENT_INDEX 7 #define NUMPAREAS 8 #define A_FUNCTIONS 8 %ifndef INITIALIZATION_BY___INIT #define A_VARIABLE_VALUES 9 #define A_VIRTUAL_VAR_VALUES 10 %endif /* INITIALIZATION_BY___INIT */ #define A_CASE_NUMBERS 11 #define A_CASE_STRINGS 12 #define A_CASE_LABELS 13 #define A_STRING_NEXT 14 #define A_INCLUDE_NAMES 15 #define NUMAREAS 16 #define CURRENT_PROGRAM_SIZE (mem_block[A_PROGRAM].current_size) #define BREAK_ON_STACK 0x40000 #define BREAK_FROM_SWITCH 0x80000 #define CASE_LABELS_ENABLED 0x100000 #define BREAK_DELIMITER -0x200000 #define CONTINUE_ADDRESS_MASK 0x3ffff #define SWITCH_DEPTH_UNIT 0x40000 #define SWITCH_DEPTH_MASK 0x3ffc0000 #define CONTINUE_DELIMITER -0x40000000 /* make sure that this struct has a size that is a power of two */ struct case_heap_entry { int key; short addr; short line; }; #define CASE_HEAP_ENTRY_ALIGN(offset) offset &= -sizeof(struct case_heap_entry) struct const_list { struct const_list *next; struct svalue val; }; struct const_list_svalue { struct svalue head; struct const_list list; }; static struct mem_block mem_block[NUMAREAS]; /* * Some good macros to have. */ #define BASIC_TYPE(e,t) ((e) == TYPE_ANY ||\ (e) == (t) ||\ (t) == TYPE_ANY) #define TYPE(e,t) (BASIC_TYPE((e) & TYPE_MOD_MASK, (t) & TYPE_MOD_MASK) ||\ (((e) & TYPE_MOD_POINTER) && ((t) & TYPE_MOD_POINTER) &&\ BASIC_TYPE((e) & (TYPE_MOD_MASK & ~TYPE_MOD_POINTER),\ (t) & (TYPE_MOD_MASK & ~TYPE_MOD_POINTER)))) #define MASKED_TYPE(e,t) (BASIC_TYPE( (e) , (t) ) ||\ ( (e) == (TYPE_MOD_POINTER|TYPE_ANY) && (t) & TYPE_MOD_POINTER ) ||\ ( (t) == (TYPE_MOD_POINTER|TYPE_ANY) && (e) & TYPE_MOD_POINTER ) ) #define VIRTUAL_VAR_TAG 0x4000 #define NON_VIRTUAL_OFFSET_TAG 0x4000 #define FUNCTION(n) ((struct function *)mem_block[A_FUNCTIONS].block + (n)) #define NV_VARIABLE(n) ((struct variable *)mem_block[A_VARIABLES].block + (n)) #define V_VARIABLE(n) ((struct variable *)mem_block[A_VIRTUAL_VAR].block + \ (n) - VIRTUAL_VAR_TAG) #define VARIABLE(n) ((n) & VIRTUAL_VAR_TAG ? V_VARIABLE(n) : NV_VARIABLE(n)) #define align(x) (((x) + (sizeof(char*)-1) ) & ~(sizeof(char*)-1) ) /* * If the type of the function is given, then strict types are * checked and required. */ static int exact_types; extern int pragma_strict_types; /* Maintained by lex.c */ extern int pragma_save_types; /* Also maintained by lex.c */ extern int pragma_combine_strings; /* Also maintained by lex.c */ int approved_object; /* How I hate all these global variables */ extern int total_num_prog_blocks, total_prog_block_size; extern int num_parse_error; extern int d_flag; static int heart_beat; /* Number of the heart beat function */ static int stored_bytes; /* used by store_line_number_info to */ static int stored_lines; /* keep track of the stored info */ static int last_include_start; static int num_virtual_variables; static int switch_pc; /* to ease relative addressing */ static int current_break_address; static int current_continue_address; static int current_case_number_heap; static int current_case_string_heap; #define SOME_NUMERIC_CASE_LABELS 0x40000 #define NO_STRING_CASE_LABELS 0x80000 static int zero_case_label; static int current_type; static int last_expression; static char *last_string_constant = 0; static struct program NULL_program; /* marion - clean neat empty struct */ static char *get_two_types PROT((int type1, int type2)); void add_local_name PROT((struct ident *, int)), smart_log PROT((char *, int, char *)); extern int yylex(); extern char *last_lex_string; static int verify_declared PROT((struct ident *)); %ifdef INITIALIZATION_BY___INIT static void copy_variables PROT((struct program *, int)); static int copy_functions PROT((struct program *, int type)); %else static void copy_variables PROT((struct program *, int, struct svalue *)); static void copy_functions PROT((struct program *, int type)); %endif void fix_function_inherit_indices PROT((struct program *)); void fix_variable_index_offsets PROT((struct program *)); static void type_error PROT((char *, int)); static void argument_type_error PROT((int, int)); extern int current_line; /* * 'inherit_file' is used as a flag. If it is set to a string * after yyparse(), this string should be loaded as an object, * and the original object must be loaded again. */ extern char *current_file, *inherit_file; /* * The names and types of arguments and auto variables. */ char *local_names[MAX_LOCAL]; unsigned short type_of_locals[MAX_LOCAL]; int current_number_of_locals = 0; int current_break_stack_need = 0 ,max_break_stack_need = 0; /* * The types of arguments when calling functions must be saved, * to be used afterwards for checking. And because function calls * can be done as an argument to a function calls, * a stack of argument types is needed. This stack does not need to * be freed between compilations, but will be reused. */ static struct mem_block type_of_arguments; struct program *compiled_prog; /* Is returned to the caller of yyparse */ %ifndef INITIALIZATION_BY___INIT struct svalue *prog_variable_values; /* this one too */ %endif /* INITIALIZATION_BY___INIT */ static struct ident *all_globals = 0; static struct ident *all_locals = 0; static struct efun_shadow *all_efun_shadows = 0; #if defined(AMIGA) void yyerrorf(char *format, ...) { va_list va; char buff[512]; va_start(va, format); vsprintf(buff, format, va); va_end(va); yyerror(buff); } #else /*VARARGS1*/ void yyerrorf(format, a1, a2, a3) char *format; int a1, a2, a3; { char buff[512]; sprintf(buff, format, a1, a2, a3); yyerror(buff); } #endif /* * Compare two types, and return true if they are compatible. */ static int compatible_types(t1, t2) int t1, t2; { if (t1 == TYPE_UNKNOWN || t2 == TYPE_UNKNOWN) return 0; if (t1 == t2) return 1; if (t1 == TYPE_ANY || t2 == TYPE_ANY) return 1; if ((t1 & TYPE_MOD_POINTER) && (t2 & TYPE_MOD_POINTER)) { if ((t1 & TYPE_MOD_MASK) == (TYPE_ANY|TYPE_MOD_POINTER) || (t2 & TYPE_MOD_MASK) == (TYPE_ANY|TYPE_MOD_POINTER)) return 1; } return 0; } /* * Add another argument type to the argument type stack */ INLINE static void add_arg_type(type) unsigned short type; { struct mem_block *mbp = &type_of_arguments; if (mbp->current_size + sizeof type > mbp->max_size) { mbp->max_size <<= 1; mbp->block = rexalloc((char *)mbp->block, mbp->max_size); } *(short*)(mbp->block + mbp->current_size) = type; mbp->current_size += sizeof type; } /* * Pop the argument type stack 'n' elements. */ INLINE static void pop_arg_stack(n) int n; { type_of_arguments.current_size -= sizeof (unsigned short) * n; } /* * Get type of argument number 'arg', where there are * 'n' arguments in total in this function call. Argument * 0 is the first argument. */ #if 0 /* not used */ INLINE static int get_argument_type(arg, n) int arg, n; { return ((unsigned short *) (type_of_arguments.block + type_of_arguments.current_size))[arg - n]; } #endif INLINE static unsigned short *get_argument_types_start(n) int n; { return &((unsigned short *) (type_of_arguments.block + type_of_arguments.current_size))[ - n]; } INLINE static void check_aggregate_types(n) int n; { unsigned short *argp, mask; argp = (unsigned short *) (type_of_arguments.block + (type_of_arguments.current_size -= sizeof (unsigned short) * n) ); for(mask = ~TYPE_MOD_REFERENCE; --n >= 0; ) { mask |= *argp++; } if (!(~mask & 0xffff)) yyerror("Can't trace reference assignments.\n"); } /* add_to_mem_block must not be called with length zero, because the length * is passed to memcpy . */ INLINE static void add_to_mem_block(n, data, size) int n, size; char *data; { struct mem_block *mbp = &mem_block[n]; while (mbp->current_size + size > mbp->max_size) { mbp->max_size <<= 1; mbp->block = rexalloc((char *)mbp->block, mbp->max_size); } memcpy(mbp->block + mbp->current_size, data, size); mbp->current_size += size; } static int realloc_mem_block(n) int n; { mem_block[n].max_size <<= 1; mem_block[n].block = rexalloc((char *)mem_block[n].block, mem_block[n].max_size); return 0; } static char *realloc_a_program() { char *p; mem_block[A_PROGRAM].max_size <<= 1; p = rexalloc((char *)mem_block[A_PROGRAM].block, mem_block[A_PROGRAM].max_size); if (p) mem_block[A_PROGRAM].block = p; return p; } #define byte_to_mem_block(n, b) ((void)(\ (mem_block[n].current_size == mem_block[n].max_size ?\ realloc_mem_block(n):0),\ mem_block[n].block[mem_block[n].current_size++] = (b) )) #define ins_byte(b) ((void)(\ (mem_block[A_PROGRAM].current_size == mem_block[A_PROGRAM].max_size ?\ realloc_a_program():0),\ mem_block[A_PROGRAM].block[mem_block[A_PROGRAM].current_size++] = (b) )) #ifndef ins_byte INLINE static void ins_byte(b) char b; { if (mem_block[A_PROGRAM].current_size == mem_block[A_PROGRAM].max_size ) { (void)realloc_a_program(); } mem_block[A_PROGRAM].block[mem_block[A_PROGRAM].current_size++] = b; } #endif /* * Store a 2 byte number. It is stored in such a way as to be sure * that correct byte order is used, regardless of machine architecture. * Also beware that some machines can't write a word to odd addresses. */ static void ins_short(l) short l; { int current_size; char *dest; current_size = CURRENT_PROGRAM_SIZE; CURRENT_PROGRAM_SIZE = current_size + 2; if (current_size +1 >= mem_block[A_PROGRAM].max_size ) (void)realloc_a_program(); dest = mem_block[A_PROGRAM].block + current_size; *dest++ = ((char *)&l)[0]; *dest = ((char *)&l)[1]; } static void upd_short(offset, l) int offset; short l; { char *dest; dest = mem_block[A_PROGRAM].block + offset; *dest++ = ((char *)&l)[0]; *dest = ((char *)&l)[1]; } static short read_short(offset) int offset; { short l[2]; char *dest; dest = mem_block[A_PROGRAM].block + offset; ((char *)l)[0] = *dest++; ((char *)l)[1] = *dest; return l[0]; } /* * Store a 4 byte number. It is stored in such a way as to be sure * that correct byte order is used, regardless of machine architecture. */ static void ins_long(l) int l; { int current_size; char *dest; current_size = CURRENT_PROGRAM_SIZE; CURRENT_PROGRAM_SIZE = current_size + 4; if (current_size +3 >= mem_block[A_PROGRAM].max_size ) (void)realloc_a_program(); dest = mem_block[A_PROGRAM].block + current_size; *dest++ = ((char *)&l)[0]; *dest++ = ((char *)&l)[1]; *dest++ = ((char *)&l)[2]; *dest = ((char *)&l)[3]; } #define ins_f_byte(b) (ins_byte((char)((b) - F_OFFSET))) #ifndef ins_f_byte static void ins_f_byte(b) unsigned int b; { ins_byte((char)(b - F_OFFSET)); } #endif #define ins_f_code(b) (_ins_f_code((b) - F_OFFSET)) #define PREPARE_INSERT(n) \ char *__PREPARE_INSERT__p = (\ (\ CURRENT_PROGRAM_SIZE+(n) > mem_block[A_PROGRAM].max_size ?\ realloc_a_program()\ :\ 0\ ),\ mem_block[A_PROGRAM].block + CURRENT_PROGRAM_SIZE); #define PREPARE_S_INSERT(n) \ short __ADD_SHORT__s[2];\ PREPARE_INSERT(n) #define add_byte(b) (void)(*__PREPARE_INSERT__p++ = (b)) #define add_short(s) \ {\ char *__ADD_SHORT__p = (char *)__ADD_SHORT__s;\ *((short*)__ADD_SHORT__p) = (s);\ *__PREPARE_INSERT__p++ = __ADD_SHORT__p[0];\ *__PREPARE_INSERT__p++ = __ADD_SHORT__p[1];\ } #define add_f_byte(b) (add_byte((char)((b) - F_OFFSET))) #define defined_function(s) \ ((s)->type == I_TYPE_GLOBAL ? (s)->u.global.function : -1) #if 0 /* * Return the index of the function found, otherwise -1. */ static int defined_function(s) char *s; { int offset; struct function *funp; for (offset = 0; offset < mem_block[A_FUNCTIONS].current_size; offset += sizeof (struct function)) { funp = (struct function *)&mem_block[A_FUNCTIONS].block[offset]; if (funp->flags & NAME_HIDDEN) continue; if (strcmp(funp->name, s) == 0) return offset / sizeof (struct function); } return -1; } #endif /* special allocate/free subroutines to be able to free intermediate results * that were thrown away due to an error. */ static char *last_yalloced = 0; static char *yalloc(size) unsigned long size; { char **p; p = (char **)xalloc(size+sizeof(char*)); *p++ = last_yalloced; last_yalloced = (char *)p; return (char *)p; } #if 1 || defined(DEBUG) static void yfree(block) char *block; { char **p; p = (char **)block; if (p != (char **)last_yalloced) { debug_message("Block mismatch"); return; } last_yalloced = *--p; xfree(p); } #else #define yfree(block) _yfree() static void _yfree() { char **p; p = (char **)last_yalloced; last_yalloced = *--p; xfree(p); } #endif /* * A mechanism to remember addresses on a stack. The size of the stack is * defined in config.h. */ static int comp_stackp; static int comp_stack[COMPILER_STACK_SIZE]; static void push_address() { if (comp_stackp >= COMPILER_STACK_SIZE) { yyerror("Compiler stack overflow"); comp_stackp++; return; } comp_stack[comp_stackp++] = mem_block[A_PROGRAM].current_size; } static void push_explicit(address) int address; { if (comp_stackp >= COMPILER_STACK_SIZE) { yyerror("Compiler stack overflow"); comp_stackp++; return; } comp_stack[comp_stackp++] = address; } static int pop_address() { if (comp_stackp == 0) fatal("Compiler stack underflow.\n"); if (comp_stackp > COMPILER_STACK_SIZE) { --comp_stackp; return 0; } return comp_stack[--comp_stackp]; } %ifdef INITIALIZATION_BY___INIT /* * If there is any initialization of a global variable, a function which will * execute the initialization code. This code is spread all over the program, * with jumps to next initializer. The next variable keeps track of * the previous jump. After the last initializer, the jump will be changed * into a return(0) statement instead. * * A function named '__INIT' will be defined, which will contain the * initialization code. If there was no initialization code, then the * function will not be defined. * * When inheriting from another object, a call will automatically be made * to call __INIT in that code from the current __INIT. */ static int last_initializer_end; static int first_initializer_start; /* * Arrange a jump to the current position for the initialization code * to continue. */ static void transfer_init_control() { if (last_initializer_end < 0) { char *name; PREPARE_INSERT(sizeof name + 3); name = make_shared_string("__INIT"); memcpy(__PREPARE_INSERT__p , (char *)&name, sizeof name); __PREPARE_INSERT__p += sizeof(name); add_byte(TYPE_ANY); add_byte(0); /* num_arg */ add_byte(0); /* num_local */ first_initializer_start = (CURRENT_PROGRAM_SIZE += sizeof name + 3) - 2; } else if (CURRENT_PROGRAM_SIZE - 2 == last_initializer_end) { mem_block[A_PROGRAM].current_size -= 3; } else { /* * Change the address of the last jump after the last * initializer to this point. */ upd_short(last_initializer_end, mem_block[A_PROGRAM].current_size); } } void add_new_init_jump(); %endif /* INITIALIZATION_BY___INIT */ static char prog_string_tags[32]; /* * Initialize the environment that the compiler needs. */ static void prolog() { int i; if (type_of_arguments.block == 0) { type_of_arguments.max_size = 100; type_of_arguments.block = xalloc(type_of_arguments.max_size); } type_of_arguments.current_size = 0; approved_object = 0; last_expression = -1; compiled_prog = 0; /* 0 means fail to load. */ heart_beat = -1; comp_stackp = 0; /* Local temp stack used by compiler */ current_continue_address = 0; current_break_address = 0; num_parse_error = 0; free_all_local_names(); /* In case of earlier error */ /* Initialize memory blocks where the result of the compilation * will be stored. */ for (i=0; i < NUMAREAS; i++) { mem_block[i].block = xalloc(START_BLOCK_SIZE); mem_block[i].current_size = 0; mem_block[i].max_size = START_BLOCK_SIZE; } stored_lines = 0; stored_bytes = 0; last_include_start = -1; bzero(prog_string_tags, sizeof prog_string_tags); num_virtual_variables = 0; %ifdef INITIALIZATION_BY___INIT last_initializer_end = -3; %endif } static int insert_inherited PROT((char *,char *, struct program **, struct function *, int, char *)); /* * The program has been compiled. Prepare a 'struct program' to be returned. */ int32 current_id_number = 0; static int define_new_function PROT(( struct ident *, int,int,int,int,int)); /* * Define a new function. Note that this function is called at least twice * for all function definitions. First as a prototype, then as the real * function. Thus, there are tests to avoid generating error messages more * than once by looking at (flags & NAME_PROTOTYPE). */ static int define_new_function(p, num_arg, num_local, offset, flags, type) struct ident *p; int num_arg, num_local; int offset, flags, type; { int num; struct function fun; unsigned short argument_start_index; flags |= type & ~TYPE_MOD_MASK; if (p->type == I_TYPE_GLOBAL && (num = p->u.global.function) >= 0) { struct function *funp; /* * The function was already defined. It may be one of several reasons: * * 1. There has been a prototype. * 2. There was the same function defined by inheritance. * 3. This function has been called, but not yet defined. * 4. The function is defined twice. * 5. A "late" prototype has been encountered. */ funp = FUNCTION(num); if (funp->flags & TYPE_MOD_NO_MASK && !((funp->flags|flags) & (NAME_PROTOTYPE|NAME_UNDEFINED)) ) yyerrorf("Illegal to redefine 'nomask' function \"%s\"", p->name); if (!(funp->flags & (NAME_UNDEFINED|NAME_PROTOTYPE|NAME_INHERITED) ) ) { yyerrorf("Redeclaration of function %s.", p->name); if ( !(flags & NAME_PROTOTYPE) ) free_string(p->name); return num; } /* * It was either an undefined but used funtion, or an inherited * function. In both cases, we now consider this to be THE new * definition. It might also have been a prototype to an already * defined function. * * Check arguments only when types are supposed to be tested, * and if this function really has been defined already. * * 'nomask' functions may not be redefined. */ if (exact_types && funp->type != TYPE_UNKNOWN) { int i; if (funp->num_arg != num_arg && !(funp->flags & TYPE_MOD_VARARGS)) yyerror("Incorrect number of arguments."); else { unsigned short first_arg; first_arg = ((unsigned short *)mem_block[A_ARGUMENT_INDEX].block)[num]; if (first_arg == INDEX_START_NONE) { if (num_arg && !(funp->flags & NAME_TYPES_LOST) ) yyerror( "Called function not compiled with type testing." ); } else { /* Now check that argument types weren't changed. */ for (i=0; i < num_arg; i++) { } } } } /* If it was yet another prototype, then simply return. */ if (flags & NAME_PROTOTYPE) { return num; } funp->num_arg = num_arg; funp->num_local = num_local; funp->flags = flags; funp->offset.pc = offset; #if 0 funp->function_index_offset = 0; #endif funp->type = type; return num; } if (strcmp(p->name, "heart_beat") == 0) heart_beat = mem_block[A_FUNCTIONS].current_size / sizeof (struct function); fun.name = p->name; fun.offset.pc = offset; fun.flags = flags; fun.num_arg = num_arg; fun.num_local = num_local; #if 0 fun.function_index_offset = 0; #endif fun.type = type; num = mem_block[A_FUNCTIONS].current_size / sizeof fun; if (p->type != I_TYPE_GLOBAL) { if (p->type != I_TYPE_UNKNOWN) { p = make_shared_identifier(p->name, I_TYPE_GLOBAL); } /* should be I_TYPE_UNKNOWN now. */ p->type = I_TYPE_GLOBAL; p->u.global.variable = -1; p->u.global.efun = -1; p->u.global.sim_efun = -1; p->next_all = all_globals; all_globals = p; } else if (p->u.global.variable == -2) { struct efun_shadow *q; #if 0 fprintf(stderr,"define efun shadow function '%s'\n",p->name); #endif q = (struct efun_shadow *)xalloc(sizeof(struct efun_shadow)); q->shadow = p; #if 0 fprintf(stderr,"all_efun_shadows: %x\n",all_efun_shadows); if (all_efun_shadows) { fprintf(stderr,"last shadow pnt: %x\n",all_efun_shadows->shadow); fprintf(stderr,"last name: '%s'\n",all_efun_shadows->shadow->name); } #endif q->next = all_efun_shadows; all_efun_shadows = q; } p->u.global.function = num; /* Number of local variables will be updated later */ add_to_mem_block(A_FUNCTIONS, (char *)&fun, sizeof fun); if (exact_types == 0) { argument_start_index = INDEX_START_NONE; } else { int i; /* * Save the start of argument types. */ argument_start_index = mem_block[A_ARGUMENT_TYPES].current_size / sizeof (unsigned short); for (i=0; i < num_arg; i++) { add_to_mem_block(A_ARGUMENT_TYPES, &type_of_locals[i], sizeof type_of_locals[i]); } } add_to_mem_block(A_ARGUMENT_INDEX, &argument_start_index, sizeof argument_start_index); return num; } %ifdef INITIALIZATION_BY___INIT static void define_variable(name, flags) struct ident *name; int32 flags; %else /* INITIALIZATION_BY___INIT */ static void define_variable(name, flags, svp) struct ident *name; int32 flags; struct svalue *svp; %endif /* INITIALIZATION_BY___INIT */ { struct variable dummy; int n; if (name->type != I_TYPE_GLOBAL) { if (name->type != I_TYPE_UNKNOWN) { name = make_shared_identifier(name->name, I_TYPE_GLOBAL); } name->type = I_TYPE_GLOBAL; name->u.global.function = -1; name->u.global.variable = -1; name->u.global.efun = -1; name->u.global.sim_efun = -1; name->next_all = all_globals; all_globals = name; } else if (name->u.global.function == -2) { struct efun_shadow *q; q = (struct efun_shadow *)xalloc(sizeof(struct efun_shadow)); q->shadow = name; q->next = all_efun_shadows; all_efun_shadows = q; } if ( (n = name->u.global.variable) >= 0) { if ( VARIABLE(n)->flags & TYPE_MOD_NO_MASK && !(flags & NAME_HIDDEN)) yyerrorf("Illegal to redefine 'nomask' variable \"%s\"", name->name); if (flags & NAME_INHERITED) { flags |= ~(VARIABLE(n)->flags) & TYPE_MOD_STATIC; } else { VARIABLE(n)->flags |= ~flags & TYPE_MOD_STATIC; } } dummy.name = name->name; increment_string_ref(dummy.name); dummy.flags = flags; if (flags & TYPE_MOD_VIRTUAL) { if (!(flags & NAME_HIDDEN)) name->u.global.variable = VIRTUAL_VAR_TAG | (mem_block[A_VIRTUAL_VAR].current_size / sizeof dummy); add_to_mem_block(A_VIRTUAL_VAR, (char *)&dummy, sizeof dummy); %ifndef INITIALIZATION_BY___INIT add_to_mem_block(A_VIRTUAL_VAR_VALUES, (char*)svp, sizeof *svp); %endif /* INITIALIZATION_BY___INIT */ } else { if (!(flags & NAME_HIDDEN)) name->u.global.variable = mem_block[A_VARIABLES].current_size / sizeof dummy; add_to_mem_block(A_VARIABLES, (char *)&dummy, sizeof dummy); %ifndef INITIALIZATION_BY___INIT add_to_mem_block(A_VARIABLE_VALUES, (char*)svp, sizeof *svp); %endif /* INITIALIZATION_BY___INIT */ } } static void redeclare_variable(name, flags, n) struct ident *name; int32 flags; int n; { if (name->type != I_TYPE_GLOBAL) { /* I_TYPE_UNKNOWN */ name->type = I_TYPE_GLOBAL; name->u.global.function = -1; name->u.global.variable = -1; name->u.global.efun = -1; name->u.global.sim_efun = -1; name->next_all = all_globals; all_globals = name; } else if (name->u.global.function == -2) { struct efun_shadow *q; q = (struct efun_shadow *)xalloc(sizeof(struct efun_shadow)); q->shadow = name; q->next = all_efun_shadows; all_efun_shadows = q; } if (flags & NAME_HIDDEN) return; if (name->u.global.variable >= 0 && name->u.global.variable != n) { if (VARIABLE(name->u.global.variable)->flags & TYPE_MOD_NO_MASK ) yyerrorf("Illegal to redefine 'nomask' variable \"%s\"", name->name); } else if ( V_VARIABLE(n)->flags & TYPE_MOD_NO_MASK && !(V_VARIABLE(n)->flags & NAME_HIDDEN) && (V_VARIABLE(n)->flags ^ flags) & TYPE_MOD_STATIC ) { yyerrorf("Illegal to redefine 'nomask' variable \"%s\"", name->name); } name->u.global.variable = n; V_VARIABLE(n)->flags = flags; } static int last_string_is_new; static int prog_string_indizes[0x100]; short store_prog_string(str) char *str; { int size; long hash; char mask, *tagp; int i, *indexp; hash = (long)str ^ (long)str >> 16; hash = (hash ^ hash >> 8); mask = 1 << (hash & 7); hash = hash & 0xff; indexp = &prog_string_indizes[hash]; tagp = &prog_string_tags[hash >> 3]; if (*tagp & mask) { i = *indexp; for(;;) { if ( ((char**)(mem_block[A_STRINGS].block))[i] == str ) { free_string(str); /* Needed as string is only free'ed once. */ last_string_is_new = 0; return i; } if ( (i=*((int*)(&((char**)(mem_block[A_STRING_NEXT].block))[i]))) < 0 ) break; } i = *indexp; } else { *tagp |= mask; i = -1; } size = mem_block[A_STRINGS].current_size; if (size + sizeof(char *) > mem_block[A_STRINGS].max_size) { realloc_mem_block(A_STRINGS); realloc_mem_block(A_STRING_NEXT); } mem_block[A_STRING_NEXT].current_size = mem_block[A_STRINGS].current_size = size + sizeof str; *((char **)(mem_block[A_STRINGS].block+size)) = str; *((int *)(mem_block[A_STRING_NEXT].block+size)) = i; last_string_is_new = 1; return *indexp = size / sizeof str; } void delete_prog_string() { char *str; int size; long hash; char mask, *tagp; int *indexp; size = mem_block[A_STRINGS].current_size - sizeof(char *); free_string( str = *(char**)(mem_block[A_STRINGS].block+size) ); mem_block[A_STRING_NEXT].current_size = mem_block[A_STRINGS].current_size = size; hash = (long)str ^ (long)str >> 16; hash = (hash ^ hash >> 8); mask = 1 << (hash & 7); hash = hash & 0xff; indexp = &prog_string_indizes[hash]; tagp = &prog_string_tags[hash >> 3]; if ( ( *indexp = *((int *)(mem_block[A_STRING_NEXT].block+size)) ) < 0) *tagp &= ~mask; } void add_to_case_heap(block_index,entry) int block_index; struct case_heap_entry *entry; { char *heap_start; int offset,parent; int current_heap; if ( block_index == A_CASE_NUMBERS ) current_heap = current_case_number_heap; else current_heap = current_case_string_heap; offset = mem_block[block_index].current_size - current_heap; add_to_mem_block(block_index, (char*)entry, sizeof(*entry) ); heap_start = mem_block[block_index].block + current_heap; for ( ; offset; offset = parent ) { parent = ( offset - sizeof(struct case_heap_entry) ) >> 1 ; CASE_HEAP_ENTRY_ALIGN(parent); if ( ((struct case_heap_entry*)(heap_start+offset))->key < ((struct case_heap_entry*)(heap_start+parent))->key ) { *(struct case_heap_entry*)(heap_start+offset) = *(struct case_heap_entry*)(heap_start+parent); *(struct case_heap_entry*)(heap_start+parent) = *entry; } } } %ifndef INITIALIZATION_BY___INIT /* convert an svalue how mt is used at run-time to it's compile-time type */ INLINE static int type_rtoc(svp) struct svalue *svp; { switch (svp->type) { case T_NUMBER: if (!svp->u.number) return TYPE_ANY; return TYPE_NUMBER; case T_STRING: return TYPE_STRING; case T_POINTER: return TYPE_MOD_POINTER | TYPE_ANY; case T_FLOAT: return TYPE_FLOAT; case T_CLOSURE: return TYPE_CLOSURE; case T_SYMBOL: return TYPE_SYMBOL; case T_QUOTED_ARRAY: return TYPE_QUOTED_ARRAY; case T_MAPPING: return TYPE_MAPPING; default: fatal("Bad svalue type at compile time.\n"); return TYPE_ANY; /* gag the compiler warning ... */ } } INLINE static struct svalue *copy_svalue(svp) struct svalue *svp; { extern struct svalue const0; switch (svp->type) { case T_NUMBER: case T_FLOAT: break; case T_STRING: if (svp->x.string_type != STRING_SHARED) return &const0; increment_string_ref(svp->u.string); break; case T_POINTER: svp->u.vec->ref++; break; case T_MAPPING: svp->u.map->ref++; break; default: return &const0; } return svp; } %endif /* INITIALIZATION_BY___INIT */ static void insert_pop_value(); #define FIX_BRANCH(lfcode, destination, location) fix_branch(\ (lfcode)-F_OFFSET, destination, location) int fix_branch(ltoken, dest, loc) int ltoken, dest, loc; { int offset; offset = dest - (loc +1); if (offset > 0xff) { int i,j; char *p; #ifdef DEBUG if (d_flag > 2) { debug_message("fix_branch handles long offset.\n"); } #endif if ( current_break_address > loc && !(current_break_address & (BREAK_ON_STACK|BREAK_DELIMITER) ) ) { for(i = current_break_address; (j=read_short(i)) > loc; ) { upd_short(i, j+1); i = j; } current_break_address++; } if ( (current_continue_address & CONTINUE_ADDRESS_MASK) > loc && !(current_continue_address & CONTINUE_DELIMITER ) ) { for(i = current_continue_address & CONTINUE_ADDRESS_MASK; (j=read_short(i)) > loc; ) { upd_short(i, j+1); i = j; } current_continue_address++; } ins_byte(0); p = mem_block[A_PROGRAM].block + mem_block[A_PROGRAM].current_size-1; i = mem_block[A_PROGRAM].current_size - loc; for( ; --i >= 0; --p ) *p = p[-1]; *p = ltoken; upd_short(loc, offset+2); if (offset > 0x7ffd) yyerror("offset overflow"); return 1; } else { mem_block[A_PROGRAM].block[loc] = offset; return 0; } } static char *ystring_copy(str) char *str; { char *p; p = yalloc(strlen(str)+1); (void)strcpy(p, str); return p; } static void add_string_constant() { mp_int len1; char *tmp; len1 = strlen(last_string_constant); tmp = alloca(len1 + strlen(last_lex_string) + 1); strcpy(tmp, last_string_constant); strcpy(tmp + len1, last_lex_string); free_string(last_string_constant); free_string(last_lex_string); last_string_constant = make_shared_string(tmp); last_lex_string = 0; } %ifndef INITIALIZATION_BY___INIT static struct vector *list_to_vector(length, initialized) int length; struct svalue *initialized; { struct const_list *list; struct vector *vec; struct svalue *svp; char *block; struct const_list_svalue *clsv; %line vec = allocate_array(length); if (length) { svp = initialized->u.lvalue; clsv = initialized->u.const_list; list = &clsv->list; block = (char *)clsv; svp = vec->item; do { *svp++ = list->val; list = list->next; xfree(block); } while (block = (char *)list); } initialized->type = T_POINTER; initialized->u.vec = vec; return vec; } static void free_const_list_svalue(svp) struct svalue *svp; { struct const_list *list; char *block; %line list = &((struct const_list_svalue *)svp)->list; block = (char *)svp; do { free_svalue(&list->val); list = list->next; xfree(block); } while (block = (char *)list); } %endif INLINE int proxy_efun PROT((int, int)); static void arrange_protected_lvalue PROT((int, int, int, int)); struct s_lrvalue { short type; unsigned short start; short code; unsigned short end; }; static struct s_lrvalue indexing_argument, indexing_index1, indexing_index2; static int indexing_code; static struct svalue *currently_initialized; %} %efuns /* Include the tokens */ %union { %line p_int number; p_uint address; /* Address of an instruction */ char *string; char *shared_string; short type; struct { p_int key; char block; } case_label; struct { int simul_efun; short start; } function_call_head; struct svalue svalue; %if 0 struct vector *array; %endif struct svalue *initialized; struct { int function; struct svalue *initialized; } const_call_head; p_int numbers[2]; struct { p_int length; struct const_list * l; } const_list; struct { char *p; unsigned short length; unsigned short line; } expression; struct { union { char *p, simple[2]; } u; unsigned short length; short type; } lvalue; struct { char *super; struct ident *real; } function_name; struct ident *ident; double float_number; struct { int type; p_int number; } closure; struct { char *name; int quotes; } symbol; struct s_lrvalue lrvalue; } %type <number> F_ASSIGN F_NUMBER constant F_LOCAL expr_list expr_list3 %type <number> lvalue_list argument type basic_type optional_star expr_list2 %type <float_number> F_FLOAT %type <closure> F_CLOSURE %type <symbol> F_SYMBOL %type <number> F_QUOTED_AGGREGATE %ifndef INITIALIZATION_BY___INIT %type <svalue> float_constant %type <const_list> const_expr_list const_expr_list2 const_expr_list3 %endif /* INITIALIZATION_BY___INIT */ %type <number> inheritance_modifier inheritance_modifier_list %type <numbers> inheritance_qualifier inheritance_qualifiers %type <number> type_modifier type_modifier_list opt_basic_type function_body %type <number> argument_list optional_else pre_inc_dec %ifdef MAPPINGS %type <numbers> m_expr_list m_expr_list2 %type <number> m_expr_values %endif %type <numbers> condStart %type <ident> F_IDENTIFIER %type <function_name> function_name %type <string> anchestor %type <case_label> case_label /* The following symbols return type information */ %type <type> decl_cast cast %type <lvalue> lvalue %type <lrvalue> function_call expr4 %type <lrvalue> catch sscanf parse_command %type <lrvalue> expr0 comma_expr %type <lrvalue> note_start %right F_ASSIGN %right '?' %left F_LOR %left F_LAND %left '|' %left '^' %left '&' %left F_EQ F_NE %left '<' F_LE '>' F_GE %left F_LSH F_RSH %left '+' '-' %left '*' '/' '%' %right '~' F_NOT %nonassoc F_INC F_DEC %left F_ARROW '[' %% all: program; program: program def possible_semi_colon | /* empty */ ; possible_semi_colon: /* empty */ | ';' { yyerror("Extra ';'. Ignored."); }; inheritance: inheritance_qualifiers F_INHERIT string_constant ';' { %line /* copy_variables might add extra inherits for virtual inheritance. * For this reason, copy_functions() can't know the actual index * of the new inherit, so it sets it to NEW_INHERITED_INDEX instead. * This is changed later to the actual value by * fix_function_inherit_indices() . */ struct object *ob; struct inherit inherit; %ifdef INITIALIZATION_BY___INIT int initializer; %endif /* INITIALIZATION_BY___INIT */ if (CURRENT_PROGRAM_SIZE) %ifdef INITIALIZATION_BY___INIT if (!(((struct function *)(mem_block[A_FUNCTIONS].block+ mem_block[A_FUNCTIONS].current_size))[-1].flags & NAME_INHERITED)) %endif /* INITIALIZATION_BY___INIT */ yyerror( "illegal to inherit after defining functions\n" ); ob = find_object2(last_string_constant); if (ob == 0) { inherit_file = last_string_constant; last_string_constant = 0; /* Return back to load_object() */ YYACCEPT; } free_string(last_string_constant); last_string_constant = 0; if (ob->flags & O_APPROVED) approved_object = 1; inherit.prog = ob->prog; inherit.function_index_offset = mem_block[A_FUNCTIONS].current_size / sizeof(struct function); %ifdef INITIALIZATION_BY___INIT initializer = copy_functions(ob->prog, $1[0]); if (initializer > 0) { transfer_init_control(); ins_f_byte(F_CALL_EXPLICIT_INHERITED); ins_short(mem_block[A_INHERITS].current_size / sizeof inherit); ins_short(initializer); ins_byte(0); /* Actual number of arguments */ ins_f_byte(F_POP_VALUE); add_new_init_jump(); } copy_variables(ob->prog, $1[1]); %else /* INITIALIZATION_BY___INIT */ copy_functions(ob->prog, $1[0]); copy_variables(ob->prog, $1[1], ob->variables); %endif /* INITIALIZATION_BY___INIT */ fix_function_inherit_indices(ob->prog); inherit.variable_index_offset = $1[1] & TYPE_MOD_VIRTUAL ? mem_block[A_VIRTUAL_VAR].current_size / sizeof(struct variable) - ob->prog->num_variables : mem_block[A_VARIABLES].current_size / sizeof(struct variable) - ob->prog->num_variables | NON_VIRTUAL_OFFSET_TAG; add_to_mem_block(A_INHERITS, &inherit, sizeof inherit); num_virtual_variables = mem_block[A_VIRTUAL_VAR].current_size / sizeof (struct variable); } optional_star: /* empty */ { $$ = 0; } | '*' { $$ = TYPE_MOD_POINTER; } ; function_body: { $<number>$ = CURRENT_PROGRAM_SIZE; if ( (CURRENT_PROGRAM_SIZE += sizeof(char *) + 3) > mem_block[A_PROGRAM].max_size ) { (void)realloc_a_program(); } } block %ifdef YACC_CANNOT_MIX_ANONYMOUS_WITH_DEFAULT { $$ = $<number>1; } %endif | ';' { $$ = -1; } ; def: type optional_star F_IDENTIFIER { $2 |= $1; if ($1 & TYPE_MOD_MASK) { exact_types = $2; } else { if (pragma_strict_types) yyerror("\"#pragma strict_types\" requires type of function"); exact_types = 0; } if ($3->type == I_TYPE_UNKNOWN) { /* prevent freeing by exotic name clashes */ struct ident *p = $3; p->type = I_TYPE_GLOBAL; p->u.global.variable = -1; p->u.global.efun = -1; p->u.global.sim_efun = -1; p->u.global.function = -1; p->next_all = all_globals; all_globals = p; } } '(' argument ')' { /* * Define a prototype. If it is a real function, then the * prototype will be replaced below. */ define_new_function($3, $6, 0, 0, NAME_UNDEFINED|NAME_PROTOTYPE, $2); } function_body { int start; char *p; %line if ( (start = $9) < 0) { /* function_body was a ';' ==> prototype */ uint32 *flagp; flagp = &FUNCTION($3->u.global.function)->flags; *flagp |= $1 & (*flagp & TYPE_MOD_PUBLIC ? (TYPE_MOD_NO_MASK|TYPE_MOD_STATIC) : (TYPE_MOD_NO_MASK|TYPE_MOD_PRIVATE|TYPE_MOD_STATIC) ); } else { /* function_body was a block */ p = &mem_block[A_PROGRAM].block[start]; memcpy(p, (char *)&$3->name, sizeof $3->name); p += sizeof $3->name; *p++ = $2; *p++ = $6; *p = current_number_of_locals - $6+ ( max_break_stack_need +sizeof(struct svalue)-1 ) / sizeof(struct svalue); define_new_function($3, $6, current_number_of_locals - $6+ ( max_break_stack_need +sizeof(struct svalue)-1 ) / sizeof(struct svalue), start + sizeof $3->name + 1, 0, $2); increment_string_ref($3->name); ins_f_byte(F_RETURN0); } free_all_local_names(); } | type name_list ';' { if ($1 == 0) yyerror("Missing type"); } | inheritance ; new_arg_name: type optional_star F_IDENTIFIER { if (exact_types && $1 == 0) { yyerror("Missing type for argument"); add_local_name($3, TYPE_ANY); /* Supress more errors */ } else { add_local_name($3, $1 | $2); } } | type optional_star F_LOCAL { yyerror("Illegal to redeclare local name"); } ; argument: /* empty */ { $$ = 0; } | argument_list ; argument_list: new_arg_name { $$ = 1; } | argument_list ',' new_arg_name { $$ = $1 + 1; } ; type_modifier: F_NO_MASK { $$ = TYPE_MOD_NO_MASK; } | F_STATIC { $$ = TYPE_MOD_STATIC; } | F_PRIVATE { $$ = TYPE_MOD_PRIVATE; } | F_PUBLIC { $$ = TYPE_MOD_PUBLIC; } | F_VARARGS { $$ = TYPE_MOD_VARARGS; } | F_PROTECTED { $$ = TYPE_MOD_PROTECTED; } ; inheritance_modifier: F_VIRTUAL { $$ = TYPE_MOD_VIRTUAL; } ; type_modifier_list: /* empty */ { $$ = 0; } | type_modifier type_modifier_list { $$ = $1 | $2; } ; inheritance_modifier_list: type_modifier_list | type_modifier_list inheritance_modifier inheritance_modifier_list { $$ = $1 | $2 | $3; } ; inheritance_qualifier: type optional_star F_IDENTIFIER { static struct ident *last_identifier; static uint32 last_modifier; %line if ($1 & TYPE_MOD_MASK) { yyerror("syntax error"); } if ( !($1 & ~TYPE_MOD_MASK) ) { /* take lookahead into account */ if ($3 == last_identifier) { last_identifier = 0; break; } } else { last_modifier = $1 & ~TYPE_MOD_MASK; } last_identifier = $3; if ($2) { yyerror("syntax error"); } if (strcmp(last_identifier->name, "functions") == 0) { $$[0] = last_modifier; $$[1] = 0; } else if (strcmp(last_identifier->name, "variables") == 0) { $$[0] = 0; $$[1] = last_modifier; } else { yyerror("Unrecognized inheritance modifier qualifier"); $$[0] = $$[1] = 0; } if (last_identifier->type == I_TYPE_UNKNOWN) free_shared_identifier(last_identifier); } ; inheritance_qualifiers: inheritance_modifier_list { $$[0] = $$[1] = $1; } | inheritance_qualifier inheritance_qualifiers { $$[0] = $1[0] | $2[0]; $$[1] = $1[1] | $2[1]; } ; type: type_modifier_list opt_basic_type { $$ = $1 | $2; current_type = $$; } ; cast: '(' basic_type optional_star ')' { $$ = $2 | $3; } ; decl_cast: '(' '{' basic_type optional_star '}' ')' { $$ = $3 | $4; } ; opt_basic_type: basic_type | /* empty */ { $$ = TYPE_UNKNOWN; } ; basic_type: F_STATUS { $$ = TYPE_NUMBER; current_type = $$; } | F_INT { $$ = TYPE_NUMBER; current_type = $$; } | F_STRING_DECL { $$ = TYPE_STRING; current_type = $$; } | F_OBJECT { $$ = TYPE_OBJECT; current_type = $$; } | F_CLOSURE_DECL { $$ = TYPE_CLOSURE; current_type = $$; } | F_SYMBOL_DECL { $$ = TYPE_SYMBOL; current_type = $$; } %ifdef FLOATS | F_FLOAT_DECL { $$ = TYPE_FLOAT; current_type = $$; }; %endif %ifdef MAPPINGS | F_MAPPING { $$ = TYPE_MAPPING; current_type = $$; }; %endif | F_VOID {$$ = TYPE_VOID; current_type = $$; } | F_MIXED { $$ = TYPE_ANY; current_type = $$; } ; name_list: new_name | new_name ',' name_list; new_name: optional_star F_IDENTIFIER { extern struct svalue const0; %line if (current_type & TYPE_MOD_VARARGS) { yyerror("can't declare a variable as varargs"); current_type &= ~TYPE_MOD_VARARGS; } %ifdef INITIALIZATION_BY___INIT define_variable($2, current_type | $1); } | optional_star F_IDENTIFIER { define_variable($2, current_type | $1); $<number>$ = verify_declared($2); transfer_init_control(); } F_ASSIGN expr0 { ins_f_byte(F_PUSH_IDENTIFIER_LVALUE); ins_byte($<number>3); if ($4 != F_ASSIGN-F_OFFSET) yyerror("Illegal initialization"); if (!compatible_types((current_type | $1) & TYPE_MOD_MASK, $5.type)){ yyerrorf("Type mismatch %s when initializing %s", get_two_types(current_type | $1, $5.type), $2->name); } ins_f_byte(F_VOID_ASSIGN); add_new_init_jump(); } ; %else /* INITIALIZATION_BY___INIT */ define_variable($2, current_type | $1, &const0); } | optional_star F_IDENTIFIER { /* svalue_constant can contain identifiers, so define the variable * now, lest the identifier could get freed by a name clash. */ extern struct svalue const0; int n; %line define_variable($2, current_type | $1 | NAME_INITIALIZED, &const0); n = $2->u.global.variable; $<initialized>$ = currently_initialized = n & VIRTUAL_VAR_TAG ? &((struct svalue *)mem_block[A_VIRTUAL_VAR_VALUES].block) [n & ~VIRTUAL_VAR_TAG] : &((struct svalue *)mem_block[A_VARIABLE_VALUES].block)[n]; } F_ASSIGN svalue_constant { %line if ($4 != F_ASSIGN-F_OFFSET) yyerror("Illegal initialization"); if (exact_types) if (!TYPE( current_type | $1 , type_rtoc($<initialized>3)) ) { yyerror("Bad initializer type"); } }; %endif /* INITIALIZATION_BY___INIT */ block: '{' local_declarations statements '}' { ; }; local_declarations: /* empty */ | local_declarations basic_type local_name_list ';' ; new_local_name: optional_star F_IDENTIFIER { add_local_name($2, current_type | $1); } ; local_name_list: new_local_name | new_local_name ',' local_name_list ; statements: /* empty */ | statement statements | error ';' ; statement: comma_expr ';' { insert_pop_value(); if (d_flag) ins_f_byte(F_BREAK_POINT); /* if (exact_types && !BASIC_TYPE($1.type, TYPE_VOID)) yyerror("Value thrown away"); */ } | cond | while | do | for | switch | case | default | return ';' | block | /* empty */ ';' | F_BREAK ';' /* This code is a jump */ { if (current_break_address == 0) yyerror("break statement outside loop"); if (current_break_address & BREAK_ON_STACK) { ins_f_byte(F_BREAK); } else { ins_f_byte(F_LBRANCH); ins_short(current_break_address); current_break_address = mem_block[A_PROGRAM].current_size - 2; } } | F_CONTINUE ';' /* This code is a jump */ { int depth; %line if (current_continue_address == 0) yyerror("continue statement outside loop"); if (depth = (current_continue_address & SWITCH_DEPTH_MASK)) { while(depth > SWITCH_DEPTH_UNIT*256) { ins_f_code(F_BREAKN_CONTINUE); ins_byte(255); ins_short(2); depth -= SWITCH_DEPTH_UNIT*256; } if (depth > SWITCH_DEPTH_UNIT) { depth /= SWITCH_DEPTH_UNIT; ins_f_code(F_BREAKN_CONTINUE); ins_byte(depth-1); } else { ins_f_code(F_BREAK_CONTINUE); } } else { ins_f_byte(F_LBRANCH); } ins_short(current_continue_address); current_continue_address = ( current_continue_address & SWITCH_DEPTH_MASK ) | ( mem_block[A_PROGRAM].current_size - 2 ); } ; while: { $<numbers>$[0] = current_continue_address; $<numbers>$[1] = current_break_address; push_address(); } F_WHILE '(' comma_expr ')' { %line int addr = pop_address(); int length = CURRENT_PROGRAM_SIZE - addr; char *expression; expression = yalloc(length+2); memcpy(expression, mem_block[A_PROGRAM].block+addr, length); if (last_expression == CURRENT_PROGRAM_SIZE - 1 && expression[length-1] == F_NOT - F_OFFSET ) { length--; expression[length] = F_BBRANCH_WHEN_ZERO - F_OFFSET; } else { expression[length] = F_BBRANCH_WHEN_NON_ZERO - F_OFFSET; } $<expression>$.p = expression; $<expression>$.length = length; $<expression>$.line = current_line; CURRENT_PROGRAM_SIZE = addr; last_expression = -1; ins_f_byte(F_BRANCH); /* to expression */ push_address(); ins_byte(0); current_continue_address = CONTINUE_DELIMITER; current_break_address = BREAK_DELIMITER; } statement { %line int offset; int next_addr; int addr = pop_address(); for(;current_continue_address > 0; current_continue_address = next_addr) { next_addr = read_short(current_continue_address); upd_short(current_continue_address, CURRENT_PROGRAM_SIZE - current_continue_address); } offset = FIX_BRANCH( F_LBRANCH, CURRENT_PROGRAM_SIZE, addr); if ($<expression>6.line != current_line) store_line_number_info(); add_to_mem_block(A_PROGRAM, $<expression>6.p, $<expression>6.length+2); yfree($<expression>6.p); offset += addr + 1 - ( CURRENT_PROGRAM_SIZE - 1 ); if (offset < -0xff) { char * codep; if (offset < -0x8000) yyerror("offset overflow"); codep = mem_block[A_PROGRAM].block + --CURRENT_PROGRAM_SIZE - 1; *codep = *codep == F_BBRANCH_WHEN_NON_ZERO - F_OFFSET ? F_LBRANCH_WHEN_NON_ZERO - F_OFFSET : F_LBRANCH_WHEN_ZERO - F_OFFSET ; ins_short(offset); } else { mem_block[A_PROGRAM].block[CURRENT_PROGRAM_SIZE-1] = -offset; } if ($<expression>6.line != current_line) store_line_number_relocation($<expression>6.line); for(;current_break_address > 0;current_break_address = next_addr) { next_addr = read_short(current_break_address); upd_short(current_break_address, CURRENT_PROGRAM_SIZE - current_break_address); } current_continue_address = $<numbers>1[0]; current_break_address = $<numbers>1[1]; } do: { $<numbers>$[0] = current_continue_address; $<numbers>$[1] = current_break_address; current_break_address = BREAK_DELIMITER; current_continue_address = CONTINUE_DELIMITER; push_address(); } F_DO statement F_WHILE { int next_addr; int current; %line current = CURRENT_PROGRAM_SIZE; for(;current_continue_address > 0; current_continue_address = next_addr) { next_addr = read_short(current_continue_address); upd_short(current_continue_address, current - current_continue_address); } } '(' comma_expr ')' ';' { %line int offset; int next_addr; int addr = pop_address(); int current; char *dest; char tmp_short[2]; current = CURRENT_PROGRAM_SIZE; if (current + 3 > mem_block[A_PROGRAM].max_size) realloc_a_program(); dest = mem_block[A_PROGRAM].block + current; if (current == last_expression + 1 && dest[-1] == F_NOT - F_OFFSET) { offset = addr - current; if (offset < -0xff) { if (offset < -0x8000) yyerror("offset overflow"); *((short *)tmp_short) = offset; dest[-1] = F_LBRANCH_WHEN_ZERO - F_OFFSET; *dest++ = tmp_short[0]; *dest = tmp_short[1]; current += 2; } else { dest[-1] = F_BBRANCH_WHEN_ZERO - F_OFFSET; *dest = -offset; current++; } } else { offset = addr - ( current + 1 ); if (offset < -0xff) { if (offset < -0x8000) yyerror("offset overflow"); *((short *)tmp_short) = offset; *dest++ = F_LBRANCH_WHEN_NON_ZERO - F_OFFSET; *dest++ = tmp_short[0]; *dest = tmp_short[1]; current += 3; } else { *dest++ = F_BBRANCH_WHEN_NON_ZERO - F_OFFSET; *dest = -offset; current += 2; } } CURRENT_PROGRAM_SIZE = current; for(;current_break_address > 0;current_break_address = next_addr) { next_addr = read_short(current_break_address); upd_short(current_break_address, current - current_break_address); } current_continue_address = $<numbers>1[0]; current_break_address = $<numbers>1[1]; } for: F_FOR '(' { $<numbers>$[0] = current_continue_address; $<numbers>$[1] = current_break_address; } for_expr ';' { insert_pop_value(); current_continue_address = CONTINUE_DELIMITER; $<number>$ = CURRENT_PROGRAM_SIZE; } for_expr ';' { %line int start, length; char *expression; start = $<number>6; length = CURRENT_PROGRAM_SIZE - start; expression = yalloc(length+2); memcpy(expression, mem_block[A_PROGRAM].block + start, length ); if (last_expression == CURRENT_PROGRAM_SIZE - 1 && expression[length-1] == F_NOT - F_OFFSET ) { length--; expression[length] = F_BBRANCH_WHEN_ZERO - F_OFFSET; } else { expression[length] = F_BBRANCH_WHEN_NON_ZERO - F_OFFSET; } $<expression>$.p = expression; $<expression>$.length = length; $<expression>$.line = current_line; CURRENT_PROGRAM_SIZE = start; last_expression = -1; } for_expr ')' { %line int length; insert_pop_value(); length = CURRENT_PROGRAM_SIZE - $<number>6; $<expression>$.p = yalloc(length); if (length) memcpy($<expression>$.p, mem_block[A_PROGRAM].block + $<number>6, length ); $<expression>$.length = length; $<expression>$.line = current_line; CURRENT_PROGRAM_SIZE = $<number>6; last_expression = -1; ins_f_byte(F_BRANCH); /* to expression */ ins_byte(0); current_break_address = BREAK_DELIMITER; } statement { %line int offset; int next_addr; for(;current_continue_address > 0; current_continue_address = next_addr) { next_addr = read_short(current_continue_address); upd_short(current_continue_address, CURRENT_PROGRAM_SIZE - current_continue_address); } if ( $<expression>9.line != current_line || ($<expression>12.line != current_line && $<expression>12.length) ) store_line_number_info(); if ($<expression>12.length) { add_to_mem_block(A_PROGRAM, $<expression>12.p, $<expression>12.length); if ($<expression>12.line != $<expression>9.line) store_line_number_relocation($<expression>12.line); } yfree($<expression>12.p); offset = FIX_BRANCH( F_LBRANCH, CURRENT_PROGRAM_SIZE, $<number>6 + 1); add_to_mem_block(A_PROGRAM, $<expression>9.p, $<expression>9.length+2); yfree($<expression>9.p); offset += $<number>6 + 2 - ( CURRENT_PROGRAM_SIZE - 1 ); if (offset < -0xff) { char * codep; if (offset < -0x8000) yyerror("offset overflow"); codep = mem_block[A_PROGRAM].block + --CURRENT_PROGRAM_SIZE - 1; *codep = *codep == F_BBRANCH_WHEN_NON_ZERO - F_OFFSET ? F_LBRANCH_WHEN_NON_ZERO - F_OFFSET : F_LBRANCH_WHEN_ZERO - F_OFFSET ; ins_short(offset); } else { mem_block[A_PROGRAM].block[CURRENT_PROGRAM_SIZE-1] = -offset; } if ($<expression>9.line != current_line) store_line_number_relocation($<expression>9.line); for(;current_break_address > 0;current_break_address = next_addr) { next_addr = read_short(current_break_address); upd_short(current_break_address, CURRENT_PROGRAM_SIZE - current_break_address); } current_continue_address = $<numbers>3[0]; current_break_address = $<numbers>3[1]; } for_expr: /* EMPTY */ { last_expression = mem_block[A_PROGRAM].current_size; ins_f_byte(F_CONST1); } | comma_expr; switch: F_SWITCH '(' comma_expr ')' { %line current_break_stack_need += sizeof(short); if ( current_break_stack_need > max_break_stack_need ) max_break_stack_need = current_break_stack_need; push_explicit(current_case_number_heap); push_explicit(current_case_string_heap); push_explicit(zero_case_label); push_explicit(current_break_address); push_explicit(switch_pc); ins_f_byte(F_SWITCH); switch_pc = mem_block[A_PROGRAM].current_size; ins_byte(0xff); /* kind of table */ current_case_number_heap = mem_block[A_CASE_NUMBERS].current_size; current_case_string_heap = mem_block[A_CASE_STRINGS].current_size; zero_case_label = NO_STRING_CASE_LABELS; ins_short(0); /* address of table */ current_break_address = mem_block[A_PROGRAM].current_size | BREAK_ON_STACK | BREAK_FROM_SWITCH | CASE_LABELS_ENABLED ; if (current_continue_address) current_continue_address += SWITCH_DEPTH_UNIT; ins_short(0); /* break address to push, table is entered before */ ins_short(0); /* default address */ } statement { %line char *heap_start; int heap_end_offs; int i,o; int current_key,last_key; #if 0 /* see below */ int size_without_table; #endif int block_index; int current_case_heap; int lookup_start; int lookup_start_key; unsigned short current_addr,last_addr; current_break_address &= ~(BREAK_ON_STACK|BREAK_FROM_SWITCH|CASE_LABELS_ENABLED); if ( !read_short(current_break_address+2 ) ) upd_short(current_break_address+2, /* no default given -> */ mem_block[A_PROGRAM].current_size - /* create one */ switch_pc ); /* it isn't unusual that the last case/default has no break */ ins_f_byte(F_BREAK); if(zero_case_label & (NO_STRING_CASE_LABELS|SOME_NUMERIC_CASE_LABELS)){ block_index = A_CASE_NUMBERS; current_case_heap = current_case_number_heap; } else { block_index = A_CASE_STRINGS; current_case_heap = current_case_string_heap; if (zero_case_label&0xffff) { struct case_heap_entry temp; temp.key = (int)ZERO_AS_STR_CASE_LABEL; temp.addr = zero_case_label; temp.line = 0; /* if this is accessed later, something is * really wrong */ add_to_case_heap(A_CASE_STRINGS,&temp); } } heap_start = mem_block[block_index].block + current_case_heap ; heap_end_offs = mem_block[block_index].current_size -current_case_heap; if (!heap_end_offs) yyerror("switch without case not supported"); /* add a dummy entry so that we can always * assume we have no or two childs */ add_to_mem_block(block_index, "\0\0\0\0\0\0\0\0", sizeof(struct case_heap_entry) ); /* read out the heap and build a sorted table */ /* the table could be optimized better, but let's first see * how much switch is used at all when it is full-featured... */ mem_block[A_CASE_LABELS].current_size = 0; lookup_start = 0; lookup_start_key = ((struct case_heap_entry*)heap_start)->key; for(last_addr=0xffff; ((struct case_heap_entry*)heap_start)->addr; ) { int offset; int curr_line,last_line; int range_start; current_key = ((struct case_heap_entry*)heap_start)->key ; curr_line = ((struct case_heap_entry*)heap_start)->line ; current_addr = ((struct case_heap_entry*)heap_start)->addr ; if ( current_key == last_key && mem_block[A_CASE_LABELS].current_size ) { yyerrorf("Duplicate case in line %d and %d", last_line, curr_line); } if (curr_line) { if (last_addr == 1) { yyerrorf( "Discontinued case label list range, line %d by line %d", last_line, curr_line); } else if (current_key == last_key + 1 && current_addr == last_addr) { if (mem_block[A_CASE_LABELS].current_size != range_start + 6) { *(short*)(mem_block[A_CASE_LABELS].block+range_start+4) =1; mem_block[A_CASE_LABELS].current_size = range_start + 6; } } else { range_start = mem_block[A_CASE_LABELS].current_size; } } last_key = current_key; last_line = curr_line; last_addr = current_addr; add_to_mem_block(A_CASE_LABELS, (char *)¤t_key, sizeof(long) ); add_to_mem_block(A_CASE_LABELS, (char *)¤t_addr, sizeof(short) ); for ( offset = 0; ; ) { int child1,child2; child1 = ( offset << 1 ) + sizeof(struct case_heap_entry); child2 = child1 + sizeof(struct case_heap_entry); if ( child1 >= heap_end_offs ) break; if ( ((struct case_heap_entry*)(heap_start+child1))->addr && ( !((struct case_heap_entry*)(heap_start+child2))->addr || ((struct case_heap_entry*)(heap_start+child1))->key <= ((struct case_heap_entry*)(heap_start+child2))->key ) ) { *(struct case_heap_entry*)(heap_start+offset) = *(struct case_heap_entry*)(heap_start+child1); offset = child1; } else if (((struct case_heap_entry*)(heap_start+child2))->addr ) { *(struct case_heap_entry*)(heap_start+offset) = *(struct case_heap_entry*)(heap_start+child2); offset = child2; } else break; } ((struct case_heap_entry*)(heap_start+offset))->addr = 0; } /* write start of table */ upd_short(current_break_address-2, mem_block[A_PROGRAM].current_size - switch_pc); if (mem_block[A_CASE_LABELS].current_size) add_to_mem_block(A_PROGRAM, mem_block[A_CASE_LABELS].block, mem_block[A_CASE_LABELS].current_size ); /* calculate starting index for itarative search at execution time */ for(i=0xf0,o=6; o<<1 <= mem_block[A_CASE_LABELS].current_size; ) i++,o<<=1; if (block_index == A_CASE_STRINGS) i = ( i << 4 ) | 0xf; /* and store it */ mem_block[A_PROGRAM].block[current_break_address-3] &= i; #if 0 /* the code for packed switch tables is still incomplete */ d = ((struct case_heap_entry*)heap_start)->key; if ( (r-d)*sizeof(short) < heap_end_offs ) { mem_block[A_PROGRAM].block[current_break_address-3] &= 0xfe; upd_short(current_break_address-2, mem_block[A_PROGRAM].current_size - switch_pc); size_without_table = mem_block[A_PROGRAM].current_size; r = heap_end_offs / sizeof(struct case_heap_entry); add_to_mem_block(A_PROGRAM,mem_block[A_PROGRAM]->block, r * sizeof(short) ); memset(mem_block[A_PROGRAM]->block+size_without_table, '\0',r * sizeof(short) ); ins_long( d ); for(; --r; heap_start += sizeof(struct case_heap_entry) ) { upd_short(size_without_table + sizeof(short)* ( ((struct case_heap_entry*)heap_start)->key - d ) , ((struct case_heap_entry*)heap_start)->addr ); } } #endif /* 0 */ upd_short(current_break_address, mem_block[A_PROGRAM].current_size - switch_pc); mem_block[A_CASE_NUMBERS].current_size = current_case_number_heap; mem_block[A_CASE_STRINGS].current_size = current_case_string_heap; switch_pc = pop_address(); current_break_address = pop_address(); if (current_continue_address) current_continue_address -= SWITCH_DEPTH_UNIT; zero_case_label = pop_address(); current_case_string_heap = pop_address(); current_case_number_heap = pop_address(); current_break_stack_need -= sizeof(short); } ; case: F_CASE case_label ':' { %line struct case_heap_entry temp; if ( !( current_break_address & CASE_LABELS_ENABLED ) ) { yyerror("Case outside switch"); break; } temp.key = $2.key; temp.addr = mem_block[A_PROGRAM].current_size - switch_pc; temp.line = current_line; add_to_case_heap($2.block,&temp); } | F_CASE case_label F_RANGE case_label ':' { %line struct case_heap_entry temp; if ( $2.block != A_CASE_NUMBERS || $4.block != A_CASE_NUMBERS ) yyerror("String case labels not allowed as range bounds"); if ($2.key > $4.key) break; temp.key = $2.key; temp.addr = 1; temp.line = current_line; add_to_case_heap(A_CASE_NUMBERS,&temp); temp.key = $4.key; temp.addr = mem_block[A_PROGRAM].current_size - switch_pc; temp.line = 0; add_to_case_heap(A_CASE_NUMBERS,&temp); } ; case_label: constant { %line if ( $$.key = $1 ) { if ( !(zero_case_label & NO_STRING_CASE_LABELS) ) yyerror("Mixed case label list not allowed"); zero_case_label |= SOME_NUMERIC_CASE_LABELS; } else { zero_case_label |= mem_block[A_PROGRAM].current_size - switch_pc; } $$.block = A_CASE_NUMBERS; } | string_constant { %line if ( zero_case_label & SOME_NUMERIC_CASE_LABELS ) yyerror("Mixed case label list not allowed"); zero_case_label &= ~NO_STRING_CASE_LABELS; store_prog_string(last_string_constant); $$.key = (int)last_string_constant; $$.block = A_CASE_STRINGS; last_string_constant = 0; } ; constant: constant '|' constant { $$ = $1 | $3; } | constant '^' constant { $$ = $1 ^ $3; } | constant '&' constant { $$ = $1 & $3; } | constant F_EQ constant { $$ = $1 == $3; } | constant F_NE constant { $$ = $1 != $3; } | constant '>' constant { $$ = $1 > $3; } | constant F_GE constant { $$ = $1 >= $3; } | constant '<' constant { $$ = $1 < $3; } | constant F_LE constant { $$ = $1 <= $3; } | constant F_LSH constant { $$ = $1 << $3; } | constant F_RSH constant { $$ = $1 >> $3; } | constant '+' constant { $$ = $1 + $3; } | constant '-' constant { $$ = $1 - $3; } | constant '*' constant { $$ = $1 * $3; } | constant '%' constant { if ($3) { $$ = $1 % $3; } else { yyerror("division by zero"); $$ = 0; } } | constant '/' constant { if ($3) { $$ = $1 / $3; } else { yyerror("division by zero"); $$ = 0; } } | '(' constant ')' { $$ = $2; } ; | '-' constant %prec '~' { $$ = -$2; } | F_NOT constant { $$ = !$2; } | '~' constant { $$ = ~$2; } ; | F_NUMBER ; default: F_DEFAULT ':' { if ( !( current_break_address & CASE_LABELS_ENABLED ) ) { yyerror("Default outside switch"); break; } current_break_address &= ~(BREAK_ON_STACK|BREAK_FROM_SWITCH|CASE_LABELS_ENABLED); if ( read_short(current_break_address+2 ) ) yyerror("Duplicate default"); upd_short(current_break_address+2, mem_block[A_PROGRAM].current_size - switch_pc ); current_break_address |= (BREAK_ON_STACK|BREAK_FROM_SWITCH|CASE_LABELS_ENABLED); } ; comma_expr: expr0 | comma_expr { insert_pop_value(); } ',' expr0 { $$.type = $4.type; } ; expr0: lvalue F_ASSIGN expr0 %prec F_ASSIGN { int length; int type2; %line type2 = $3.type; if (exact_types && !compatible_types($1.type, type2) && !($1.type == TYPE_STRING && type2 == TYPE_NUMBER && $2 == F_ADD_EQ-F_OFFSET)) { type_error("Bad assignment. Rhs", $3.type); } if (type2 & TYPE_MOD_REFERENCE) yyerror("Can't trace reference assignments.\n"); length = $1.length; if (length) { add_to_mem_block (A_PROGRAM, $1.u.p, length+1); yfree($1.u.p); mem_block[A_PROGRAM].block[ last_expression = CURRENT_PROGRAM_SIZE-1 ] = $2; } else { char *source, *dest; int current_size; source = $1.u.simple; current_size = CURRENT_PROGRAM_SIZE; CURRENT_PROGRAM_SIZE = (last_expression = current_size + 2) + 1; if (current_size + 3 > mem_block[A_PROGRAM].max_size ) if (!realloc_a_program()) { yyerror("Out of memory\n"); YYACCEPT; } dest = mem_block[A_PROGRAM].block + current_size; *dest++ = *source++; *dest++ = *source; *dest = $2; } $$.type = type2; } | error F_ASSIGN expr0 %prec F_ASSIGN { yyerror("Illegal LHS"); $$.type = TYPE_ANY; }; | expr0 '?' %prec '?' { ins_f_byte(F_BRANCH_WHEN_ZERO); $<number>$ = CURRENT_PROGRAM_SIZE; ins_byte(0); } expr0 { int address, offset; address = $<number>3; ins_f_byte(F_BRANCH); $<number>$ = CURRENT_PROGRAM_SIZE; ins_byte(0); offset = CURRENT_PROGRAM_SIZE - ( address + 1); if (offset > 0xff - 1) { int i; char *p; $<number>$ = CURRENT_PROGRAM_SIZE; ins_byte(0); p = mem_block[A_PROGRAM].block + mem_block[A_PROGRAM].current_size-1; for( i = offset; --i >= 0; --p ) *p = p[-1]; p[-2] = F_LBRANCH_WHEN_ZERO-F_OFFSET; upd_short(address, offset+2); if (offset > 0x7ffd) yyerror("offset overflow"); } else { mem_block[A_PROGRAM].block[address] = offset; } } ':' expr0 %prec '?' { int address, old_address; int offset; int type1, type2; last_expression = -1; old_address = $<number>3; address = $<number>5; offset = mem_block[A_PROGRAM].current_size - ( address + 1); if (offset > 0xff) { int i; char *p; ins_byte(0); p = mem_block[A_PROGRAM].block + mem_block[A_PROGRAM].current_size-1; for( i = offset; --i >= 0; --p ) *p = p[-1]; p[-2] = F_LBRANCH-F_OFFSET; upd_short(address, offset+2); if (offset > 0x7ffd) yyerror("offset overflow"); if ( mem_block[A_PROGRAM].block[old_address-1] == F_BRANCH_WHEN_ZERO-F_OFFSET ) mem_block[A_PROGRAM].block[old_address]++; else upd_short(old_address,read_short(old_address)+1); } else { mem_block[A_PROGRAM].block[address] = offset; } type1 = $4.type; type2 = $7.type; if (exact_types && !compatible_types(type1, type2)) { type_error("Different types in ?: expr", type1); type_error(" and ", type2); } if (type1 == TYPE_ANY) $$.type = type2; else if (type2 == TYPE_ANY) $$.type = type1; else if (type1 == (TYPE_MOD_POINTER|TYPE_ANY) ) $$.type = type2; else if (type2 == (TYPE_MOD_POINTER|TYPE_ANY) ) $$.type = type1; else $$.type = type1; } | expr0 F_LOR %prec F_LOR { ins_f_byte(F_LOR); $<number>$ = CURRENT_PROGRAM_SIZE; ins_byte(0); } expr0 { int address, offset; last_expression = -1; address = $<number>3; offset = mem_block[A_PROGRAM].current_size - ( address + 1); if (offset > 0xff) { int i; char *p; ins_short(0); ins_byte(0); p = mem_block[A_PROGRAM].block + mem_block[A_PROGRAM].current_size-1; for( i = offset; --i >= 0; --p ) *p = p[-3]; p[-4] = F_DUP-F_OFFSET; p[-3] = F_LBRANCH_WHEN_NON_ZERO-F_OFFSET; upd_short(address+1, offset+3); if (offset > 0x7ffc) yyerror("offset overflow"); p[0] = F_POP_VALUE-F_OFFSET; } else { mem_block[A_PROGRAM].block[address] = offset; } if ($1.type == $4.type) $$.type = $1.type; else $$.type = TYPE_ANY; /* Return type can't be known */ } | expr0 F_LAND %prec F_LAND { ins_f_byte(F_LAND); $<number>$ = CURRENT_PROGRAM_SIZE; ins_byte(0); } expr0 { int address, offset; last_expression = -1; address = $<number>3; offset = mem_block[A_PROGRAM].current_size - ( address + 1); if (offset > 0xff) { int i; char *p; ins_short(0); ins_byte(0); p = mem_block[A_PROGRAM].block + mem_block[A_PROGRAM].current_size-1; for( i = offset; --i >= 0; --p ) *p = p[-3]; p[-4] = F_DUP-F_OFFSET; p[-3] = F_LBRANCH_WHEN_ZERO-F_OFFSET; upd_short(address+1, offset+3); if (offset > 0x7ffc) yyerror("offset overflow"); p[0] = F_POP_VALUE-F_OFFSET; } else { mem_block[A_PROGRAM].block[address] = offset; } if ($1.type == $4.type) $$.type = $1.type; else $$.type = TYPE_ANY; /* Return type can't be known */ } ; | expr0 '|' expr0 { if (exact_types && !BASIC_TYPE($1.type,TYPE_NUMBER)) type_error("Bad argument 1 to |", $1.type); if (exact_types && !BASIC_TYPE($3.type,TYPE_NUMBER)) type_error("Bad argument 2 to |", $3.type); $$.type = TYPE_NUMBER; ins_f_byte(F_OR); } | expr0 '^' expr0 { if (exact_types && !BASIC_TYPE($1.type,TYPE_NUMBER)) type_error("Bad argument 1 to ^", $1.type); if (exact_types && !BASIC_TYPE($3.type,TYPE_NUMBER)) type_error("Bad argument 2 to ^", $3.type); $$.type = TYPE_NUMBER; ins_f_byte(F_XOR); } | expr0 '&' expr0 { ins_f_byte(F_AND); $$.type = TYPE_ANY; if (exact_types) { short first_type = $1.type; short second_type = $3.type; if ( first_type == TYPE_ANY && second_type == TYPE_ANY ) { /* $$ == TYPE_ANY is correct */ } else if ( (first_type | second_type) & TYPE_MOD_POINTER) { if (first_type == TYPE_NUMBER || second_type == TYPE_NUMBER) { yyerrorf("Incompatible types for arguments to & %s" ,get_two_types(first_type, second_type)); } else if ( ( !( first_type & TYPE_MOD_POINTER ) || first_type & TYPE_MOD_REFERENCE) && first_type != TYPE_ANY ) { type_error("Bad argument 1 to &", first_type ); } else if ( ( !( second_type & TYPE_MOD_POINTER ) || second_type & TYPE_MOD_REFERENCE) && second_type != TYPE_ANY ) { type_error("Bad argument 2 to &", first_type ); } else if ( !BASIC_TYPE(first_type &~TYPE_MOD_POINTER, second_type &~TYPE_MOD_POINTER) ) { yyerrorf("Incompatible types for arguments to & %s" ,get_two_types(first_type, second_type)); } else { $$.type = TYPE_ANY | TYPE_MOD_POINTER; } } else { if ( !BASIC_TYPE(first_type ,TYPE_NUMBER) ) type_error("Bad argument 1 to &", first_type ); if ( !BASIC_TYPE(second_type,TYPE_NUMBER) ) type_error("Bad argument 2 to &", second_type); $$.type = TYPE_NUMBER; } } /* end of exact_types code */ } /* end of '&' code */ | expr0 F_EQ expr0 { int t1 = $1.type, t2 = $3.type; if (exact_types && t1 != t2 && t1 != TYPE_ANY && t2 != TYPE_ANY) { type_error("== always false because of different types", $1.type); type_error(" compared to", $3.type); } ins_f_byte(F_EQ); $$.type = TYPE_NUMBER; } | expr0 F_NE expr0 { int t1 = $1.type, t2 = $3.type; if (exact_types && t1 != t2 && t1 != TYPE_ANY && t2 != TYPE_ANY) { type_error("!= always true because of different types", $1.type); type_error(" compared to", $3.type); } ins_f_byte(F_NE); $$.type = TYPE_NUMBER; } | expr0 '>' expr0 { $$.type = TYPE_NUMBER; ins_f_byte(F_GT); } | expr0 F_GE expr0 { $$.type = TYPE_NUMBER; ins_f_byte(F_GE); } | expr0 '<' expr0 { $$.type = TYPE_NUMBER; ins_f_byte(F_LT); } | expr0 F_LE expr0 { $$.type = TYPE_NUMBER; ins_f_byte(F_LE); } | expr0 F_LSH expr0 { ins_f_byte(F_LSH); $$.type = TYPE_NUMBER; if (exact_types && !BASIC_TYPE($1.type, TYPE_NUMBER)) type_error("Bad argument number 1 to '<<'", $1.type); if (exact_types && !BASIC_TYPE($3.type, TYPE_NUMBER)) type_error("Bad argument number 2 to '<<'", $3.type); } | expr0 F_RSH expr0 { ins_f_byte(F_RSH); $$.type = TYPE_NUMBER; if (exact_types && !BASIC_TYPE($1.type, TYPE_NUMBER)) type_error("Bad argument number 1 to '>>'", $1.type); if (exact_types && !BASIC_TYPE($3.type, TYPE_NUMBER)) type_error("Bad argument number 2 to '>>'", $3.type); }; | expr0 '+' { %line $<numbers>$[0] = last_expression; $<numbers>$[1] = last_string_is_new; } expr0 { /* Type checks of this case are complicated */ int current_size; unsigned char *p; %line if (pragma_combine_strings && last_expression + 2 == (current_size = CURRENT_PROGRAM_SIZE) && $<numbers>3[0] + 4 == current_size && (((p = &mem_block[A_PROGRAM].block[current_size])[-2] - (F_CSTRING0 - F_OFFSET)) & ~3) == 0 && ((p[-4] - (F_CSTRING0 - F_OFFSET)) & ~3) == 0 ) { char *str1, *str2, *sum; int i; str1 = ((char**)(mem_block[A_STRINGS].block)) [p[-3] | (p[-4]-(F_CSTRING0-F_OFFSET))<<8 ]; str2 = ((char**)(mem_block[A_STRINGS].block)) [p[-1] | (p[-2]-(F_CSTRING0-F_OFFSET))<<8 ]; sum = xalloc(strlen(str1) + strlen(str2) + 1); strcpy(sum, str1); strcat(sum, str2); if (last_string_is_new) { delete_prog_string(); } if ($<numbers>3[1]) { delete_prog_string(); } i = store_prog_string(make_shared_string(sum)); xfree(sum); last_expression = current_size - 4; if (i < 0x400) { p[-4] = F_CSTRING0 - F_OFFSET + (i>>8); p[-3] = i; CURRENT_PROGRAM_SIZE = current_size - 2; } else { p[-4] = F_STRING-F_OFFSET; upd_short(current_size - 3, i); CURRENT_PROGRAM_SIZE = current_size - 1; } $$.type = TYPE_STRING; } else { ins_f_byte(F_ADD); $$.type = TYPE_ANY; } }; | expr0 '-' expr0 { %line int bad_arg = 0; $$.type = TYPE_ANY; if (exact_types) { int type1 = $1.type; int type2 = $3.type; if (type1 != TYPE_ANY && type1 != TYPE_NUMBER && type1 != TYPE_FLOAT && !(type1 & TYPE_MOD_POINTER) ) { type_error("Bad argument number 1 to '-'", type1); bad_arg++; } if (type2 != TYPE_ANY && type2 != TYPE_NUMBER && type2 != TYPE_FLOAT && !(type2 & TYPE_MOD_POINTER) ) { type_error("Bad argument number 2 to '-'", type2); bad_arg++; } if ( ( type1 == TYPE_ANY && BASIC_TYPE(type2, TYPE_NUMBER) ) || ( type2 == TYPE_ANY && BASIC_TYPE(type1, TYPE_NUMBER) ) ) { $$.type = TYPE_ANY; } else if ( type1 == TYPE_NUMBER && type2 == TYPE_NUMBER ) { $$.type = TYPE_NUMBER; } else if ( ( type1 == TYPE_FLOAT ) || ( type2 == TYPE_FLOAT ) ) { if (!bad_arg) $$.type = TYPE_FLOAT; } if ( (type1 | type2 ) & TYPE_MOD_POINTER && !bad_arg) { if (type1 != type2 && ((type1 & ~TYPE_MOD_POINTER) != TYPE_ANY || !(type2 & TYPE_MOD_POINTER) || (type2 & TYPE_MOD_REFERENCE)) && ((type2 & ~TYPE_MOD_POINTER) != TYPE_ANY || !(type1 & TYPE_MOD_POINTER) || (type1 & TYPE_MOD_REFERENCE)) ) { yyerror("Arguments to '-' don't match"); $$.type = TYPE_ANY; } else $$.type = TYPE_MOD_POINTER | TYPE_ANY; } } ins_f_byte(F_SUBTRACT); }; | expr0 '*' expr0 { int type1, type2; type1 = $1.type; type2 = $3.type; if (exact_types) { if ( !BASIC_TYPE(type1, TYPE_NUMBER) && type1 != TYPE_FLOAT) type_error("Bad argument number 1 to '*'", type1); if ( !BASIC_TYPE(type2, TYPE_NUMBER) && type2 != TYPE_FLOAT) type_error("Bad argument number 2 to '*'", type2); } ins_f_byte(F_MULTIPLY); if (type1 == TYPE_FLOAT || type2 == TYPE_FLOAT ) { $$.type = TYPE_FLOAT; } else { $$.type = TYPE_NUMBER; } }; | expr0 '%' expr0 { if (exact_types) { if (!BASIC_TYPE($1.type, TYPE_NUMBER)) type_error("Bad argument number 1 to '%'", $1.type); if (!BASIC_TYPE($3.type, TYPE_NUMBER)) type_error("Bad argument number 2 to '%'", $3.type); } ins_f_byte(F_MOD); $$.type = TYPE_NUMBER; }; | expr0 '/' expr0 { int type1, type2; type1 = $1.type; type2 = $3.type; if (exact_types) { if ( !BASIC_TYPE(type1, TYPE_NUMBER) && type1 != TYPE_FLOAT) type_error("Bad argument number 1 to '/'", type1); if ( !BASIC_TYPE(type2, TYPE_NUMBER) && type2 != TYPE_FLOAT) type_error("Bad argument number 2 to '/'", type2); } ins_f_byte(F_DIVIDE); if (type1 == TYPE_FLOAT || type2 == TYPE_FLOAT ) { $$.type = TYPE_FLOAT; } else { $$.type = TYPE_NUMBER; } }; | decl_cast expr0 %prec '~' { $$.type = $1; if (exact_types && $2.type != TYPE_ANY && $2.type != TYPE_UNKNOWN && $1 != TYPE_VOID) type_error("Casts are only legal for type mixed, or when unknown", $2.type); } ; | cast expr0 %prec '~' { $$.type = $1; if ($2.type != TYPE_ANY && $2.type != TYPE_UNKNOWN && $1 != TYPE_VOID) { switch($1) { default: type_error("Illegal cast", $1); break; case TYPE_NUMBER: ins_f_code(F_TO_INT); break; case TYPE_FLOAT: ins_f_code(F_TO_FLOAT); break; case TYPE_STRING: ins_f_code(F_TO_STRING); break; case TYPE_OBJECT: ins_f_code(F_FIND_OBJECT); break; case TYPE_NUMBER|TYPE_MOD_POINTER: ins_f_code(F_TO_ARRAY); break; } } } ; | pre_inc_dec F_IDENTIFIER %prec F_INC { int i; PREPARE_INSERT(3) %line i = verify_declared($2); if (i != -1) { if (i & VIRTUAL_VAR_TAG) { add_f_byte(F_PUSH_VIRTUAL_VARIABLE_LVALUE); add_byte(i); i = V_VARIABLE(i)->flags & TYPE_MOD_MASK; } else { add_f_byte(F_PUSH_IDENTIFIER_LVALUE); add_byte(i + num_virtual_variables); i = NV_VARIABLE(i)->flags & TYPE_MOD_MASK; } if (exact_types && !BASIC_TYPE(i, TYPE_NUMBER)) { argument_type_error($1, i); } } CURRENT_PROGRAM_SIZE = (last_expression = CURRENT_PROGRAM_SIZE + 2) + 1; add_byte($1); $$.type = TYPE_NUMBER; } | pre_inc_dec F_LOCAL %prec F_INC { int i; PREPARE_INSERT(3) %line add_f_byte(F_PUSH_LOCAL_VARIABLE_LVALUE); add_byte($2); CURRENT_PROGRAM_SIZE = (last_expression = CURRENT_PROGRAM_SIZE + 2) + 1; add_byte($1); i = type_of_locals[$2]; if (exact_types && !BASIC_TYPE(i, TYPE_NUMBER)) { argument_type_error($1, i); } $$.type = TYPE_NUMBER; } | pre_inc_dec expr4 '[' expr0 ']' %prec '[' { /* the ',' operator is reserved for indexing on multi-valued * mappings and other multi-dimensional data */ int current; char *p; int start; %line if (exact_types) { int type; type = $2.type; if (type & TYPE_MOD_POINTER) { if (type != (TYPE_MOD_POINTER|TYPE_ANY) && type != (TYPE_MOD_POINTER|TYPE_NUMBER) ) argument_type_error($1, type); } else switch (type) { default: type_error("Bad type to indexed lvalue", type); case TYPE_STRING: case TYPE_ANY: if (!BASIC_TYPE($4.type, TYPE_NUMBER)) type_error("Bad type of index", $4.type); #ifdef MAPPINGS case TYPE_MAPPING: #endif ; } } current = CURRENT_PROGRAM_SIZE; start = $2.start; if ($2.code >= 0) { if ($2.end) { int length; char *q; length = $2.end - start; if (current+length > mem_block[A_PROGRAM].max_size) realloc_a_program(); p = mem_block[A_PROGRAM].block; memcpy( p + current, p + start, length ); p += start; q = p + length + 1; length = current - start - 1; for( ; --length >= 0; ) *p++ = *q++; *p++ = $2.code; *p++ = F_INDEX_LVALUE - F_OFFSET; } else { int i; int length; if (current + 2 > mem_block[A_PROGRAM].max_size) realloc_a_program(); p = mem_block[A_PROGRAM].block + start; i = p[1]; length = current - start - 2; for( ; --length >= 0; p++) *p = p[2]; *p++ = $2.code; *p++ = i; *p++ = F_INDEX_LVALUE - F_OFFSET; } } else { if (current + 2 > mem_block[A_PROGRAM].max_size) realloc_a_program(); p = mem_block[A_PROGRAM].block + start; *p++ = F_PUSH_INDEXED_LVALUE - F_OFFSET; } *p = $1; last_expression = current + 1; CURRENT_PROGRAM_SIZE = current + 2; $$.type = TYPE_NUMBER; }; | pre_inc_dec expr4 '[' '<' expr0 ']' %prec '[' { /* the ',' operator is reserved for indexing on multi-valued * mappings and other multi-dimensional data */ int current; char *p; int start; %line if (exact_types) { int type; type = $2.type; if (type & TYPE_MOD_POINTER) { if (type != (TYPE_MOD_POINTER|TYPE_ANY) && type != (TYPE_MOD_POINTER|TYPE_NUMBER) ) argument_type_error($1, type); } else switch (type) { default: type_error("Bad type to indexed lvalue", type); case TYPE_STRING: case TYPE_ANY: if (!BASIC_TYPE($5.type, TYPE_NUMBER)) type_error("Bad type of index", $5.type); #ifdef MAPPINGS case TYPE_MAPPING: #endif ; } } current = CURRENT_PROGRAM_SIZE; start = $2.start; if ($2.code >= 0) { if ($2.end) { int length; char *q; length = $2.end - start; if (current+length > mem_block[A_PROGRAM].max_size) realloc_a_program(); p = mem_block[A_PROGRAM].block; memcpy( p + current, p + start, length ); p += start; q = p + length + 1; length = current - start - 1; for( ; --length >= 0; ) *p++ = *q++; *p++ = $2.code; *p++ = F_RINDEX_LVALUE - F_OFFSET; } else { int i; int length; if (current + 2 > mem_block[A_PROGRAM].max_size) realloc_a_program(); p = mem_block[A_PROGRAM].block + start; i = p[1]; length = current - start - 2; for( ; --length >= 0; p++) *p = p[2]; *p++ = $2.code; *p++ = i; *p++ = F_RINDEX_LVALUE - F_OFFSET; } } else { if (current + 2 > mem_block[A_PROGRAM].max_size) realloc_a_program(); p = mem_block[A_PROGRAM].block + start; *p++ = F_PUSH_RINDEXED_LVALUE - F_OFFSET; } *p = $1; last_expression = current + 1; CURRENT_PROGRAM_SIZE = current + 2; $$.type = TYPE_NUMBER; }; | F_NOT expr0 { last_expression = CURRENT_PROGRAM_SIZE; ins_f_byte(F_NOT); /* Any type is valid here. */ $$.type = TYPE_NUMBER; }; | '~' expr0 { ins_f_byte(F_COMPL); if (exact_types && !BASIC_TYPE($2.type, TYPE_NUMBER)) type_error("Bad argument to ~", $2.type); $$.type = TYPE_NUMBER; }; | '-' expr0 %prec '~' { int type; if (CURRENT_PROGRAM_SIZE - last_expression == 2 && mem_block[A_PROGRAM].block[last_expression] == F_CLIT - F_OFFSET ) { mem_block[A_PROGRAM].block[last_expression] = F_NCLIT - F_OFFSET; } else { ins_f_byte(F_NEGATE); } type = $2.type; $$.type = type; if (exact_types && !BASIC_TYPE(type, TYPE_NUMBER) && type != TYPE_FLOAT ) type_error("Bad argument to unary '-'", $2.type); }; | lvalue F_INC %prec F_INC { if ($1.length) { add_to_mem_block(A_PROGRAM, $1.u.p, $1.length); yfree($1.u.p); last_expression = CURRENT_PROGRAM_SIZE; ins_f_byte(F_POST_INC); } else { PREPARE_INSERT(3) char *source; CURRENT_PROGRAM_SIZE = (last_expression = CURRENT_PROGRAM_SIZE+2) + 1; source = $1.u.simple; add_byte(*source++); add_byte(*source); add_f_byte(F_POST_INC); } if (exact_types && !BASIC_TYPE($1.type, TYPE_NUMBER)) type_error("Bad argument to ++", $1.type); $$.type = TYPE_NUMBER; }; | lvalue F_DEC %prec F_DEC { if ($1.length) { add_to_mem_block(A_PROGRAM, $1.u.p, $1.length+1); yfree($1.u.p); mem_block[A_PROGRAM].block[ last_expression = CURRENT_PROGRAM_SIZE-1 ] = F_POST_DEC - F_OFFSET; } else { PREPARE_INSERT(3) char *source; CURRENT_PROGRAM_SIZE = (last_expression = CURRENT_PROGRAM_SIZE+2) + 1; source = $1.u.simple; add_byte(*source++); add_byte(*source); add_f_byte(F_POST_DEC); } if (exact_types && !BASIC_TYPE($1.type, TYPE_NUMBER)) type_error("Bad argument to --", $1.type); $$.type = TYPE_NUMBER; }; | expr4 ; note_start: { $$.start = CURRENT_PROGRAM_SIZE; } expr4: function_call %prec '~' %// | F_STRING F_STRING %// { fatal("presence of rule should prevent its reduction"); } | F_STRING { int string_number; PREPARE_S_INSERT(3) char *p; %line p = last_lex_string; last_lex_string = 0; $$.start = last_expression = CURRENT_PROGRAM_SIZE; $$.type = TYPE_STRING; $$.code = -1; string_number = store_prog_string(p); if ( string_number <= 0xff ) { add_f_byte(F_CSTRING0); add_byte(string_number); } else if ( string_number <= 0x1ff ) { add_f_byte(F_CSTRING1); add_byte(string_number); } else if ( string_number <= 0x2ff ) { add_f_byte(F_CSTRING2); add_byte(string_number); } else if ( string_number <= 0x3ff ) { add_f_byte(F_CSTRING3); add_byte(string_number); } else { add_f_byte(F_STRING); add_short(string_number); CURRENT_PROGRAM_SIZE++; } CURRENT_PROGRAM_SIZE += 2; }; | F_NUMBER { int current; int number; PREPARE_INSERT(5) %line $$.start = last_expression = current = CURRENT_PROGRAM_SIZE; $$.code = -1; number = $1; if ( number == 0 ) { current++; add_f_byte(F_CONST0); $$.type = TYPE_ANY; } else if ( number == 1 ) { add_f_byte(F_CONST1); current++; $$.type = TYPE_NUMBER; } else if ( number >= 0 && number <= 0xff ) { add_f_byte(F_CLIT); add_byte(number); current += 2; $$.type = TYPE_NUMBER; } else { char * source = (char*)&$1; add_f_byte(F_NUMBER); add_byte(*source++); add_byte(*source++); add_byte(*source++); add_byte(*source); current += 5; $$.type = TYPE_NUMBER; } CURRENT_PROGRAM_SIZE = current; } ; | F_CLOSURE { int ix; $$.start = CURRENT_PROGRAM_SIZE; $$.code = -1; ix = $1.number; ins_f_byte(F_CLOSURE); ins_short(ix); $$.type = TYPE_CLOSURE; } ; | F_SYMBOL { int string_number; int quotes; $$.start = CURRENT_PROGRAM_SIZE; $$.code = -1; quotes = $1.quotes; string_number = store_prog_string($1.name); if (quotes == 1 && string_number < 0x100) { ins_f_byte(F_CSTRING0); ins_byte(string_number); ins_f_byte(F_QUOTE); } else { ins_f_byte(F_SYMBOL); ins_short(string_number); ins_byte(quotes); } $$.type = TYPE_SYMBOL; } ; %ifdef FLOATS | F_FLOAT { int exponent; $$.start = CURRENT_PROGRAM_SIZE; $$.code = -1; ins_f_byte(F_FLOAT); ins_long ( SPLIT_DOUBLE( $1, &exponent) ); ins_short( exponent ); $$.type = TYPE_FLOAT; } ; %endif /* FLOATS */ | '(' note_start comma_expr ')' %prec '~' { $$.type = $3.type; $$.start = $2.start; $$.code = -1; } | catch %prec '~' | sscanf %prec '~' | parse_command %prec '~' | '(' '{' note_start expr_list '}' ')' %prec '~' { check_aggregate_types($4); /* We don't care about these types, * unless a reference appears */ ins_f_byte(F_AGGREGATE); ins_short($4); if ($4 > MAX_ARRAY_SIZE) yyerror("Illegal array size.\n"); $$.type = TYPE_MOD_POINTER | TYPE_ANY; $$.start = $3.start; $$.code = -1; } | F_QUOTED_AGGREGATE note_start expr_list '}' ')' %prec '~' { int quotes; check_aggregate_types($3); /* We don't care about these types, * unless a reference appears */ ins_f_byte(F_AGGREGATE); ins_short($3); if ($3 > MAX_ARRAY_SIZE) yyerror("Illegal array size.\n"); $$.type = TYPE_QUOTED_ARRAY; $$.start = $2.start; $$.code = -1; quotes = $1; do { ins_f_byte(F_QUOTE); } while (--quotes); } %ifdef MAPPINGS | '(' '[' note_start m_expr_list ']' ')' { mp_int num_keys; check_aggregate_types($4[0]); num_keys = $4[0] / ($4[1]+1); if ( (num_keys | $4[1]) &~0xff) { ins_f_byte(F_M_AGGREGATE); ins_short(num_keys); ins_short($4[1]); } else { ins_f_byte(F_M_CAGGREGATE); ins_byte(num_keys); ins_byte($4[1]); } $$.type = TYPE_MAPPING; $$.start = $3.start; $$.code = -1; } %endif | expr4 '[' expr0 F_RANGE expr0 ']' %prec '[' { %line $$.start = $1.start; $$.code = -1; ins_f_byte(F_RANGE); if (exact_types) { int type; $$.type = type = $1.type & TYPE_MOD_MASK; if ((type & TYPE_MOD_POINTER) == 0 && type != TYPE_ANY && type != TYPE_STRING) { type_error("Bad type of argument used for range", type); $$.type = TYPE_ANY; } type = $3.type & TYPE_MOD_MASK; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); type = $5.type & TYPE_MOD_MASK; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); } }; | expr4 '[' expr0 F_RANGE '<' expr0 ']' %prec '[' { %line $$.start = $1.start; $$.code = -1; ins_f_code(F_NR_RANGE); if (exact_types) { int type; $$.type = type = $1.type & TYPE_MOD_MASK; if ((type & TYPE_MOD_POINTER) == 0 && type != TYPE_ANY && type != TYPE_STRING) { type_error("Bad type of argument used for range", type); $$.type = TYPE_ANY; } type = $3.type & TYPE_MOD_MASK; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); type = $6.type & TYPE_MOD_MASK; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); } }; | expr4 '[' '<' expr0 F_RANGE expr0 ']' %prec '[' { %line $$.start = $1.start; $$.code = -1; ins_f_code(F_RN_RANGE); if (exact_types) { int type; $$.type = type = $1.type & TYPE_MOD_MASK; if ((type & TYPE_MOD_POINTER) == 0 && type != TYPE_ANY && type != TYPE_STRING) { type_error("Bad type of argument used for range", type); $$.type = TYPE_ANY; } type = $4.type & TYPE_MOD_MASK; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); type = $6.type & TYPE_MOD_MASK; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); } }; | expr4 '[' '<' expr0 F_RANGE '<' expr0 ']' %prec '[' { %line $$.start = $1.start; $$.code = -1; ins_f_code(F_RR_RANGE); if (exact_types) { int type; $$.type = type = $1.type & TYPE_MOD_MASK; if ((type & TYPE_MOD_POINTER) == 0 && type != TYPE_ANY && type != TYPE_STRING) { type_error("Bad type of argument used for range", type); $$.type = TYPE_ANY; } type = $4.type & TYPE_MOD_MASK; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); type = $7.type & TYPE_MOD_MASK; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); } }; | expr4 '[' expr0 F_RANGE ']' %prec '[' { %line $$.start = $1.start; $$.code = -1; ins_f_byte(F_EXTRACT2); if (exact_types) { int type; $$.type = type = $1.type & TYPE_MOD_MASK; if ((type & TYPE_MOD_POINTER) == 0 && type != TYPE_ANY && type != TYPE_STRING) { type_error("Bad type of argument used for range", type); $$.type = TYPE_ANY; } type = $3.type & TYPE_MOD_MASK; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); } }; | expr4 '[' '<' expr0 F_RANGE ']' %prec '[' { %line $$.start = $1.start; $$.code = -1; if (CURRENT_PROGRAM_SIZE - last_expression == 2 && mem_block[A_PROGRAM].block[last_expression] == F_CLIT - F_OFFSET ) { mem_block[A_PROGRAM].block[last_expression] = F_NCLIT - F_OFFSET; } else { ins_f_byte(F_NEGATE); } ins_f_byte(F_EXTRACT2); if (exact_types) { int type; $$.type = type = $1.type & TYPE_MOD_MASK; if ((type & TYPE_MOD_POINTER) == 0 && type != TYPE_ANY && type != TYPE_STRING) { type_error("Bad type of argument used for range", type); $$.type = TYPE_ANY; } type = $4.type & TYPE_MOD_MASK; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); } }; | '&' F_IDENTIFIER %prec '~' { int i; int current; char *p; %line i = verify_declared($2); $$.start = current = CURRENT_PROGRAM_SIZE; $$.code = -1; if (current + 2 > mem_block[A_PROGRAM].max_size) realloc_a_program(); p = mem_block[A_PROGRAM].block + current; if (i & VIRTUAL_VAR_TAG) { *p++ = F_PUSH_VIRTUAL_VARIABLE_LVALUE - F_OFFSET; *p = i; } else { *p++ = F_PUSH_IDENTIFIER_LVALUE - F_OFFSET; *p = i + num_virtual_variables; } CURRENT_PROGRAM_SIZE = current + 2; if (i == -1) $$.type = TYPE_ANY | TYPE_MOD_REFERENCE; else $$.type = (VARIABLE(i)->flags & TYPE_MOD_MASK) | TYPE_MOD_REFERENCE; }; | '&' F_LOCAL %prec '~' { int current; char *p; %line $$.start = current = CURRENT_PROGRAM_SIZE; $$.code = -1; if (current + 2 > mem_block[A_PROGRAM].max_size) realloc_a_program(); p = mem_block[A_PROGRAM].block + current; *p++ = F_PUSH_LOCAL_VARIABLE_LVALUE - F_OFFSET; *p = $2; CURRENT_PROGRAM_SIZE = current + 2; $$.type = type_of_locals[$2] | TYPE_MOD_REFERENCE; }; | '&' '(' expr4 '[' expr0 ']' ')' %prec '~' { %line /* the ',' operator is reserved for indexing on multi-valued * mappings and other multi-dimensional data */ arrange_protected_lvalue($3.start, $3.code, $3.end, F_PROTECTED_INDEX_LVALUE - F_OFFSET ); $$.start = $3.start; $$.code = -1; if (!exact_types) { $$.type = TYPE_ANY | TYPE_MOD_REFERENCE; } else { int type; type = $3.type & TYPE_MOD_MASK; if (type & TYPE_MOD_POINTER) { $$.type = type & ~TYPE_MOD_POINTER; } else switch (type) { default: type_error("Bad type to indexed reference", type); case TYPE_ANY: #ifdef MAPPINGS case TYPE_MAPPING: $5.type = TYPE_ANY; #endif $$.type = TYPE_ANY | TYPE_MOD_REFERENCE; break; case TYPE_STRING: $$.type = TYPE_NUMBER | TYPE_MOD_REFERENCE; break; } if (!BASIC_TYPE($5.type, TYPE_NUMBER)) type_error("Bad type of index", $5.type); } }; | '&' '(' expr4 '[' '<' expr0 ']' ')' %prec '~' { %line arrange_protected_lvalue($3.start, $3.code, $3.end, F_PROTECTED_RINDEX_LVALUE - F_OFFSET ); $$.start = $3.start; $$.code = -1; if (!exact_types) { $$.type = TYPE_ANY | TYPE_MOD_REFERENCE; } else { int type; type = $3.type & TYPE_MOD_MASK; if (type & TYPE_MOD_POINTER) { $$.type = type & ~TYPE_MOD_POINTER; } else switch (type) { default: type_error("Bad type to indexed reference", type); case TYPE_ANY: #ifdef MAPPINGS case TYPE_MAPPING: $6.type = TYPE_ANY; #endif $$.type = TYPE_ANY | TYPE_MOD_REFERENCE; break; case TYPE_STRING: $$.type = TYPE_NUMBER | TYPE_MOD_REFERENCE; break; } if (!BASIC_TYPE($6.type, TYPE_NUMBER)) type_error("Bad type of index", $6.type); } }; %ifdef MAPPINGS | '&' '(' expr4 '[' expr0 ',' expr0 ']' ')' { %line $$.start = $3.start; $$.code = -1; $$.type = TYPE_ANY | TYPE_MOD_REFERENCE; ins_f_code(F_PUSH_PROTECTED_INDEXED_MAP_LVALUE); if (exact_types) { int type; type = $3.type & TYPE_MOD_MASK; if (type != TYPE_ANY && type != TYPE_MAPPING) { type_error("Bad type to indexed value", type); } type = $7.type & TYPE_MOD_MASK; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); } }; %endif /* MAPPINGS */ | '&' '(' expr4 '[' expr0 F_RANGE expr0 ']' ')' %prec '~' { %line arrange_protected_lvalue($3.start, $3.code, $3.end, F_PROTECTED_RANGE_LVALUE - F_OFFSET ); $$.start = $3.start; $$.code = -1; if (!exact_types) { $$.type = TYPE_ANY | TYPE_MOD_REFERENCE; } else { int type; $$.type = type = $3.type & TYPE_MOD_MASK; if ((type & TYPE_MOD_POINTER) == 0 && type != TYPE_ANY && type != TYPE_STRING) { type_error("Bad type of argument used for range", type); $$.type = TYPE_ANY; } type = $5.type & TYPE_MOD_MASK; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); type = $7.type & TYPE_MOD_MASK; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); } }; | '&' '(' expr4 '[' expr0 F_RANGE '<' expr0 ']' ')' %prec '~' { %line arrange_protected_lvalue($3.start, $3.code, $3.end, F_PROTECTED_NR_RANGE_LVALUE - F_OFFSET ); $$.start = $3.start; $$.code = -1; if (!exact_types) { $$.type = TYPE_ANY | TYPE_MOD_REFERENCE; } else { int type; $$.type = type = $3.type & TYPE_MOD_MASK; if ((type & TYPE_MOD_POINTER) == 0 && type != TYPE_ANY && type != TYPE_STRING) { type_error("Bad type of argument used for range", type); $$.type = TYPE_ANY; } type = $5.type & TYPE_MOD_MASK; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); type = $8.type & TYPE_MOD_MASK; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); } }; | '&' '(' expr4 '[' '<' expr0 F_RANGE expr0 ']' ')' %prec '~' { %line arrange_protected_lvalue($3.start, $3.code, $3.end, F_PROTECTED_RN_RANGE_LVALUE - F_OFFSET ); $$.start = $3.start; $$.code = -1; if (!exact_types) { $$.type = TYPE_ANY | TYPE_MOD_REFERENCE; } else { int type; $$.type = type = $3.type & TYPE_MOD_MASK; if ((type & TYPE_MOD_POINTER) == 0 && type != TYPE_ANY && type != TYPE_STRING) { type_error("Bad type of argument used for range", type); $$.type = TYPE_ANY; } type = $6.type & TYPE_MOD_MASK; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); type = $8.type & TYPE_MOD_MASK; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); } }; | '&' '(' expr4 '[' '<' expr0 F_RANGE '<' expr0 ']' ')' %prec '~' { %line arrange_protected_lvalue($3.start, $3.code, $3.end, F_PROTECTED_RR_RANGE_LVALUE - F_OFFSET ); $$.start = $3.start; $$.code = -1; if (!exact_types) { $$.type = TYPE_ANY | TYPE_MOD_REFERENCE; } else { int type; $$.type = type = $3.type & TYPE_MOD_MASK; if ((type & TYPE_MOD_POINTER) == 0 && type != TYPE_ANY && type != TYPE_STRING) { type_error("Bad type of argument used for range", type); $$.type = TYPE_ANY; } type = $6.type & TYPE_MOD_MASK; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); type = $9.type & TYPE_MOD_MASK; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); } }; %// The following expressions can be patched to lvalues for use in index_lvalue. | F_IDENTIFIER { int i; int current; char *p; %line i = verify_declared($1); $$.start = current = CURRENT_PROGRAM_SIZE; $$.end = 0; if (current + 2 > mem_block[A_PROGRAM].max_size) realloc_a_program(); p = mem_block[A_PROGRAM].block + current; if (i & VIRTUAL_VAR_TAG) { $$.code = F_PUSH_VIRTUAL_VARIABLE_LVALUE - F_OFFSET; *p++ = F_VIRTUAL_VARIABLE - F_OFFSET; *p = i; $$.type = V_VARIABLE(i)->flags & TYPE_MOD_MASK; } else { $$.code = F_PUSH_IDENTIFIER_LVALUE - F_OFFSET; *p++ = F_IDENTIFIER - F_OFFSET; *p = i + num_virtual_variables; $$.type = NV_VARIABLE(i)->flags & TYPE_MOD_MASK; } CURRENT_PROGRAM_SIZE = current + 2; if (i == -1) $$.type = TYPE_ANY; } | F_LOCAL { int current; char *p; %line $$.start = current = CURRENT_PROGRAM_SIZE; $$.code = F_PUSH_LOCAL_VARIABLE_LVALUE - F_OFFSET; $$.end = 0; if (current + 2 > mem_block[A_PROGRAM].max_size) realloc_a_program(); p = mem_block[A_PROGRAM].block + current; *p++ = F_LOCAL - F_OFFSET; *p = $1; CURRENT_PROGRAM_SIZE = current + 2; $$.type = type_of_locals[$1]; } | expr4 '[' expr0 ']' %prec '[' { %line /* the ',' operator is reserved for indexing on multi-valued * mappings and other multi-dimensional data */ $$.start = $1.start; $$.end = CURRENT_PROGRAM_SIZE; $$.code = F_PUSH_INDEXED_LVALUE - F_OFFSET; ins_f_byte(F_INDEX); if (exact_types) { int type; type = $1.type & TYPE_MOD_MASK; if (type & TYPE_MOD_POINTER) { $$.type = type & ~TYPE_MOD_POINTER; } else switch (type) { default: type_error("Bad type to indexed value", type); #ifdef MAPPINGS case TYPE_MAPPING: #endif case TYPE_ANY: $3.type = TYPE_ANY; $$.type = TYPE_ANY; break; case TYPE_STRING: $$.type = TYPE_NUMBER; break; } if (!BASIC_TYPE($3.type, TYPE_NUMBER)) type_error("Bad type of index", $3.type); } }; | expr4 '[' '<' expr0 ']' %prec '[' { %line $$.start = $1.start; $$.end = CURRENT_PROGRAM_SIZE; $$.code = F_PUSH_RINDEXED_LVALUE - F_OFFSET; ins_f_byte(F_RINDEX); if (exact_types) { int type; type = $1.type & TYPE_MOD_MASK; if (type & TYPE_MOD_POINTER) { $$.type = type & ~TYPE_MOD_POINTER; } else switch (type) { default: type_error("Bad type to indexed value", type); case TYPE_ANY: $$.type = TYPE_ANY; break; case TYPE_STRING: $$.type = TYPE_NUMBER; break; } if (!BASIC_TYPE($4.type, TYPE_NUMBER)) type_error("Bad type of index", $4.type); } }; %ifdef MAPPINGS | expr4 '[' expr0 ',' expr0 ']' %prec '[' { %line $$.start = $1.start; $$.end = CURRENT_PROGRAM_SIZE; $$.code = F_PUSH_INDEXED_MAP_LVALUE - F_OFFSET; $$.type = TYPE_ANY; ins_f_byte(F_MAP_INDEX); if (exact_types) { int type; type = $1.type & TYPE_MOD_MASK; if (type != TYPE_ANY && type != TYPE_MAPPING) { type_error("Bad type to indexed value", type); } type = $5.type & TYPE_MOD_MASK; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); } }; %endif /* MAPPINGS */ pre_inc_dec: F_INC { $$ = F_PRE_INC-F_OFFSET; } | F_DEC { $$ = F_PRE_DEC-F_OFFSET; } ; return: F_RETURN { if (exact_types && !BASIC_TYPE(exact_types & TYPE_MOD_MASK, TYPE_VOID)) type_error("Must return a value for a function declared", exact_types); ins_f_byte(F_RETURN0); } | F_RETURN comma_expr { %line if (exact_types) { if (!MASKED_TYPE($2.type, exact_types & TYPE_MOD_MASK)) type_error("Return type not matching", exact_types); /* if (exact_types & ~TYPE_MOD_POINTER) == TYPE_ANY , * a reference in $2.type remains undetected. */ } if ($2.type & TYPE_MOD_REFERENCE) { yyerror("May not return a reference"); } if (last_expression == CURRENT_PROGRAM_SIZE - 1 && mem_block[A_PROGRAM].block[last_expression] == F_CONST0 - F_OFFSET ) { mem_block[A_PROGRAM].block[last_expression] = F_RETURN0 - F_OFFSET; last_expression = -1; } else ins_f_byte(F_RETURN); }; expr_list: /* empty */ { $$ = 0; } | expr_list2 { $$ = $1; } | expr_list2 ',' { $$ = $1; } ; /* Allow a terminating comma */ expr_list2: expr0 { $$ = 1; add_arg_type($1.type); } | expr_list2 ',' expr0 { $$ = $1 + 1; add_arg_type($3.type); } ; expr_list3: /* empty */ { $$ = 0; } | expr0 { $$ = 1; add_arg_type($1.type); } | expr_list2 ',' expr0 { $$ = $1 + 1; add_arg_type($3.type); } ; %ifdef MAPPINGS m_expr_list: /* empty */ { $$[0] = 0; $$[1]= 1; } | m_expr_list2 /* { $$ = $1; } */ | m_expr_list2 ',' /* { $$ = $1; } Allow a terminating comma */ | expr_list2 { $$[0] = $1; $$[1] = 0; } ; | expr_list2 ',' { $$[0] = $1; $$[1] = 0; } ; m_expr_list2: expr0 m_expr_values { $$[0] = 1 + $2; $$[1] = $2; add_arg_type($1.type); /* order doesn't matter */ } | m_expr_list2 ',' expr0 m_expr_values { if ($1[1] != $4) { yyerror("Inconsistent number of values in mapping literal"); } $$[0] = $1[0] + 1 + $4; $$[1] = $1[1]; add_arg_type($3.type); } m_expr_values: ':' expr0 { $$ = 1; add_arg_type($2.type); } | m_expr_values ';' expr0 { $$ = $1 + 1; add_arg_type($3.type); } %endif /* MAPPINGS */ %ifndef INITIALIZATION_BY___INIT const_expr_list: /* empty */ { $$.length = 0; }; | const_expr_list2 { $$ = $1; } | const_expr_list2 ',' { $$ = $1; } ; const_expr_list2: { struct svalue *svp; struct const_list_svalue *clsv; %line clsv = (struct const_list_svalue *)xalloc(sizeof *clsv); svp = currently_initialized; svp->type = T_LVALUE; svp->u.lvalue = &clsv->head; clsv->head.type = T_ERROR_HANDLER; clsv->head.u.error_handler = free_const_list_svalue; clsv->list.next = 0; clsv->list.val.type = T_INVALID; currently_initialized = &clsv->list.val; $<const_list>$.l = &clsv->list; $<const_list>$.length = 1; } svalue_constant %ifdef YACC_CANNOT_MIX_ANONYMOUS_WITH_DEFAULT { $$ = $<const_list>1; } %endif | const_expr_list2 ',' { struct const_list *l; %line l = (struct const_list *)xalloc(sizeof (struct const_list)); l->next = 0; l->val.type = T_INVALID; currently_initialized = &l->val; $1.l->next = l; } svalue_constant { $$.l = $1.l->next; $$.length = $1.length+1; } const_expr_list3: /* empty */ { $$.length =0; $$.l = (struct const_list *)0; }; | const_expr_list2 { $$ = $1; } ; svalue_constant: constant { struct svalue *svp = currently_initialized; %line svp->type = T_NUMBER; svp->u.number = $1; } | string_constant { struct svalue *svp = currently_initialized; %line svp->type = T_STRING; svp->x.string_type = STRING_SHARED; svp->u.string = last_string_constant; last_string_constant = 0; } | F_SYMBOL { struct svalue *svp = currently_initialized; %line svp->type = T_SYMBOL; svp->x.quotes = $1.quotes; svp->u.string = $1.name; } | array_constant | F_QUOTED_AGGREGATE { $<initialized>$ = currently_initialized; } const_expr_list '}' ')' { struct svalue *svp = $<initialized>2; %line list_to_vector($3.length, svp); svp->type = T_QUOTED_ARRAY; svp->x.quotes = $1; } | float_constant { *currently_initialized = $1; } | constant_function_call | F_CLOSURE { int ix; struct svalue *svp = currently_initialized; %line ix = $1.number; svp->type = T_CLOSURE; if (ix < 0xf000) { struct lambda *l; l = (struct lambda *)xalloc( sizeof *l - sizeof l->function + sizeof l->function.index ); l->ref = 1; l->ob = current_object; l->function.index = ix; svp->u.lambda = l; svp->x.closure_type = CLOSURE_PRELIMINARY; } else { svp->x.closure_type = ix >= CLOSURE_SIMUL_EFUN_OFFS ? ix : (instrs[ix - CLOSURE_EFUN_OFFS].Default == -1 ? ix + CLOSURE_OPERATOR-CLOSURE_EFUN : ix); svp->u.ob = current_object; } add_ref(current_object, "closure"); } %ifdef MAPPINGS | '(' '[' ']' ')' { extern struct mapping *allocate_mapping PROT((int, int)); struct svalue *svp = currently_initialized; %line svp->type = T_MAPPING; svp->u.map = allocate_mapping(0, 1); } %endif ; array_constant: '(' '{' { $<initialized>$ = currently_initialized; } const_expr_list '}' ')' { %line list_to_vector($4.length, $<initialized>3); }; float_constant: F_FLOAT { %line STORE_DOUBLE_USED $$.type = T_FLOAT; STORE_DOUBLE(&$$, $1); } | '-' float_constant { %line STORE_DOUBLE_USED double d; d = -READ_DOUBLE(&$2); $$.type = T_FLOAT; STORE_DOUBLE(&$$, d); }; constant_function_call: F_IDENTIFIER { /* I_TYPE_UNKNOWN must not be overrun by annother one, so * evaluate the identifier now. */ /* we rely on the fact that $1.real->type is either * I_TYPE_UNKNOWN or I_TYPE_GLOBAL here. All others are filtered * by the lexical analysis. */ $<const_call_head>$.function = $1->u.global.efun; $<const_call_head>$.initialized = currently_initialized; if ($1->type == I_TYPE_UNKNOWN) { free_shared_identifier($1); $<number>$ = -1; } } '(' const_expr_list3 ')' { extern struct svalue const0; struct svalue *svp; struct const_list_svalue *list; %line svp = $<const_call_head>2.initialized; list = svp->u.const_list; switch($<const_call_head>2.function) { case F_ORDER_ALIST-F_OFFSET: { int i, listsize; struct vector *vec; if ($4.length == 1 && list->list.val.type == T_POINTER && (vec = list->list.val.u.vec)->size && vec->item[0].type == T_POINTER ) { xfree((char *)list); } else { vec = list_to_vector($4.length, svp); } if (listsize = vec->size && vec->item[0].type == T_POINTER) { int keynum = vec->item[0].u.vec->size; for (i = 0; i < vec->size; i++) { if (vec->item[i].type != T_POINTER || vec->item[i].u.vec->size != keynum) { yyerrorf("bad data array %d for alist", i); free_vector(vec); *svp = const0; break; } } } else { yyerror("missing argument for order_alist"); } if (listsize) { svp->type = T_POINTER; svp->u.vec = order_alist(vec->item, listsize, 1); } else { *svp = const0; } free_vector(vec); break; } default: yyerror("Illegal function call in initialization"); free_svalue(svp); *svp = const0; } }; %endif /* INITIALIZATION_BY___INIT */ catch: F_CATCH { $<number>$ = CURRENT_PROGRAM_SIZE; ins_f_byte(F_CATCH); ins_byte(0); } '(' comma_expr ')' { %line int start, offset; #if 1 ins_f_code(F_END_CATCH); #else ins_f_byte(F_POP_VALUE); ins_f_byte(F_RETURN); #endif start = $<number>2; offset = CURRENT_PROGRAM_SIZE - (start + 2); if (offset >= 0x100) { /* should happen seldom, but better handle it without error... */ int i; char *p; if (CURRENT_PROGRAM_SIZE + 5 > mem_block[A_PROGRAM].max_size) realloc_a_program(); CURRENT_PROGRAM_SIZE += 5; p = mem_block[A_PROGRAM].block + CURRENT_PROGRAM_SIZE - 1; for( i = offset; --i >= 0; --p ) *p = p[-5]; p[-5] = 2; p[-4] = F_BRANCH - F_OFFSET; p[-3] = 3; p[-2] = F_LBRANCH - F_OFFSET; upd_short(start + 5, offset+2); if (offset > 0x7ffd) yyerror("offset overflow"); } else { mem_block[A_PROGRAM].block[start+1] = offset; } $$.start = start; $$.type = TYPE_ANY; $$.code = -1; }; sscanf: F_SSCANF note_start '(' expr0 ',' expr0 lvalue_list ')' { ins_f_byte(F_SSCANF); ins_byte($7 + 2); $$.start = $2.start; $$.type = TYPE_NUMBER; $$.code = -1; } ; parse_command: F_PARSE_COMMAND note_start '(' expr0 ',' expr0 ',' expr0 lvalue_list ')' { ins_f_byte(F_PARSE_COMMAND); ins_byte($9 + 3); $$.start = $2.start; $$.type = TYPE_NUMBER; $$.code = -1; } ; lvalue_list: /* empty */ { $$ = 0; } | lvalue_list ',' F_IDENTIFIER { int i; %line $$ = 1 + $1; i = verify_declared($3); if (i & VIRTUAL_VAR_TAG) { ins_f_byte(F_PUSH_VIRTUAL_VARIABLE_LVALUE); ins_byte(i); } else { ins_f_byte(F_PUSH_IDENTIFIER_LVALUE); ins_byte(i + num_virtual_variables); } } | lvalue_list ',' F_LOCAL { %line $$ = 1 + $1; ins_f_byte(F_PUSH_LOCAL_VARIABLE_LVALUE); ins_byte($3); }; | lvalue_list ',' expr4 '[' expr0 ']' { %line $$ = 1 + $1; arrange_protected_lvalue($3.start, $3.code, $3.end, F_PROTECTED_INDEX_LVALUE - F_OFFSET ); if (exact_types) { int type; type = $3.type; if ( !(type & TYPE_MOD_POINTER) ) switch (type) { default: type_error("Bad type to indexed lvalue", type); case TYPE_ANY: #ifdef MAPPINGS case TYPE_MAPPING: $5.type = TYPE_ANY; #endif break; case TYPE_STRING: break; } if (!BASIC_TYPE($5.type, TYPE_NUMBER)) type_error("Bad type of index", $5.type); } }; | lvalue_list ',' expr4 '[' '<' expr0 ']' { %line $$ = 1 + $1; arrange_protected_lvalue($3.start, $3.code, $3.end, F_PROTECTED_RINDEX_LVALUE - F_OFFSET ); if (exact_types) { int type; type = $3.type; if ( !(type & TYPE_MOD_POINTER) ) switch (type) { default: type_error("Bad type to indexed lvalue", type); case TYPE_ANY: #ifdef MAPPINGS case TYPE_MAPPING: $6.type = TYPE_ANY; #endif break; case TYPE_STRING: break; } if (!BASIC_TYPE($6.type, TYPE_NUMBER)) type_error("Bad type of index", $6.type); } }; %ifdef MAPPINGS | lvalue_list ',' expr4 '[' expr0 ',' expr0 ']' { %line $$ = 1 + $1; ins_f_code(F_PUSH_PROTECTED_INDEXED_MAP_LVALUE); if (exact_types) { int type; type = $3.type; if (type != TYPE_ANY && type != TYPE_MAPPING) { type_error("Bad type to indexed value", type); } type = $7.type; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); } }; %endif /* MAPPINGS */ | lvalue_list ',' expr4 '[' expr0 F_RANGE ']' { %line $$ = 1 + $1; arrange_protected_lvalue($3.start, $3.code, $3.end, F_PROTECTED_EXTRACT_LVALUE - F_OFFSET ); if (exact_types) { int type; type = $3.type & TYPE_MOD_MASK; if ((type & TYPE_MOD_POINTER) == 0 && type != TYPE_ANY && type != TYPE_STRING) { type_error("Bad type of argument used for range", type); } type = $5.type; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); } }; | lvalue_list ',' expr4 '[' expr0 F_RANGE expr0 ']' { %line $$ = 1 + $1; arrange_protected_lvalue($3.start, $3.code, $3.end, F_PROTECTED_RANGE_LVALUE - F_OFFSET ); if (exact_types) { int type; type = $3.type; if ((type & TYPE_MOD_POINTER) == 0 && type != TYPE_ANY && type != TYPE_STRING) { type_error("Bad type of argument used for range", type); } type = $5.type; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); type = $7.type; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); } }; | lvalue_list ',' expr4 '[' expr0 F_RANGE '<' expr0 ']' { %line $$ = 1 + $1; arrange_protected_lvalue($3.start, $3.code, $3.end, F_PROTECTED_NR_RANGE_LVALUE - F_OFFSET ); if (exact_types) { int type; type = $3.type; if ((type & TYPE_MOD_POINTER) == 0 && type != TYPE_ANY && type != TYPE_STRING) { type_error("Bad type of argument used for range", type); } type = $5.type; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); type = $8.type; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); } }; | lvalue_list ',' expr4 '[' '<' expr0 F_RANGE expr0 ']' { %line $$ = 1 + $1; arrange_protected_lvalue($3.start, $3.code, $3.end, F_PROTECTED_RN_RANGE_LVALUE - F_OFFSET ); if (exact_types) { int type; type = $3.type; if ((type & TYPE_MOD_POINTER) == 0 && type != TYPE_ANY && type != TYPE_STRING) { type_error("Bad type of argument used for range", type); } type = $6.type; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); type = $8.type; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); } }; | lvalue_list ',' expr4 '[' '<' expr0 F_RANGE '<' expr0 ']' { %line $$ = 1 + $1; arrange_protected_lvalue($3.start, $3.code, $3.end, F_PROTECTED_RR_RANGE_LVALUE - F_OFFSET ); if (exact_types) { int type; type = $3.type; if ((type & TYPE_MOD_POINTER) == 0 && type != TYPE_ANY && type != TYPE_STRING) { type_error("Bad type of argument used for range", type); } type = $6.type; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); type = $9.type; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); } }; lvalue: F_IDENTIFIER { int i; %line i = verify_declared($1); if (i & VIRTUAL_VAR_TAG) { $$.u.simple[0] = F_PUSH_VIRTUAL_VARIABLE_LVALUE - F_OFFSET; $$.u.simple[1] = i; $$.type = V_VARIABLE(i)->flags & TYPE_MOD_MASK; } else { $$.u.simple[0] = F_PUSH_IDENTIFIER_LVALUE - F_OFFSET; $$.u.simple[1] = i + num_virtual_variables; $$.type = NV_VARIABLE(i)->flags & TYPE_MOD_MASK; } $$.length = 0; if (i == -1) $$.type = TYPE_ANY; } | F_LOCAL { %line $$.u.simple[0] = F_PUSH_LOCAL_VARIABLE_LVALUE - F_OFFSET; $$.u.simple[1] = $1; $$.length = 0; $$.type = type_of_locals[$1]; } | expr4 '[' expr0 ']' %prec '[' %// the ',' operator is reserved for indexing on multi-valued %// mappings and other multi-dimensional data { char *p, *q; int start, current; %line start = $1.start; current = CURRENT_PROGRAM_SIZE; p = mem_block[A_PROGRAM].block; q = yalloc(current-start+2); /* assign uses an extra byte */ if ($1.code >= 0) { int end, start2; if (end = $1.end) { start2 = end+1; p[end] = $1.code; memcpy(q, p + start2, current - start2); memcpy(q + current - start2, p + start, start2 - start); q[current - start] = F_INDEX_LVALUE - F_OFFSET; } else { char c; start2 = start + 2; c = p[start+1]; memcpy(q, p + start2, current - start2); p = q + current - start2; *p++ = $1.code; *p++ = c; *p = F_INDEX_LVALUE - F_OFFSET; } } else { memcpy(q, p + start, current - start); q[current - start] = F_PUSH_INDEXED_LVALUE - F_OFFSET; } $$.length = current + 1 - start; $$.u.p = q; CURRENT_PROGRAM_SIZE = start; last_expression = -1; if (exact_types) { int type; type = $1.type; if (type & TYPE_MOD_POINTER) { $$.type = type & ~TYPE_MOD_POINTER; } else switch (type) { default: type_error("Bad type to indexed lvalue", type); #ifdef MAPPINGS case TYPE_MAPPING: #endif case TYPE_ANY: $3.type = TYPE_ANY; $$.type = TYPE_ANY; break; case TYPE_STRING: $$.type = TYPE_NUMBER; break; } if (!BASIC_TYPE($3.type, TYPE_NUMBER)) type_error("Bad type of index", $3.type); } }; | expr4 '[' '<' expr0 ']' %prec '[' { char *p, *q; int start, current; %line start = $1.start; current = CURRENT_PROGRAM_SIZE; p = mem_block[A_PROGRAM].block; q = yalloc(current-start+2); /* assign uses an extra byte */ if ($1.code >= 0) { int end, start2; if (end = $1.end) { start2 = end+1; p[end] = $1.code; memcpy(q, p + start2, current - start2); memcpy(q + current - start2, p + start, start2 - start); q[current - start] = F_RINDEX_LVALUE - F_OFFSET; } else { char c; start2 = start + 2; c = p[start+1]; memcpy(q, p + start2, current - start2); p = q + current - start2; *p++ = $1.code; *p++ = c; *p = F_RINDEX_LVALUE - F_OFFSET; } } else { memcpy(q, p + start, current - start); q[current - start] = F_PUSH_RINDEXED_LVALUE - F_OFFSET; } $$.length = current + 1 - start; $$.u.p = q; CURRENT_PROGRAM_SIZE = start; last_expression = -1; if (exact_types) { int type; type = $1.type; if (type & TYPE_MOD_POINTER) { $$.type = type & ~TYPE_MOD_POINTER; } else switch (type) { default: type_error("Bad type to indexed lvalue", type); case TYPE_ANY: $$.type = TYPE_ANY; break; case TYPE_STRING: $$.type = TYPE_NUMBER; break; } if (!BASIC_TYPE($4.type, TYPE_NUMBER)) type_error("Bad type of index", $4.type); } }; %ifdef MAPPINGS | expr4 '[' expr0 ',' expr0 ']' %prec '[' { char *p, *q; int start, current; %line start = $1.start; current = CURRENT_PROGRAM_SIZE; p = mem_block[A_PROGRAM].block; q = yalloc(current-start+2); /* assign uses an extra byte */ memcpy(q, p + start, current - start); q[current - start] = F_PUSH_INDEXED_MAP_LVALUE - F_OFFSET; $$.length = current + 1 - start; $$.u.p = q; $$.type = TYPE_ANY; CURRENT_PROGRAM_SIZE = start; last_expression = -1; if (exact_types) { int type; type = $1.type; if (type != TYPE_ANY && type != TYPE_MAPPING) { type_error("Bad type to indexed value", type); } type = $5.type; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); } }; %endif /* MAPPINGS */ | expr4 '[' expr0 F_RANGE ']' %prec '[' { %line indexing_argument = $1; indexing_index1 = $3; indexing_index2.type = TYPE_ANY; indexing_code = F_EXTRACT_LVALUE - F_OFFSET; goto range_lvalue_indexing; }; | expr4 '[' '<' expr0 F_RANGE ']' %prec '[' { %line if (CURRENT_PROGRAM_SIZE - last_expression == 2 && mem_block[A_PROGRAM].block[last_expression] == F_CLIT - F_OFFSET ) { mem_block[A_PROGRAM].block[last_expression] = F_NCLIT - F_OFFSET; } else { ins_f_byte(F_NEGATE); } indexing_argument = $1; indexing_index1 = $4; indexing_index2.type = TYPE_ANY; indexing_code = F_EXTRACT_LVALUE - F_OFFSET; goto range_lvalue_indexing; }; | expr4 '[' expr0 F_RANGE expr0 ']' %prec '[' { char *p, *q; int start, current; %line indexing_argument = $1; indexing_index1 = $3; indexing_index2 = $5; indexing_code = F_RANGE_LVALUE - F_OFFSET; range_lvalue_indexing: start = indexing_argument.start; current = CURRENT_PROGRAM_SIZE; p = mem_block[A_PROGRAM].block; q = yalloc(current-start+3); if (indexing_argument.code < 0) { yyerror("Need lvalue for range lvalue."); } else { int end, start2; if (end = indexing_argument.end) { start2 = end+1; p[end] = indexing_argument.code; } else { start2 = start+2; p[start] = indexing_argument.code; } memcpy(q, p + start2, current - start2); memcpy(q + current - start2, p + start, start2 - start); current -= start; if (indexing_code > 0xff) { q[current++] = F_ESCAPE - F_OFFSET; } q[current] = indexing_code; } $$.length = current + 1; $$.u.p = q; CURRENT_PROGRAM_SIZE = start; last_expression = -1; if (exact_types) { int type; $$.type = type = indexing_argument.type; if ((type & TYPE_MOD_POINTER) == 0 && type != TYPE_ANY && type != TYPE_STRING) { type_error("Bad type of argument used for range", type); $$.type = TYPE_ANY; } type = indexing_index1.type; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); type = indexing_index2.type; if (type != TYPE_ANY && type != TYPE_NUMBER) type_error("Bad type of index", type); } }; | expr4 '[' expr0 F_RANGE '<' expr0 ']' %prec '[' { %line indexing_argument = $1; indexing_index1 = $3; indexing_index2 = $6; indexing_code = F_NR_RANGE_LVALUE - F_OFFSET; goto range_lvalue_indexing; }; | expr4 '[' '<' expr0 F_RANGE expr0 ']' %prec '[' { %line indexing_argument = $1; indexing_index1 = $4; indexing_index2 = $6; indexing_code = F_RN_RANGE_LVALUE - F_OFFSET; goto range_lvalue_indexing; }; | expr4 '[' '<' expr0 F_RANGE '<' expr0 ']' %prec '[' { %line indexing_argument = $1; indexing_index1 = $4; indexing_index2 = $7; indexing_code = F_RR_RANGE_LVALUE - F_OFFSET; goto range_lvalue_indexing; }; string_constant: F_STRING { last_string_constant = last_lex_string; last_lex_string = 0; } | string_constant '+' F_STRING { add_string_constant(); } | F_STRING F_STRING { fatal("presence of rule should prevent its reduction"); } | string_constant '+' F_STRING F_STRING { fatal("presence of rule should prevent its reduction"); } ; function_call: function_name { %line /* This seems to be an ordinary function call. But, if the function * is not defined, then it might be a call to a simul_efun. * If it is, then we make it a call_other(), which requires the * function name as argument. * We have to remember until after parsing the arguments if it was * a simulated efun or not, which means that the pointer has to be * pushed on a stack. Use the internal yacc stack for this purpose. */ struct ident *real_name; $<function_call_head>$.start = CURRENT_PROGRAM_SIZE; $<function_call_head>$.simul_efun = -1; real_name = $1.real; /* we rely on the fact that $1.real->type is either * I_TYPE_UNKNOWN or I_TYPE_GLOBAL here. All others are filtered * by the lexical analysis. */ if (real_name->type == I_TYPE_UNKNOWN) { /* prevent freeing by exotic name clashes */ /* also makes life easyer below */ real_name->type = I_TYPE_GLOBAL; real_name->u.global.function = -1; real_name->u.global.variable = -1; real_name->u.global.efun = -1; real_name->u.global.sim_efun = -1; real_name->next_all = all_globals; all_globals = real_name; } else if (!$1.super && real_name->u.global.function < 0 && real_name->u.global.sim_efun >= 0) { if ( ($<function_call_head>$.simul_efun = real_name->u.global.sim_efun) & ~0xff) { PREPARE_S_INSERT(6) char *p = real_name->name; increment_string_ref(p); add_f_byte(F_STRING); add_short(store_prog_string( make_shared_string(query_simul_efun_file_name()))); add_f_byte(F_STRING); add_short(store_prog_string(p)); CURRENT_PROGRAM_SIZE += 6; } } } '(' expr_list3 ')' { %line PREPARE_S_INSERT(6) int f; unsigned short *arg_types; int first_arg; int efun_override = $1.super && strcmp($1.super, "efun") == 0; int simul_efun; $$.start = $<function_call_head>2.start; $$.code = -1; if ( (simul_efun = $<function_call_head>2.simul_efun) >= 0) { extern struct function *simul_efunp; struct function *funp; funp = &simul_efunp[simul_efun]; if ($4 > funp->num_arg) yyerrorf("Too many arguments to simul_efun %s", funp->name); if (simul_efun & ~0xff) { add_f_byte(F_CALL_OTHER); add_byte($4 + 2); CURRENT_PROGRAM_SIZE += 2; } else { if (funp->num_arg != 0xff) { int i; i = funp->num_arg - $4; if (i > 4 && CURRENT_PROGRAM_SIZE + i + 2 > mem_block[A_PROGRAM].max_size) { realloc_a_program(); } CURRENT_PROGRAM_SIZE += i; while ( --i >= 0 ) { add_f_byte(F_CONST0); } } add_f_byte(F_SIMUL_EFUN); add_byte(simul_efun); if (funp->num_arg == 0xff) { add_byte($4); CURRENT_PROGRAM_SIZE += 3; } else CURRENT_PROGRAM_SIZE += 2; } $$.type = funp->type & TYPE_MOD_MASK; } else if ($1.super?!efun_override:(f=defined_function($1.real)) >= 0) { struct function *funp; if ($1.super) { struct program *super_prog; int ix; static struct function dummy; ix = insert_inherited( $1.super, $1.real->name, &super_prog, &dummy, $4, __PREPARE_INSERT__p ); if ($1.real->type == I_TYPE_UNKNOWN) { free_shared_identifier($1.real); } if (ix < 0) { yyerror("function not defined by inheritance as specified"); $$.type = TYPE_ANY; if ($1.super) yfree($1.super); pop_arg_stack($4); /* Argument types not needed more */ break; } arg_types = super_prog->argument_types; first_arg = !arg_types ? INDEX_START_NONE : super_prog->type_start[ix]; CURRENT_PROGRAM_SIZE += 6; funp = &dummy; } else { add_f_byte(F_CALL_FUNCTION_BY_ADDRESS); add_short(f); funp = FUNCTION(f); arg_types = (unsigned short *) mem_block[A_ARGUMENT_TYPES].block; first_arg = ((unsigned short *)mem_block[A_ARGUMENT_INDEX].block)[f]; add_byte($4); /* Actual number of arguments */ CURRENT_PROGRAM_SIZE += 4; } /* * Verify that the function has been defined already. */ if ((funp->flags & NAME_UNDEFINED) && !(funp->flags & (NAME_PROTOTYPE|NAME_INHERITED)) && exact_types) { yyerrorf("Function %.50s undefined", funp->name); } $$.type = funp->type & TYPE_MOD_MASK; /* * Check number of arguments. */ if (funp->num_arg != $4 && !(funp->flags & TYPE_MOD_VARARGS) && (first_arg != INDEX_START_NONE) && exact_types) { yyerrorf("Wrong number of arguments to %.60s", $1.real->name); } /* * Check the argument types. */ if (exact_types && first_arg != INDEX_START_NONE) { int i; unsigned short *argp; int num_arg, anum_arg; if (num_arg = funp->num_arg) { if (num_arg > (anum_arg = $4) ) num_arg = anum_arg; arg_types += first_arg; argp = get_argument_types_start(anum_arg); for (i = num_arg; --i >= 0; ) { int tmp1, tmp2; tmp1 = *argp++ & TYPE_MOD_RMASK; tmp2 = *arg_types++ & TYPE_MOD_MASK; if (!MASKED_TYPE(tmp1, tmp2)) { yyerrorf("Bad type for argument %d of %s %s", anum_arg - i, funp->name, get_two_types(tmp2, tmp1)); } } } } } else if ( (f = lookup_predef($1.real)) != -1 ) { int min, max, def, *argp, num_arg; extern int efun_arg_types[]; { int f2; min = instrs[f].min_arg; max = instrs[f].max_arg; def = instrs[f].Default; $$.type = instrs[f].ret_type; argp = &efun_arg_types[instrs[f].arg_index]; num_arg = $4; if (def && num_arg == min-1) { add_f_byte(def); CURRENT_PROGRAM_SIZE++; max--; min--; } else if (num_arg < min && ( (f2 = proxy_efun(f, num_arg)) < 0 || (f = f2,MY_FALSE) ) ) { yyerrorf("Too few arguments to %s", instrs[f].name); } else if (num_arg > max && max != -1) { yyerrorf("Too many arguments to %s", instrs[f].name); num_arg = max; } if (max != -1 && exact_types && num_arg) { /* * Now check all types of the arguments to efuns. */ int argn; unsigned short *aargp; aargp = get_argument_types_start(num_arg); for (argn=0; argn < num_arg; argn++) { int tmp1, tmp2; tmp1 = *aargp++ & TYPE_MOD_MASK; for (;;) { if ( !(tmp2 = *argp) ) { yyerrorf("Bad argument %d type to efun %s()", argn+1, instrs[f].name); break; } argp++; /* break if types are compatible; take care to * handle references correctly */ if (tmp1 == tmp2) break; if ((tmp1 & ~(TYPE_MOD_POINTER|TYPE_MOD_REFERENCE)) == TYPE_ANY) { if (tmp1 & TYPE_MOD_POINTER & ~tmp2) { if ((tmp2 & ~TYPE_MOD_REFERENCE) != TYPE_ANY) { continue; } } if ( !( (tmp1 ^ tmp2) & TYPE_MOD_REFERENCE) ) break; } else if ( (tmp2 & ~(TYPE_MOD_POINTER|TYPE_MOD_REFERENCE)) == TYPE_ANY) { if (tmp2 & TYPE_MOD_POINTER & ~tmp1) continue; if ( !( (tmp1 ^ tmp2) & TYPE_MOD_REFERENCE) ) break; } } /* end for */ while(*argp++); } } if (f > 255) { switch(0) { default: if (f > LAST_INSTRUCTION_CODE) { f = efun_aliases[f-LAST_INSTRUCTION_CODE-1]; if (f <= 255) break; } add_f_byte(F_ESCAPE); CURRENT_PROGRAM_SIZE++; } } add_byte(f); CURRENT_PROGRAM_SIZE++; /* Only store number of arguments for instructions * that allowed a variable number. */ if (max != min) { add_byte($4);/* Number of actual arguments */ CURRENT_PROGRAM_SIZE++; } if ( instrs[f].ret_type == TYPE_VOID ) { last_expression = mem_block[A_PROGRAM].current_size; add_f_byte(F_CONST0); CURRENT_PROGRAM_SIZE++; } } } else if (efun_override) { yyerrorf("Unknown efun: %s", $1.real->name); } else { struct function *funp; f = define_new_function( $1.real, 0, 0, 0, NAME_UNDEFINED, TYPE_UNKNOWN ); add_f_byte(F_CALL_FUNCTION_BY_ADDRESS); add_short(f); add_byte($4); /* Number of actual arguments */ CURRENT_PROGRAM_SIZE += 4; funp = FUNCTION(f); #if 0 if (strchr($1, ':')) { /* * A function defined by inheritance. Find * real definition immediately. */ find_inherited(funp); } #endif /* * Check if this function has been defined. * But, don't complain yet about functions defined * by inheritance. */ if (exact_types && (funp->flags & NAME_UNDEFINED)) { yyerrorf("Undefined function %.50s", $1.real->name); } if (!(funp->flags & NAME_UNDEFINED)) $$.type = funp->type; else $$.type = TYPE_ANY; /* Just a guess */ } if ($1.super) yfree($1.super); pop_arg_stack($4); /* Argument types not needed more */ } | expr4 F_ARROW function_name %prec F_ARROW { %line int string_number; char *p = $3.real->name; increment_string_ref(p); if ($3.real->type == I_TYPE_UNKNOWN) free_shared_identifier($3.real); if ($3.super) { yfree($3.super); yyerror("inherited function may not be called by call_other"); } string_number = store_prog_string(p); if ( string_number <= 0x0ff ) { ins_f_byte(F_CSTRING0); ins_byte(string_number); } else if ( string_number <= 0x1ff ) { ins_f_byte(F_CSTRING1); ins_byte(string_number); } else if ( string_number <= 0x2ff ) { ins_f_byte(F_CSTRING2); ins_byte(string_number); } else if ( string_number <= 0x3ff ) { ins_f_byte(F_CSTRING3); ins_byte(string_number); } else { ins_f_byte(F_STRING); ins_short(string_number); } } '(' expr_list3 ')' { ins_f_byte(F_CALL_OTHER); ins_byte($6 + 2); $$.type = instrs[F_CALL_OTHER-F_OFFSET].ret_type; $$.code = -1; $$.start = $1.start; pop_arg_stack($6); /* No good need of these arguments */ }; anchestor: F_IDENTIFIER { $$ = ystring_copy($1->name); if ($1->type == I_TYPE_UNKNOWN) free_shared_identifier($1); } | F_STRING F_STRING { fatal("presence of rule should prevent its reduction"); } | F_STRING { $$ = ystring_copy(last_lex_string); free_string(last_lex_string); last_lex_string = 0; }; function_name: F_IDENTIFIER { $$.super = 0; $$.real = $1; } | F_COLON_COLON F_IDENTIFIER { *($$.super = yalloc(1)) = '\0'; $$.real = $2; } | anchestor F_COLON_COLON F_IDENTIFIER { extern struct function *simul_efunp; extern struct object *master_ob; %line if ( !strcmp($1, "efun") && $3->type == I_TYPE_GLOBAL && $3->u.global.sim_efun >= 0 && simul_efunp[$3->u.global.sim_efun].flags & TYPE_MOD_NO_MASK && master_ob ) { struct svalue *res; push_constant_string("nomask simul_efun"); push_volatile_string(current_file); push_volatile_string($3->name); res = apply_master_ob("privilege_violation", 3); if (!res || res->type != T_NUMBER || res->u.number < 0) { yyerrorf( "Privilege violation: nomask simul_efun %s", $3->name ); yfree($1); $$.super = 0; } else if (!res->u.number) { yfree($1); $$.super = 0; } else { $$.super = $1; } } else $$.super = $1; $$.real = $3; }; condStart: F_IF '(' comma_expr ')' { int current; char *current_code; $$[0] = current_break_address; /* don't place labels to enter the inner part of an if */ current_break_address &= ~CASE_LABELS_ENABLED; current = CURRENT_PROGRAM_SIZE; if (current + 2 > mem_block[A_PROGRAM].max_size) realloc_a_program(); current_code = mem_block[A_PROGRAM].block + current; if (last_expression == current - 1 && current_code[-1] == F_NOT - F_OFFSET) { current_code[-1] = F_BRANCH_WHEN_NON_ZERO - F_OFFSET; } else { *current_code = F_BRANCH_WHEN_ZERO - F_OFFSET; current++; } $$[1] = current; CURRENT_PROGRAM_SIZE = current + 1; } ; cond: condStart statement optional_else { int destination, location, offset; destination = $3; location = $1[1]; if ( (offset = destination - location) > 0x100) { FIX_BRANCH( mem_block[A_PROGRAM].block[location-1] == F_BRANCH_WHEN_ZERO - F_OFFSET ? F_LBRANCH_WHEN_ZERO : F_LBRANCH_WHEN_NON_ZERO , destination, location ); } else { mem_block[A_PROGRAM].block[location] = offset - 1; } current_break_address |= $1[0] & CASE_LABELS_ENABLED; }; optional_else: /* empty */ { $$=mem_block[A_PROGRAM].current_size; } | F_ELSE { ins_f_byte(F_BRANCH); $<number>$ = CURRENT_PROGRAM_SIZE; ins_byte(0); } statement { $$ = FIX_BRANCH( F_LBRANCH, CURRENT_PROGRAM_SIZE, $<number>2); $$ += $<number>2 + 1; }; %% %line %ifdef INITIALIZATION_BY___INIT /* * Add a trailing jump after the last initialization code. */ void add_new_init_jump() { /* * Add a new jump. */ ins_f_byte(F_JUMP); last_initializer_end = mem_block[A_PROGRAM].current_size; ins_short(0); } %endif /* INITIALIZATION_BY___INIT */ static void arrange_protected_lvalue(start, code, end, newcode) int start, code, end, newcode; { int current; char *p; current = CURRENT_PROGRAM_SIZE; if (code >= 0) { if (end) { int length; char *q; length = end - start; /* This does not include the indexing code.*/ if (current+length > mem_block[A_PROGRAM].max_size) realloc_a_program(); p = mem_block[A_PROGRAM].block; memcpy(p + current, p + start, length); p += start; q = p + length + 1; length = current - start; for( ; --length >= 0; ) *p++ = *q++; switch(code) { case F_PUSH_INDEXED_LVALUE - F_OFFSET: code = F_PUSH_PROTECTED_INDEXED_LVALUE - F_OFFSET; break; case F_PUSH_RINDEXED_LVALUE - F_OFFSET: code = F_PUSH_PROTECTED_RINDEXED_LVALUE - F_OFFSET; break; case F_PUSH_INDEXED_MAP_LVALUE - F_OFFSET: code = F_PUSH_PROTECTED_INDEXED_MAP_LVALUE - F_OFFSET; break; #ifdef DEBUG default: fatal("Unexpected lvalue code\n"); #endif } --p; *p++ = F_ESCAPE - F_OFFSET; *p++ = code; *p++ = F_ESCAPE - F_OFFSET; *p = newcode; current++; } else { int i; int length; if (current + 2 > mem_block[A_PROGRAM].max_size) realloc_a_program(); p = mem_block[A_PROGRAM].block + start; i = p[1]; length = current - start - 2; for( ; --length >= 0; p++) *p = p[2]; *p++ = code; *p++ = i; *p++ = F_ESCAPE - F_OFFSET; *p = newcode; } } else { switch(newcode) { case F_PROTECTED_INDEX_LVALUE - F_OFFSET: newcode = F_PUSH_PROTECTED_INDEXED_LVALUE - F_OFFSET; break; case F_PROTECTED_RINDEX_LVALUE - F_OFFSET: newcode = F_PUSH_PROTECTED_RINDEXED_LVALUE - F_OFFSET; break; default: yyerror("Need lvalue for range lvalue."); } if (current + 2 > mem_block[A_PROGRAM].max_size) realloc_a_program(); p = mem_block[A_PROGRAM].block + start; *p++ = F_ESCAPE - F_OFFSET; *p = newcode; } CURRENT_PROGRAM_SIZE = current + 2; } void epilog() { extern int current_time; int size, i; mp_int num_functions, num_strings, num_variables; char *p; struct ident *g,*q; struct function *f; mp_int num_function_names; struct function *funname_start1, *funname_start2, **link1, **link2; struct program *prog; #ifdef DEBUG if (num_parse_error == 0 && type_of_arguments.current_size != 0) fatal("Failed to deallocate argument type stack\n"); #endif if (last_string_constant) { free_string(last_string_constant); last_string_constant = 0; } add_to_mem_block( A_VIRTUAL_VAR, mem_block[A_VARIABLES].block, mem_block[A_VARIABLES].current_size ); mem_block[A_VARIABLES].current_size = 0; %ifndef INITIALIZATION_BY___INIT add_to_mem_block( A_VIRTUAL_VAR_VALUES, mem_block[A_VARIABLE_VALUES].block, mem_block[A_VARIABLE_VALUES].current_size ); mem_block[A_VARIABLE_VALUES].current_size = 0; %else /* * Define the __INIT function, but only if there was any code * to initialize. */ if (last_initializer_end > 0) { struct ident *ip; ip = make_shared_identifier("__INIT", I_TYPE_UNKNOWN); switch (0) { default: if (!ip) { yyerror("Out of memory"); break; } if (ip->type > I_TYPE_GLOBAL) { /* sigh. can't people keep from such #defines? */ do { q = ip; ip = ip->inferior; } while (ip && ip->type > I_TYPE_GLOBAL); if (!ip) { ip = (struct ident *)xalloc(sizeof(struct ident)); if (!ip) { yyerror("Out of memory"); break; } ip->name = q->name; ip->type = I_TYPE_UNKNOWN; ip->inferior = 0; ip->hash = q->hash; q->inferior = ip; } } define_new_function(ip, 0, 0, first_initializer_start, 0, 0); } /* ref count for ip->name was incremented by transfer_init_control() */ /* * Change the last jump after the last initializer into a * return(1) statement. */ mem_block[A_PROGRAM].block[last_initializer_end-1] = F_CONST1 - F_OFFSET; mem_block[A_PROGRAM].block[last_initializer_end-0] = F_RETURN - F_OFFSET; } %endif /* INITIALIZATION_BY___INIT */ if (mem_block[A_STRINGS].current_size > 0x10000 * sizeof (char *)) yyerror("Too many strings"); while(mem_block[A_INCLUDE_NAMES].current_size) { add_to_mem_block( A_STRINGS, mem_block[A_INCLUDE_NAMES].block + (mem_block[A_INCLUDE_NAMES].current_size -= sizeof(char *)), sizeof(char*) ); } num_functions = mem_block[A_FUNCTIONS].current_size / sizeof (struct function); if (num_functions > 0x10000) { yyerror("Too many functions"); } num_strings = mem_block[A_STRINGS].current_size / sizeof (char *); num_variables = mem_block[A_VIRTUAL_VAR].current_size / sizeof (struct variable); if (num_variables > 0x100) { yyerror("Too many variables"); } f = (struct function *)mem_block[A_FUNCTIONS].block; link1 = &funname_start2; link2 = &funname_start1; num_function_names = 0; /* Save the time to fill in undefined functions & to sort functions * if there was an error or unresolved inheritance. */ if (!num_parse_error && !inherit_file) { for (i = num_functions; --i >= 0; f++) { uint32 flags; if ( f->flags & NAME_CROSS_DEFINED ) { int32 offset; offset = f->offset.func - (INHERIT_MASK + 1 >> 1); while (f[offset].flags & NAME_CROSS_DEFINED) { offset = (f->offset.func = offset + f[offset].offset.func) - (INHERIT_MASK + 1 >> 1); } } if ((f->flags & (NAME_UNDEFINED|NAME_INHERITED)) == NAME_UNDEFINED) { if (CURRENT_PROGRAM_SIZE + sizeof f->name + 5 > mem_block[A_PROGRAM].max_size) { realloc_a_program(); } increment_string_ref(f->name); f->offset.pc = CURRENT_PROGRAM_SIZE + sizeof f->name + 1; p = mem_block[A_PROGRAM].block + CURRENT_PROGRAM_SIZE; memcpy(p, (char *)&f->name, sizeof f->name); p += sizeof f->name; *p++ = f->type; *p++ = f->num_arg; *p++ = f->num_local; *p++ = F_ESCAPE-F_OFFSET; *p = F_UNDEF-F_OFFSET-0x100; CURRENT_PROGRAM_SIZE += sizeof f->name + 5; } flags = f->flags; f->flags = flags & NAME_INHERITED ? (flags & ~INHERIT_MASK) | (f->offset.inherit & INHERIT_MASK) : (flags & ~FUNSTART_MASK) | (f->offset.pc & FUNSTART_MASK); if ( !(flags & (NAME_HIDDEN|NAME_UNDEFINED) ) ) { *link1 = f; link1 = link2; link2 = &f->offset.next; num_function_names++; } } *link1 = 0; *link2 = 0; /* Store line number info for undefined functions */ store_line_number_info(); if (num_function_names <= 1) { funname_start1 = funname_start2; } else { int runlength; runlength = 1; do { struct function *out_start1, *out_start2, **out1, **out2; int count1, count2; count1 = num_function_names & runlength-1; count2 = num_function_names & runlength; if (!count1) { out2 = &out_start1; *out2 = funname_start2; while (--count2 >= 0) { out2 = &(*out2)->offset.next; } funname_start2 = *out2; count1 = count2 = runlength; out1 = &out_start2; } else if (!count2) { out2 = &out_start1; *out2 = funname_start1; do { out2 = &(*out2)->offset.next; } while (--count1); funname_start1 = *out2; count1 = count2 = runlength; out1 = &out_start2; } else { out1 = &out_start1; out2 = &out_start2; } while (funname_start1) { while (1) { /* must use memcmp(), because it is used later for the * program. byteorder is non-portable. */ if (memcmp( &funname_start2->name, &funname_start1->name, sizeof(char *) ) < 0) { *out1 = funname_start2; out1 = &funname_start2->offset.next; funname_start2 = *out1; if (!--count2) { *out1 = funname_start1; do { out1 = &(*out1)->offset.next; } while (--count1); funname_start1 = *out1; break; } } else { *out1 = funname_start1; out1 = &funname_start1->offset.next; funname_start1 = *out1; if (!--count1) { *out1 = funname_start2; do { out1 = &(*out1)->offset.next; } while (--count2); funname_start2 = *out1; break; } } } { struct function **temp; temp = out1; out1 = out2; out2 = temp; } count1 = count2 = runlength; } *out1 = 0; *out2 = 0; funname_start1 = out_start1; funname_start2 = out_start2; runlength <<= 1; } while (runlength < num_function_names); } if (CURRENT_PROGRAM_SIZE > FUNSTART_MASK) { struct function *functions; yyerror("Program too large"); for (i = num_functions; --i >= 0; functions++) { if ( !(functions->flags & (NAME_UNDEFINED|NAME_INHERITED)) == NAME_UNDEFINED) { free_string(functions->name); } } } } %ifndef INITIALIZATION_BY___INIT prog_variable_values = (struct svalue *)mem_block[A_VIRTUAL_VAR_VALUES].block; %endif /* INITIALIZATION_BY___INIT */ free_all_local_names(); for (q=all_globals; g=q; ) { q=g->next_all; free_shared_identifier(g); } while(last_yalloced) { yfree(last_yalloced); debug_message("freeing lost block\n"); } #if 0 fprintf(stderr,"freeing efun shadows\n"); #endif if (all_efun_shadows) { struct efun_shadow *s, *t; for (t=all_efun_shadows; s=t; ) { #if 0 fprintf(stderr,"freeing efun shadow '%s'\n",s->shadow->name); #endif s->shadow->u.global.function = -2; s->shadow->u.global.variable = -2; t=s->next; xfree((char *)s); } all_efun_shadows = 0; } all_globals = 0; switch (0) { default: if (num_parse_error > 0 || inherit_file) break; size = align(sizeof (struct program)); if (!pragma_save_types) { mem_block[A_ARGUMENT_TYPES].current_size = 0; mem_block[A_ARGUMENT_INDEX].current_size = 0; } for (i=0; i<NUMPAREAS; i++) size += align(mem_block[i].current_size); size += align(num_function_names * sizeof *prog->function_names); size += align(num_functions * sizeof *prog->functions); if ( !(p = (char *)xalloc(size)) ) { yyerror("Out of memory"); break; } prog = (struct program *)p; *prog = NULL_program; if ( !(prog->name = string_copy(current_file)) ) { xfree((char*)prog); yyerror("Out of memory"); break; } prog->total_size = size; prog->ref = 0; prog->heart_beat = heart_beat; prog->id_number = ++current_id_number ? current_id_number : renumber_programs(); prog->load_time = current_time; total_prog_block_size += prog->total_size; total_num_prog_blocks += 1; p += align(sizeof (struct program)); prog->program = p; if (mem_block[A_PROGRAM].current_size) memcpy(p, mem_block[A_PROGRAM].block, mem_block[A_PROGRAM].current_size); prog->program_size = mem_block[A_PROGRAM].current_size; p += align(mem_block[A_PROGRAM].current_size); prog->line_numbers = p; if (mem_block[A_LINENUMBERS].current_size) memcpy(p, mem_block[A_LINENUMBERS].block, mem_block[A_LINENUMBERS].current_size); p += align(mem_block[A_LINENUMBERS].current_size); prog->num_function_names = num_function_names; prog->function_names = (unsigned short *)p; { unsigned short *namep; namep = (unsigned short *)p; if ( (f = funname_start1) || (f = funname_start2) ) { do { *namep++ = f - (struct function *)mem_block[A_FUNCTIONS].block; } while (f = f->offset.next); } } p += align(num_function_names * sizeof *prog->function_names); prog->num_functions = num_functions; prog->functions = (uint32 *)p; { uint32 *flagp; f = (struct function *)mem_block[A_FUNCTIONS].block; flagp = (uint32 *)p; for (i = num_functions; --i >= 0; f++) *flagp++ = f->flags; } p += align(num_functions * sizeof *prog->functions); prog->strings = (char **)p; prog->num_strings = num_strings; if (mem_block[A_STRINGS].current_size) memcpy(p, mem_block[A_STRINGS].block, mem_block[A_STRINGS].current_size); p += align(mem_block[A_STRINGS].current_size); prog->variable_names = (struct variable *)p; prog->num_variables = num_variables; if (mem_block[A_VIRTUAL_VAR].current_size) memcpy(p, mem_block[A_VIRTUAL_VAR].block, mem_block[A_VIRTUAL_VAR].current_size); p += align(mem_block[A_VIRTUAL_VAR].current_size); prog->num_inherited = mem_block[A_INHERITS].current_size / sizeof (struct inherit); if (prog->num_inherited) { memcpy(p, mem_block[A_INHERITS].block, mem_block[A_INHERITS].current_size); prog->inherit = (struct inherit *)p; } else { prog->inherit = 0; } p += align(mem_block[A_INHERITS].current_size); if (pragma_save_types) { if (mem_block[A_ARGUMENT_TYPES].current_size) memcpy(p, mem_block[A_ARGUMENT_TYPES].block, mem_block[A_ARGUMENT_TYPES].current_size); prog->argument_types = (unsigned short *)p; p += align(mem_block[A_ARGUMENT_TYPES].current_size); if (mem_block[A_ARGUMENT_INDEX].current_size) memcpy(p, mem_block[A_ARGUMENT_INDEX].block, mem_block[A_ARGUMENT_INDEX].current_size); prog->type_start = (unsigned short *)p; p += align(mem_block[A_ARGUMENT_INDEX].current_size); } else { prog->argument_types = 0; prog->type_start = 0; } fix_variable_index_offsets(prog); for (i=0; i<NUMAREAS; i++) { %ifndef INITIALIZATION_BY___INIT if (i == A_VIRTUAL_VAR_VALUES) /* Don't free now */ continue; %endif /* INITIALIZATION_BY___INIT */ xfree((char *)mem_block[i].block); } /* marion Do referencing here - avoid multiple referencing when an object inherits more than one object and one of the inherited is already loaded and not the last inherited */ reference_prog (prog, "epilog"); for (i = 0; i < prog->num_inherited; i++) { reference_prog (prog->inherit[i].prog, "inheritance"); } compiled_prog = prog; return; } { extern void do_free_sub_strings PROT((int, char **, int, struct variable *)); struct function *functions; %ifndef INITIALIZATION_BY___INIT for (i=0; i<num_variables; i++) free_svalue(&prog_variable_values[i]); %endif /* INITIALIZATION_BY___INIT */ /* Free all function names. */ functions = (struct function *)mem_block[A_FUNCTIONS].block; for (i = num_functions; --i >= 0; functions++) if ( !(functions->flags & (NAME_INHERITED|NAME_UNDEFINED)) && functions->name ) { free_string(functions->name); } do_free_sub_strings( num_strings, (char **)mem_block[A_STRINGS].block, num_variables, (struct variable *)mem_block[A_VIRTUAL_VAR].block ); compiled_prog = 0; for (i=0; i<NUMAREAS; i++) xfree(mem_block[i].block); return; } } INLINE int proxy_efun(function, num_arg) int function, num_arg; { if (function == F_EXTRACT-F_OFFSET) { if (num_arg == 2) { return F_EXTRACT2-F_OFFSET; } if (num_arg == 1) { return F_EXTRACT1-F_OFFSET; } } if (function == F_PREVIOUS_OBJECT-F_OFFSET) { /* num_arg == 0 */ return F_PREVIOUS_OBJECT0-F_OFFSET; } return -1; } static void _ins_f_code(b) unsigned int b; { if (b > 0x100) ins_f_byte(F_ESCAPE); ins_byte(b); } /* * Patch a function definition of an inherited function, to what it really * should be. * The name of the function can be one of: * object::name * ::name * name * Where 'object' is the name of the superclass. */ /* this function could be inline, but it is not called very often, and making it inline would damage the variable-register mapping in the calling block of yyparse. */ static int insert_inherited(super_name, real_name, super_p, fun_p, num_arg, __PREPARE_INSERT__p) char *super_name; char *real_name; struct program **super_p; struct function *fun_p; int num_arg; char *__PREPARE_INSERT__p; { extern char *findstring PROT((char *)); struct inherit *ip; int num_inherits, super_length; short __ADD_SHORT__s[2]; super_length = strlen(super_name); num_inherits = mem_block[A_INHERITS].current_size / sizeof (struct inherit); real_name = findstring(real_name); ip = (struct inherit *)mem_block[A_INHERITS].block; for (; num_inherits > 0; ip++, num_inherits--) { short i; uint32 flags; if (*super_name) { /* ip->prog->name includes .c */ int l = strlen(ip->prog->name + 2); if (l < super_length) continue; if (l > super_length && ip->prog->name[l-super_length-1] != '/') continue; if (strncmp(super_name, ip->prog->name + l - super_length, super_length) != 0) continue; } if ( (i = find_function(real_name, ip->prog)) < 0) continue; flags = ip->prog->functions[i]; if (flags & NAME_INHERITED) { struct inherit *ip2; struct program *prog1, *prog2; int numvar2; prog1 = ip->prog; ip2 = &prog1->inherit[flags & INHERIT_MASK]; prog2 = ip2->prog; if ( (numvar2 = prog2->num_variables) && prog1->variable_names[ip2->variable_index_offset+numvar2-1].flags& TYPE_MOD_VIRTUAL && !(prog2->variable_names[numvar2-1].flags & TYPE_MOD_VIRTUAL) ) { /* inherited from a virtually inherited program */ do --ip; while (ip->prog != prog2); i -= ip2->function_index_offset; } } add_f_byte(F_CALL_EXPLICIT_INHERITED); add_short(ip - (struct inherit *)mem_block[A_INHERITS].block); add_short(i); add_byte(num_arg); *super_p = ip->prog; fun_p->name = real_name; fun_p->flags = flags & ~INHERIT_MASK; { int i2 = i; char *funstart; while ( (flags = ip->prog->functions[i2]) & NAME_INHERITED) { ip = &ip->prog->inherit[flags & INHERIT_MASK]; i2 -= ip->function_index_offset; } funstart = &ip->prog->program[flags & FUNSTART_MASK]; fun_p->type = funstart[-1]; fun_p->num_arg = funstart[0]; } return i; } return -1; } void yyerror(str) char *str; { extern int num_parse_error; if (num_parse_error > 5) return; (void)fprintf(stderr, "%s: %s line %d\n", current_file, str, current_line); fflush(stderr); smart_log(current_file, current_line, str); if (num_parse_error == 0) save_error(str, current_file, current_line); num_parse_error++; } #if 0 static int check_declared(varname) struct ident *varname; { struct variable *vp; int offset; for (offset=0; offset < mem_block[A_VARIABLES].current_size; offset += sizeof (struct variable)) { vp = (struct variable *)&mem_block[A_VARIABLES].block[offset]; if (vp->flags & NAME_HIDDEN) continue; if (strcmp(vp->name, str) == 0) return offset / sizeof (struct variable); } return -1; } #endif static int verify_declared(p) struct ident *p; { int r; if (p->type != I_TYPE_GLOBAL || (r = p->u.global.variable) < 0) { yyerrorf("Variable %s not declared !", p->name); return -1; } return r; } void free_all_local_names() { struct ident *p,*q; for (q=all_locals; p=q;) { q = p->next_all; free_shared_identifier(p); } all_locals = 0; #if 0 int i; for (i=0; i<current_number_of_locals; i++) { xfree(local_names[i]); local_names[i] = 0; } #endif current_number_of_locals = 0; current_break_stack_need = 0; max_break_stack_need = 0; } void add_local_name(ident, type) struct ident *ident; int type; { if (current_number_of_locals == MAX_LOCAL) yyerror("Too many local variables"); else { if (ident->type != I_TYPE_UNKNOWN) { ident = make_shared_identifier(ident->name, I_TYPE_LOCAL); } ident->type = I_TYPE_LOCAL; ident->u.local = current_number_of_locals; ident->next_all = all_locals; all_locals = ident; type_of_locals[current_number_of_locals++] = type; } } static void cross_define(from, to, offset) struct function *from, *to; int32 offset; { short nomask; to->flags = (to->flags & ~NAME_UNDEFINED) | (from->flags & (NAME_UNDEFINED|NAME_PROTOTYPE)) | NAME_CROSS_DEFINED | NAME_HIDDEN | NAME_INHERITED; to->offset.func = offset + (INHERIT_MASK + 1 >> 1); nomask = (from->flags|to->flags) & TYPE_MOD_NO_MASK; from->flags |= nomask; to ->flags |= nomask; } static uint32 *get_function_id(progp, fx) struct program *progp; int fx; { uint32 flags; flags = progp->functions[fx]; if (flags & NAME_CROSS_DEFINED) { fx += (flags & INHERIT_MASK) - (INHERIT_MASK + 1 >> 1); flags = progp->functions[fx]; } while(flags & NAME_INHERITED) { struct inherit *inheritp; inheritp = &progp->inherit[flags & INHERIT_MASK]; progp = inheritp->prog; fx -= inheritp->function_index_offset; flags = progp->functions[fx]; } return &progp->functions[fx]; } #define NEW_INHERITED_INDEX (0xfffff) /* * Copy all function definitions from an inherited object. They are added * as undefined, so that they can be redefined by a local definition. * If they are not redefined, then they will be updated, so that they * point to the inherited definition. See epilog(). Types will be copied * at that moment (if available). * * An explicit call to an inherited function will not be * done through this entry (because this entry can be replaced by a new * definition). If an function defined by inheritance is called, * this is done with F_CALL_EXPLICIT_INHERITED */ %ifdef INITIALIZATION_BY___INIT static int copy_functions(from, type) struct program *from; int type; { int i, initializer = -1; uint32 current_func_index; %else static void copy_functions(from, type) struct program *from; int type; { int i; uint32 current_func_index; %endif struct function *fun_p; unsigned short *ixp; while (mem_block[A_FUNCTIONS].max_size - mem_block[A_FUNCTIONS].current_size < from->num_functions * sizeof(struct function) ) { realloc_mem_block(A_FUNCTIONS); } fun_p = (struct function *) (mem_block[A_FUNCTIONS].block + mem_block[A_FUNCTIONS].current_size); for (i=0; i < from->num_functions; i++,fun_p++) { struct program *defprog; struct inherit *ip; unsigned char *funstart; int i2; uint32 flags; flags = from->functions[i]; fun_p->offset.inherit = NEW_INHERITED_INDEX; i2 = i; if (flags & NAME_INHERITED) { fun_p->flags = (flags & ~INHERIT_MASK) | NAME_INHERITED | NAME_HIDDEN; if (flags & NAME_CROSS_DEFINED) { i2 += (fun_p->offset.func = (flags & INHERIT_MASK)) - (INHERIT_MASK + 1 >> 1); } } else { fun_p->flags = (flags & ~FUNSTART_MASK) | NAME_INHERITED | NAME_HIDDEN; } defprog = from; while ( (flags = defprog->functions[i2]) & NAME_INHERITED) { ip = &defprog->inherit[flags & INHERIT_MASK]; i2 -= ip->function_index_offset; defprog = ip->prog; } funstart = &defprog->program[flags & FUNSTART_MASK]; memcpy( (char *)&fun_p->name, funstart - 1 - sizeof fun_p->name, sizeof fun_p->name ); fun_p->type = funstart[-1]; fun_p->num_arg = funstart[0]; if (funstart[2] == F_ESCAPE - F_OFFSET && funstart[3] == F_UNDEF - F_OFFSET -0x100) { fun_p->flags |= NAME_UNDEFINED; } } fun_p = (struct function *) (mem_block[A_FUNCTIONS].block + mem_block[A_FUNCTIONS].current_size); ixp = from->function_names; for (i = from->num_function_names; --i >= 0; ) { fun_p[*ixp++].flags &= ~NAME_HIDDEN; } current_func_index = mem_block[A_FUNCTIONS].current_size / sizeof (struct function); mem_block[A_FUNCTIONS].current_size += sizeof *fun_p * from->num_functions; for (i=0; i < from->num_functions; i++,current_func_index++) { /* Do not call define_new_function() from here, as duplicates would * be removed. */ struct function fun; int new_type; unsigned short tmp_short; struct ident* p; fun = fun_p[i]; /* Make a copy */ /* Prepare some data to be used if this function will not be * redefined. */ /* fun.name has already it's ref as a newly defined function in from */ fun.flags |= type & TYPE_MOD_NO_MASK; switch (0) { default: if ( (fun.flags & (NAME_HIDDEN|TYPE_MOD_NO_MASK|NAME_UNDEFINED) ) == (NAME_HIDDEN|TYPE_MOD_NO_MASK) ) break; /* this function is either visible or subject to redefinition */ p = make_shared_identifier(fun.name, I_TYPE_GLOBAL); if (!p) { yyerror("Out of memory"); break; } if (p->type > I_TYPE_GLOBAL) { /* sigh. can't people keep from such #defines? */ struct ident *q; do { q = p; p = p->inferior; } while (p && p->type > I_TYPE_GLOBAL); if (!p) { p = (struct ident *)xalloc(sizeof(struct ident)); if (!p) { yyerror("Out of memory"); break; } p->name = q->name; p->type = I_TYPE_UNKNOWN; p->inferior = 0; p->hash = q->hash; q->inferior = p; } } if (p->type != I_TYPE_UNKNOWN) { int32 n; if ( (n = p->u.global.function) >= 0) { /* already inherited from somewhere else */ struct function *OldFunction = FUNCTION(n); if ( !(OldFunction->flags & NAME_INHERITED) ) { debug_message( "Misplaced prototype for %s in %s\n", fun.name, current_file ); cross_define( &fun, OldFunction, current_func_index - n ); p->u.global.function = current_func_index; } else if (fun.flags & TYPE_MOD_VIRTUAL && OldFunction->flags & TYPE_MOD_VIRTUAL && !((fun.flags | OldFunction->flags) & NAME_HIDDEN) && get_function_id(from, i) == get_function_id( ((struct inherit *)mem_block[A_INHERITS].block) [OldFunction->offset.inherit].prog, n - ((struct inherit *)mem_block[A_INHERITS].block) [OldFunction->offset.inherit].function_index_offset) ) { /* Entries denote the same function. We have to use * cross_define nonetheless, to get consistant * redefinition. */ /* prefer the first one */ OldFunction->flags |= fun.flags & (TYPE_MOD_PUBLIC|TYPE_MOD_NO_MASK); OldFunction->flags &= fun.flags | ~TYPE_MOD_STATIC; cross_define( OldFunction, &fun, n - current_func_index ); } else if ( (fun.flags & OldFunction->flags & TYPE_MOD_NO_MASK) && /* both are nomask... */ !( (fun.flags|OldFunction->flags) & NAME_UNDEFINED ) ) { yyerrorf( "Illegal to inherit 'nomask' function '%s' twice", fun.name); } else if ((fun.flags & TYPE_MOD_NO_MASK || OldFunction->flags & (NAME_HIDDEN|NAME_UNDEFINED)) && !( fun.flags & (NAME_HIDDEN|NAME_UNDEFINED)) ) { /* silently prefer this one */ cross_define( &fun, OldFunction, current_func_index - n ); p->u.global.function = current_func_index; } else { /* prefer the first one */ cross_define( OldFunction, &fun, n - current_func_index ); } } else { if (n == -2) { struct efun_shadow *q; q =(struct efun_shadow *) xalloc(sizeof(struct efun_shadow)); if (!q) { yyerror("Out of memory"); break; } q->shadow = p; q->next = all_efun_shadows; all_efun_shadows = q; } p->u.global.function = current_func_index; } } else { /* was I_TYPE_UNKNOWN */ p->type = I_TYPE_GLOBAL; p->u.global.variable = -1; p->u.global.efun = -1; p->u.global.sim_efun = -1; p->u.global.function = current_func_index; p->next_all = all_globals; all_globals = p; } /* * public functions should not become private when inherited * 'private' */ new_type = type; if (fun.flags & TYPE_MOD_PUBLIC) new_type &= ~TYPE_MOD_PRIVATE; fun.flags |= new_type; /* marion * this should make possible to inherit a heart beat function, and * thus to mask it if wanted. */ if ((heart_beat == -1) && fun.name[0] == 'h' && (strcmp(fun.name, "heart_beat") == 0)) heart_beat = current_func_index; %ifdef INITIALIZATION_BY___INIT else if (fun.name[0] == '_' && strcmp(fun.name+1, "_INIT") == 0) { initializer = i; fun.flags |= NAME_UNDEFINED; } %endif } /* end of visibility/redifinability - only code */ /* * Copy information about the types of the arguments, if it is * available. */ tmp_short = INDEX_START_NONE; /* Presume not available. */ if (from->type_start != 0) { if (from->type_start[i] != INDEX_START_NONE) { /* * They are available for function number 'i'. Copy types of * all arguments, and remember where they started. */ tmp_short = mem_block[A_ARGUMENT_TYPES].current_size / sizeof from->argument_types[0]; if (fun.num_arg) add_to_mem_block(A_ARGUMENT_TYPES, &from->argument_types[from->type_start[i]], (sizeof (unsigned short)) * fun.num_arg); } } else fun.flags |= NAME_TYPES_LOST; /* * Save the index where they started. Every function will have an * index where the type info of arguments starts. */ add_to_mem_block(A_ARGUMENT_INDEX, &tmp_short, sizeof tmp_short); fun_p[i] = fun; } %ifdef INITIALIZATION_BY___INIT return initializer; %endif } void fix_function_inherit_indices(from) struct program *from; { int i, inherit_index; struct function *funp; inherit_index = mem_block[A_INHERITS].current_size / sizeof (struct inherit); funp = (struct function *) (mem_block[A_FUNCTIONS].block+mem_block[A_FUNCTIONS].current_size) - from->num_functions; for(i = from->num_functions; --i>=0; funp++) { if ( funp->offset.inherit == NEW_INHERITED_INDEX && !(funp->flags & NAME_CROSS_DEFINED) ) { funp->offset.inherit = inherit_index; } } } void fix_variable_index_offsets(new_prog) struct program *new_prog; { int i; struct inherit *inheritp; i = new_prog->num_inherited; for (inheritp = new_prog->inherit; --i >= 0; inheritp++) { if (inheritp->variable_index_offset & NON_VIRTUAL_OFFSET_TAG) { inheritp->variable_index_offset += num_virtual_variables; inheritp->variable_index_offset &= ~NON_VIRTUAL_OFFSET_TAG; } } } /* * Copy all variable names from the object that is inherited from. * It is very important that they are stored in the same order with the * same index. */ %ifndef INITIALIZATION_BY___INIT static void copy_variables(from, type, initializers) struct program *from; int type; struct svalue *initializers; %else static void copy_variables(from, type) struct program *from; int type; %endif { int i, j; int new_bound, last_bound; int variable_index_offset, function_index_offset; struct inherit *inheritp; int from_variable_index_offset = -1; int previous_variable_index_offset; type &= ~TYPE_MOD_VARARGS; if (type & TYPE_MOD_VIRTUAL) { inheritp = (struct inherit *)(mem_block[A_INHERITS].block); j = mem_block[A_INHERITS].current_size; for (; (j -= sizeof(struct inherit)) >= 0; inheritp++) { if (inheritp->prog == from && !(inheritp->variable_index_offset & NON_VIRTUAL_OFFSET_TAG) ) { from_variable_index_offset = inheritp->variable_index_offset + VIRTUAL_VAR_TAG; break; } } } function_index_offset = mem_block[A_FUNCTIONS].current_size / sizeof(struct function) - from->num_functions; variable_index_offset = mem_block[A_VIRTUAL_VAR].current_size / sizeof(struct variable); i = from->num_inherited; last_bound = 0; for (inheritp = from->inherit; ; inheritp++) { if (--i >= 0) { struct program *progp; progp = inheritp->prog; new_bound = inheritp->variable_index_offset + progp->num_variables; if (progp->num_variables && from->variable_names[new_bound-1].flags & TYPE_MOD_VIRTUAL && !(progp->variable_names[progp->num_variables-1].flags & TYPE_MOD_VIRTUAL) ) { struct inherit inherit, *inheritp2; int k, inherit_index; struct function *funp; inherit = *inheritp; inheritp2 = (struct inherit *)(mem_block[A_INHERITS].block); j = mem_block[A_INHERITS].current_size; for (; (j -= sizeof(struct inherit)) >= 0; inheritp2++) { if (inheritp2->prog == inherit.prog && !(inheritp2->variable_index_offset & NON_VIRTUAL_OFFSET_TAG) ) { inherit.variable_index_offset = inheritp2->variable_index_offset; break; } } if (j < 0) { variable_index_offset += new_bound - last_bound; inherit.variable_index_offset = variable_index_offset - progp->num_variables; } inherit_index = (mem_block[A_INHERITS].current_size - j) / sizeof(struct inherit) - 1; inherit.function_index_offset += function_index_offset; add_to_mem_block(A_INHERITS, &inherit, sizeof inherit); funp = (struct function *)mem_block[A_FUNCTIONS].block + inherit.function_index_offset; for (k = inherit.prog->num_functions; --k >= 0; funp++) { if ( !(funp->flags & NAME_CROSS_DEFINED) ) { funp->offset.inherit = inherit_index; } } if (j >= 0) { /* There has been another instance * of this virtual superclass before */ if (new_bound > last_bound) last_bound = new_bound; continue; } previous_variable_index_offset = -1; } else { continue; /* Not a virtual superclass */ } } else { previous_variable_index_offset = from_variable_index_offset; new_bound = from->num_variables; if (new_bound == last_bound) break; } for (j = last_bound; j < new_bound; j++) { extern struct svalue const0; struct ident *p; int new_type; p = make_shared_identifier(from->variable_names[j].name, I_TYPE_GLOBAL); if (!p) { yyerror("Out of memory"); return; } if (p->type > I_TYPE_GLOBAL) { /* sigh. can't people keep from such #defines? */ struct ident *q; do { q = p; p = p->inferior; } while (p && p->type > I_TYPE_GLOBAL); if (!p) { p = (struct ident *)xalloc(sizeof(struct ident)); if (!p) { yyerror("Out of memory"); return; } p->name = q->name; p->type = I_TYPE_UNKNOWN; p->inferior = 0; p->hash = q->hash; q->inferior = p; } } new_type = type; /* * 'public' variables should not become private when inherited * 'private'. */ if (from->variable_names[j].flags & TYPE_MOD_PUBLIC) new_type &= ~TYPE_MOD_PRIVATE; /* define_variable checks for previous 'nomask' definition. */ if (previous_variable_index_offset >= 0) { if ( !(from->variable_names[j].flags & TYPE_MOD_PRIVATE) ) redeclare_variable(p, new_type | from->variable_names[j].flags | NAME_INHERITED, previous_variable_index_offset + j ); } else { define_variable(p, new_type | from->variable_names[j].flags | (from->variable_names[j].flags & TYPE_MOD_PRIVATE ? (NAME_HIDDEN|NAME_INHERITED) : NAME_INHERITED ) %ifndef INITIALIZATION_BY___INIT ,from->variable_names[j].flags & NAME_INITIALIZED ? copy_svalue(&initializers[j]) : &const0 %endif ); } } /* end loop through functions */ last_bound = new_bound; } /* end of loop through inherits */ } /* * This function is called from lex.c for every new line read from the * "top" file (means not included files). Some new lines are missed, * as with #include statements, so it is compensated for. */ void store_line_number_info() { char c; short offset = mem_block[A_PROGRAM].current_size - stored_bytes; if (offset <= 0) return; stored_bytes = mem_block[A_PROGRAM].current_size; if (offset <= 8 && current_line - stored_lines >= 2 && current_line - stored_lines <= 9) { c = offset + 8*(current_line - stored_lines) + 47; byte_to_mem_block(A_LINENUMBERS, c); stored_lines = current_line; return; } stored_lines++; while(stored_lines < current_line) { int lines; lines = current_line - stored_lines; if (lines > LI_MAXEMPTY) lines = LI_MAXEMPTY; stored_lines += lines; c = 256 - lines; byte_to_mem_block(A_LINENUMBERS, c); } while(offset >= LI_MAXOFFSET) { byte_to_mem_block(A_LINENUMBERS, LI_MAXOFFSET); offset -= LI_MAXOFFSET; } byte_to_mem_block(A_LINENUMBERS, offset); } void store_line_number_relocation(relocated_from) int relocated_from; { int save_current, offset; save_current = current_line; stored_lines -= 2; current_line = stored_lines+1; offset = current_line - relocated_from; if (offset >= LI_SMALL_REL) { byte_to_mem_block(A_LINENUMBERS, LI_L_RELOCATED); byte_to_mem_block(A_LINENUMBERS, offset >> 8); byte_to_mem_block(A_LINENUMBERS, offset); /* trailing LI_L_RELOCATED allows bidirectional traversal */ byte_to_mem_block(A_LINENUMBERS, LI_L_RELOCATED); } else { byte_to_mem_block(A_LINENUMBERS, LI_RELOCATED + offset); } store_line_number_info(); current_line = save_current; } static int simple_includes; void store_include_info(name) char *name; { extern char *out_of_memory_string; if (last_include_start == mem_block[A_LINENUMBERS].current_size) { simple_includes++; } else { simple_includes = 0; } stored_lines++; while(stored_lines < current_line) { int lines; lines = current_line - stored_lines; if (lines > LI_MAXEMPTY) lines = LI_MAXEMPTY; stored_lines += lines; byte_to_mem_block(A_LINENUMBERS, 256 - lines); } byte_to_mem_block(A_LINENUMBERS, LI_INCLUDE); last_include_start = mem_block[A_LINENUMBERS].current_size; name = make_shared_string(name); if (!name) { increment_string_ref(name = out_of_memory_string); yyerror("Out of memory"); } add_to_mem_block(A_INCLUDE_NAMES, &name, sizeof name); stored_lines = 0; } void store_include_end() { unsigned char c; stored_lines = current_line-1; if (last_include_start == mem_block[A_LINENUMBERS].current_size) { last_include_start = mem_block[A_LINENUMBERS].current_size - 1; stored_lines--; while(last_include_start && (c = mem_block[A_LINENUMBERS].block[last_include_start - 1]) >= 0x100 - LI_MAXEMPTY) { stored_lines += c - 0x100; last_include_start--; } mem_block[A_LINENUMBERS].current_size = last_include_start; if (--simple_includes < 0) { last_include_start--; } free_string( *(char **) (mem_block[A_INCLUDE_NAMES].block + (mem_block[A_INCLUDE_NAMES].current_size -= sizeof(char *))) ); } else { byte_to_mem_block(A_LINENUMBERS, LI_INCLUDE_END); } } static char *get_type_name(type) int type; { static char buff[100]; static char *type_name[] = { "unknown", "int", "string", "void", "object", "mapping", "float", "mixed", 0, "closure", "symbol", "quoted_array", }; int pointer = 0, reference = 0; buff[0] = 0; if (type & TYPE_MOD_STATIC) strcat(buff, "static "); if (type & TYPE_MOD_NO_MASK) strcat(buff, "nomask "); if (type & TYPE_MOD_PRIVATE) strcat(buff, "private "); if (type & TYPE_MOD_PROTECTED) strcat(buff, "protected "); if (type & TYPE_MOD_PUBLIC) strcat(buff, "public "); if (type & TYPE_MOD_VARARGS) strcat(buff, "varargs "); type &= TYPE_MOD_MASK; if (type & TYPE_MOD_POINTER) { pointer = 1; type &= ~TYPE_MOD_POINTER; } if (type & TYPE_MOD_REFERENCE) { reference = 1; type &= ~TYPE_MOD_REFERENCE; } if (type >= sizeof type_name / sizeof type_name[0]) fatal("Bad type\n"); strcat(buff, type_name[type]); strcat(buff," "); if (pointer) strcat(buff, "* "); if (reference) strcat(buff, "& "); return buff; } static void type_error(str, type) char *str; int type; { char *p; p = get_type_name(type); yyerrorf("%s: \"%s\"", str, p); } static void argument_type_error(i, type) int i, type; { char *p; p = get_type_name(type); yyerrorf("Bad argument to %s: \"%s\"", instrs[i].name, p); } /* * Compile an LPC file. */ void compile_file() { int yyparse(); prolog(); yyparse(); epilog(); } static char *get_two_types(type1, type2) int type1, type2; { static char buff[100]; strcpy(buff, "( "); strcat(buff, get_type_name(type1)); strcat(buff, "vs "); strcat(buff, get_type_name(type2)); strcat(buff, ")"); return buff; } static void insert_pop_value() { if (last_expression == mem_block[A_PROGRAM].current_size-1) { switch ( mem_block[A_PROGRAM].block[last_expression]+F_OFFSET ) { case F_ASSIGN: mem_block[A_PROGRAM].block[last_expression] = F_VOID_ASSIGN - F_OFFSET; break; case F_ADD_EQ: mem_block[A_PROGRAM].block[last_expression] = F_VOID_ADD_EQ - F_OFFSET; break; case F_PRE_INC: case F_POST_INC: mem_block[A_PROGRAM].block[last_expression] = F_INC - F_OFFSET; break; case F_PRE_DEC: case F_POST_DEC: mem_block[A_PROGRAM].block[last_expression] = F_DEC - F_OFFSET; break; case F_CONST0: case F_CONST1: mem_block[A_PROGRAM].current_size = last_expression; break; default: ins_f_byte(F_POP_VALUE); } last_expression = -1; } else ins_f_byte(F_POP_VALUE); } #if defined( DEBUG ) && defined ( TRACE_CODE ) int code_window_offset = -1; void set_code_window() { code_window_offset = CURRENT_PROGRAM_SIZE; } void show_code_window() { int i; unsigned char *p; if (code_window_offset < 0) return; p = (unsigned char *)mem_block[A_PROGRAM].block + code_window_offset; for (i=0; i<16; i++) { printf("%3d ", p[i]); } printf("\n"); fflush(stdout); } #endif #ifdef MALLOC_smalloc void count_compiler_refs() { if (type_of_arguments.block) { note_malloced_block_ref(type_of_arguments.block); } } #endif