%{
#line 2 "postlang.y"
/*
* These are token values that needn't have an associated code for the
* compiled file
*/
%}
%token F_CASE F_DEFAULT
%union
{
int number;
float real;
unsigned int address; /* Address of an instruction */
char *string;
short type;
struct { int key; char block; } case_label;
struct function *funp;
}
%type <number> opt_int assign F_NUMBER constant F_LOCAL_NAME expr_list
%type <number> const1 const2 const3 const4 const5 const6 const7 const8 const9
%type <number> lvalue_list argument type basic_type optional_star expr_list2
%type <number> type_modifier type_modifier_list opt_basic_type block_or_semi
%type <number> argument_list m_expr_list m_expr_list2
%type <string> identifier fun_identifier opt_inherit_name
%type <string> F_IDENTIFIER F_STRING string_con1 string_constant function_name
%type <real> F_FLOATC
%type <case_label> case_label
/* The following symbols return type information */
%type <type> function_call lvalue string cast expr01 comma_expr
%type <type> expr2 expr211 expr1 expr212 expr213 expr24 expr22 expr23 expr25
%type <type> expr27 expr28 expr3 expr31 expr4 number expr0 real
/* %expect 1 */ /* You can uncomment previous statement if you use bison */
%{
/* has to be here so that F_EXT is defined */
static void store_reloc_data(char, unsigned short, char *name, int, char);
static void ins_f_byte(unsigned int );
static int first_default_arg, current_arg;
static int is_ctor, is_dtor;
static int return_label;
#define CTOR_FUNC ((char *)1)
#define DTOR_FUNC ((char *)2)
%}
%%
all: { invariant_last_address = 0; } program ;
program: program def possible_semi_colon
| /* empty */ ;
possible_semi_colon: /* empty */
| ';' { yyerror("Extra ';'. Ignored."); };
inheritance: type_modifier_list F_INHERIT F_STRING opt_inherit_name ';'
{
char *initializer_name;
struct object *ob;
struct inherit inherit;
int initializer;
extern char *findstring (char *);
if (mem_block[A_VARIABLES].current_size ||
mem_block[A_FUNCTIONS].current_size)
yyerror("Inherit after other definitions\n");
ob = find_object2($3);
if (ob == 0) {
if (inherit_file)
free(inherit_file);
inherit_file = $3;
free($4);
/* Return back to load_object() */
YYACCEPT;
}
if (ob->prog->flags & PRAGMA_NO_INHERIT)
{
yyerror("Inheriting bad object.\n");
}
if (!check_inherits(ob->prog))
{
if (inherit_file)
free(inherit_file);
inherit_file = $3;
free($4);
/* Return back to load_object() */
YYACCEPT;
}
free($3);
inherit.prog = ob->prog;
inherit.type = $1;
copy_inherits (ob->prog, inherit.type, $4);
free($4);
}
opt_inherit_name: /* empty */
{
char *n = strrchr($<string>0, '/');
if (n)
{
$$ = string_copy(n + 1);
}
else
$$ = string_copy($<string>0);
}
| F_IDENTIFIER
{
$$ = $1;
} ;
invariant : '<' '>' ':'
{
if (invariant_last_address)
{
if (invariant_last_address + 2 ==
mem_block[A_PROGRAM].current_size)
mem_block[A_PROGRAM].current_size -= 3;
else
upd_short(invariant_last_address,
mem_block[A_PROGRAM].current_size);
}
else
invariant_first_address = mem_block[A_PROGRAM].current_size;
}
expr0
{
ins_f_byte(F_FAIL_INVARIANT);
ins_f_byte(F_JUMP);
invariant_last_address = mem_block[A_PROGRAM].current_size;
ins_short(0);
} ;
pre_condition : F_LSH ':'
{
if (pre_cond_last_address)
if (pre_cond_last_address + 2 ==
mem_block[A_PROGRAM].current_size)
mem_block[A_PROGRAM].current_size -= 3;
else
upd_short(pre_cond_last_address,
mem_block[A_PROGRAM].current_size);
else
pre_cond_first_address = mem_block[A_PROGRAM].current_size;
if (is_ctor)
{
yyerror("Constructors may not have preconditions");
}
}
expr0
{
ins_f_byte(F_FAIL_PRECOND);
ins_f_byte(F_JUMP);
pre_cond_last_address = mem_block[A_PROGRAM].current_size;
ins_short(0);
} ;
post_condition : F_RSH ':'
{
if (post_cond_last_address)
if (post_cond_last_address + 2 ==
mem_block[A_PROGRAM].current_size)
mem_block[A_PROGRAM].current_size -= 3;
else
upd_short(post_cond_last_address,
mem_block[A_PROGRAM].current_size);
else
post_cond_first_address = mem_block[A_PROGRAM].current_size;
if (is_dtor)
{
yyerror("Destructors may not have postconditions");
}
}
expr0
{
ins_f_byte(F_FAIL_POSTCOND);
ins_f_byte(F_JUMP);
post_cond_last_address = mem_block[A_PROGRAM].current_size;
ins_short(0);
} ;
opt_int : /* empty */ { $$ = 1; }
| constant
assertion : '@' opt_int ':'
{
ins_f_byte(F_ASSERTION);
ins_short($2);
push_explicit(mem_block[A_PROGRAM].current_size);
ins_short(0);
}
expr0
{
ins_f_byte(F_FAIL_ASSERTION);
upd_short(pop_address(), mem_block[A_PROGRAM].current_size);
}
number: F_NUMBER
{
if ( $1 == 0 ) {
ins_f_byte(F_CONST0); $$ = TYPE_ANY;
} else if ( $1 == 1 ) {
ins_f_byte(F_CONST1); $$ = TYPE_NUMBER;
} else {
ins_f_byte(F_NUMBER); ins_long($1); $$ = TYPE_NUMBER;
}
} ;
optional_star: /* empty */ { $$ = 0; } | '*' { $$ = TYPE_MOD_POINTER; } ;
block_or_semi: block { $$ = 0; }
| ';' { $$ = ';'; }
| '=' string_con1 ';' { $<string>$ = $<string>2; };
| '=' F_NUMBER ';'
{
if ($2 != 0)
{
yyerror("Syntax error");
}
$$ = 1;
}
opt_pre_post_cond : /* empty */
| pre_post_cond ;
pre_post_cond : pre_condition ';'
| post_condition ';'
| pre_post_cond pre_condition ';'
| pre_post_cond post_condition ';' ;
def: type optional_star fun_identifier
{
/* Save start of function. */
clear_init_arg_stack();
push_explicit(mem_block[A_PROGRAM].current_size);
true_varargs = 0;
pre_cond_first_address = pre_cond_last_address =
post_cond_first_address = post_cond_last_address = 0;
first_default_arg = current_arg = 0;
is_ctor = is_dtor = 0;
return_label = make_label();
if ($3 == CTOR_FUNC)
{
$3 = string_copy(".CTOR");
is_ctor = 1;
}
else if ($3 == DTOR_FUNC)
{
$3 = string_copy(".DTOR");
is_dtor = 1;
}
if (is_ctor | is_dtor)
{
if ($1 | $2)
{
yyerror("Constructors and destructors doesn't have a type");
$1 = $2 = 0;
}
if (pragma_strict_types)
{
$1 = exact_types = TYPE_VOID;
}
else
exact_types = 0;
}
else if ($1 & TYPE_MASK)
{
exact_types = $1 | $2;
}
else
{
if (pragma_strict_types)
yyerror("\"#pragma strict_types\" requires type of function");
exact_types = 0;
}
}
'(' argument ')'
{
/*
* Define a prototype. If it is a real function, then the
* prototype will be replaced below.
*/
if ($6 && is_ctor | is_dtor)
{
yyerror("Constructors and destructors don't take arguments");
}
ins_f_byte(F_JUMP);
push_explicit(mem_block[A_PROGRAM].current_size);
ins_short(0);
}
opt_pre_post_cond
{
int i;
unsigned short j;
i = pop_address();
push_explicit(mem_block[A_PROGRAM].current_size);
dump_init_arg_table($6);
j = mem_block[A_PROGRAM].current_size;
upd_short(i, mem_block[A_PROGRAM].current_size);
((char *)mem_block[A_PROGRAM].block)[i] = ((char *)&j)[0];
((char *)mem_block[A_PROGRAM].block)[i + 1] = ((char *)&j)[1];
define_new_function($3, $6, 0, 0,
NAME_PROTOTYPE | $1 | $2 | true_varargs,
first_default_arg);
if (pre_cond_last_address)
{
ins_f_byte(F_DO_PRECOND);
ins_short(pre_cond_first_address);
upd_short(pre_cond_last_address,
mem_block[A_PROGRAM].current_size);
}
}
block_or_semi
{
/* Either a prototype or a block */
if ($11 == ';') /* its only a prototype */
{
pop_address(); /* Not used here */
mem_block[A_PROGRAM].current_size =
pop_address();
}
else if ($11 == 0)
{
define_new_function($3, $6, current_number_of_locals - $6,
pop_address(), $1 | $2 | true_varargs,
first_default_arg);
ins_f_byte(F_CONST0);
set_label(return_label, mem_block[A_PROGRAM].current_size);
if (post_cond_last_address)
{
ins_f_byte(F_DO_POSTCOND);
ins_short(post_cond_first_address);
upd_short(post_cond_last_address,
mem_block[A_PROGRAM].current_size);
}
/* Code for calling invariants */
if (!is_dtor)
ins_f_byte(F_DO_INVARIANTS);
/* End of invariants */
ins_f_byte(F_RETURN);
pop_address(); /* Not used here */
}
else if ($11 == 1)
{
if (is_ctor | is_dtor)
yyerror("Constructors and destructors can't be abstract");
define_new_function($3, $6, 0, 0,
NAME_ABSTRACT | $1 | $2 | true_varargs,
first_default_arg);
yyerror("Abstract functions isn't implemented yet");
}
else
{
extern void (* get_C_fun_address(char *, char *))();
void (*func)();
define_new_function($3, $6, current_number_of_locals - $6,
pop_address(), $1 | $2 | true_varargs,
first_default_arg);
ins_f_byte(F_CALL_C);
func = get_C_fun_address(current_file, $<string>11);
if (!func)
{
char buf[256];
sprintf(buf,"Undefined interface %s() = \"%s\".\n",
$3, $<string>11);
yyerror(buf);
}
free($<string>11);
#ifdef __alpha
ins_long((int) ((long)func & 0xffffffff));
ins_long((int) ((long)func >> 32));
#else
ins_long((long)func);
#endif
if (!is_dtor)
ins_f_byte(F_DO_INVARIANTS);
ins_f_byte(F_RETURN);
pop_address(); /* Not used here */
}
free_all_local_names();
free($3); /* Value was copied above */
is_ctor = is_dtor = 0;
}
| type name_list ';' { if ($1 == 0) yyerror("Missing type"); }
| inheritance ;
| invariant ';'
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);
}
if (first_default_arg != current_arg)
yyerror("non default argument defined after default one");
else
first_default_arg++;
push_init_arg_address(mem_block[A_PROGRAM].current_size);
} ;
| type F_LOCAL_NAME
{yyerror("Illegal to redeclare local name"); } ;
| type optional_star F_IDENTIFIER
{
int var_num;
if (exact_types && $1 == 0) {
yyerror("Missing type for argument");
var_num = add_local_name($3, TYPE_ANY); /* Supress more errors */
} else {
var_num = add_local_name($3, $1 | $2);
}
push_init_arg_address(mem_block[A_PROGRAM].current_size);
ins_f_byte(F_PUSH_LOCAL_VARIABLE_LVALUE);
ins_byte(var_num);
}
'=' expr0
{
if (!compatible_types((($1 ? $1 : TYPE_ANY) | $2) & TYPE_MASK, $6)){
char buff[100];
sprintf(buff, "Type mismatch %s when initializing %s",
get_two_types($1 | $2, $6), $3);
yyerror(buff);
}
ins_f_byte(F_ASSIGN);
ins_f_byte(F_POP_VALUE);
} ;
| type F_LOCAL_NAME '=' expr0
{yyerror("Illegal to redeclare local name"); } ;
argument: /* empty */ { $$ = 0;}
| argument_list ;
| argument_list ',' F_VARARG
{
true_varargs = TYPE_MOD_TRUE_VARARGS;
$$ = $1 + 1;
push_init_arg_address(mem_block[A_PROGRAM].current_size);
ins_f_byte(F_PUSH_LOCAL_VARIABLE_LVALUE);
ins_byte(add_local_name(string_copy("argv"), TYPE_ANY | TYPE_MOD_POINTER));
ins_f_byte(F_AGGREGATE);
ins_short(0);
ins_f_byte(F_ASSIGN);
ins_f_byte(F_POP_VALUE);
current_arg++;
}
argument_list: new_arg_name { $$ = 1; current_arg++; }
| argument_list ',' new_arg_name { $$ = $1 + 1; current_arg++; } ;
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; } ;
type_modifier_list: /* empty */ { $$ = 0; }
| type_modifier type_modifier_list { $$ = $1 | $2; } ;
type: type_modifier_list opt_basic_type { $$ = $1 | $2; current_type = $$; } ;
cast: '(' basic_type optional_star ')'
{
$$ = $2 | $3;
} ;
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_VOID {$$ = TYPE_VOID; current_type = $$; }
| F_MIXED { $$ = TYPE_ANY; current_type = $$; }
| F_MAPPING { $$ = TYPE_MAPPING; current_type = $$; };
| F_FLOAT { $$ = TYPE_FLOAT; current_type = $$; };
name_list: new_name
| new_name ',' name_list;
new_name: optional_star F_IDENTIFIER
{
define_variable($2, current_type | $1);
free($2);
}
| optional_star F_IDENTIFIER
{
int var_num;
define_variable($2, current_type | $1);
transfer_init_control();
ins_f_byte(F_PUSH_IDENTIFIER_LVALUE);
ins_byte(variable_inherit_found);
ins_byte(variable_index_found);
}
'=' expr0
{
if (pragma_strict_types &&
!compatible_types((current_type | $1) & TYPE_MASK, $5)){
char buff[100];
sprintf(buff, "Type mismatch %s when initializing %s",
get_two_types(current_type | $1, $5), $2);
yyerror(buff);
}
ins_f_byte(F_ASSIGN);
ins_f_byte(F_POP_VALUE);
add_new_init_jump();
free($2);
} ;
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);
} ;
| optional_star F_IDENTIFIER
{
int var_num;
var_num = add_local_name($2, current_type | $1);
ins_f_byte(F_PUSH_LOCAL_VARIABLE_LVALUE);
ins_byte(var_num);
}
'=' expr0
{
if (exact_types && !compatible_types((current_type | $1) & TYPE_MASK, $5)){
char buff[100];
sprintf(buff, "Type mismatch %s when initializing %s",
get_two_types(current_type | $1, $5), $2);
yyerror(buff);
}
ins_f_byte(F_ASSIGN);
ins_f_byte(F_POP_VALUE);
} ;
local_name_list: new_local_name
| new_local_name ',' local_name_list ;
statements: /* empty */
| statement statements
| error ';' ;
statement: comma_expr ';'
{
ins_f_byte(F_POP_VALUE);
if (d_flag & DEBUG_BREAK_POINT)
ins_f_byte(F_BREAK_POINT);
/* if (exact_types && !TYPE($1,TYPE_VOID))
yyerror("Value thrown away"); */
}
| cond | while | do | for | switch | case | default | return ';'
| block | assertion ';'
| /* empty */ ';'
| F_BREAK ';' /* This code is a jump to 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_JUMP);
ins_short(current_break_address);
}
}
| F_CONTINUE ';' /* This code is a jump to a jump */
{
if (current_continue_address == 0)
yyerror("continue statement outside loop");
ins_f_byte(F_JUMP); ins_short(current_continue_address);
}
;
while: { push_explicit(current_continue_address);
push_explicit(current_break_address);
current_continue_address = mem_block[A_PROGRAM].current_size;
} F_WHILE '(' comma_expr ')'
{
ins_f_byte(F_JUMP_WHEN_NON_ZERO); ins_short(0); /* to block */
current_break_address = mem_block[A_PROGRAM].current_size;
ins_f_byte(F_JUMP); ins_short(0); /* Exit loop */
upd_short(current_break_address-2,
mem_block[A_PROGRAM].current_size);
}
statement
{
ins_f_byte(F_JUMP); ins_short(current_continue_address);
upd_short(current_break_address+1,
mem_block[A_PROGRAM].current_size);
current_break_address = pop_address();
current_continue_address = pop_address();
}
do: {
int tmp_save;
push_explicit(current_continue_address);
push_explicit(current_break_address);
/* Jump to start of loop. */
ins_f_byte(F_JUMP); tmp_save = mem_block[A_PROGRAM].current_size;
ins_short(0);
current_break_address = mem_block[A_PROGRAM].current_size;
/* Jump to end of loop. All breaks go through this one. */
ins_f_byte(F_JUMP); push_address(); ins_short(0);
current_continue_address = mem_block[A_PROGRAM].current_size;
upd_short(tmp_save, current_continue_address);
push_address();
} F_DO statement F_WHILE '(' comma_expr ')' ';'
{
ins_f_byte(F_JUMP_WHEN_NON_ZERO); ins_short(pop_address());
/* Fill in the break jump address in the beginning of the loop. */
upd_short(pop_address(), mem_block[A_PROGRAM].current_size);
current_break_address = pop_address();
current_continue_address = pop_address();
}
for: F_FOR '(' { push_explicit(current_continue_address);
push_explicit(current_break_address); }
for_expr ';' { ins_f_byte(F_POP_VALUE);
push_address();
}
for_expr ';' {
ins_f_byte(F_JUMP_WHEN_NON_ZERO);
ins_short(0); /* Jump to block of block */
current_break_address = mem_block[A_PROGRAM].current_size;
ins_f_byte(F_JUMP); ins_short(0); /* Out of loop */
current_continue_address =
mem_block[A_PROGRAM].current_size;
}
for_expr ')' {
ins_f_byte(F_POP_VALUE);
ins_f_byte(F_JUMP); ins_short(pop_address());
/* Here starts the block. */
upd_short(current_break_address-2,
mem_block[A_PROGRAM].current_size);
}
statement
{
ins_f_byte(F_JUMP); ins_short(current_continue_address);
/* Now, the address of the end of the block is known. */
upd_short(current_break_address+1, mem_block[A_PROGRAM].current_size);
current_break_address = pop_address();
current_continue_address = pop_address();
}
for_expr: /* EMPTY */ { ins_f_byte(F_CONST1); }
| comma_expr {;} ;
switch: F_SWITCH '(' comma_expr ')'
{
/* initialize switch */
push_explicit(current_case_number_heap);
push_explicit(current_case_string_heap);
push_explicit(zero_case_label);
push_explicit(current_break_address);
ins_f_byte(F_SWITCH);
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_FROM_CASE;
ins_f_byte(F_JUMP);
ins_short(0); /* break address to push, table is entered before */
ins_short(0); /* default address */
}
statement
{
int i;
int block_index;
int current_case_heap;
short default_addr;
/* Wrap up switch */
current_break_address &= ~BREAK_FROM_CASE;
/* It is not unusual that the last case/default has no break
*/
/* Default address */
if (!(default_addr = read_short(current_break_address + 3)))
{
upd_short(current_break_address + 3, /* no default given -> */
mem_block[A_PROGRAM].current_size); /* create one */
default_addr = mem_block[A_PROGRAM].current_size;
}
ins_f_byte(F_JUMP);
ins_short(current_break_address);
/* Table address */
upd_short(current_break_address - 2,
mem_block[A_PROGRAM].current_size);
/* What type of table? */
if (zero_case_label & (NO_STRING_CASE_LABELS|SOME_NUMERIC_CASE_LABELS))
{
block_index = A_CASE_NUMBERS;
current_case_heap = current_case_number_heap;
mem_block[A_PROGRAM].block[current_break_address - 3] = 0;
}
else
{
block_index = A_CASE_STRINGS;
current_case_heap = current_case_string_heap;
mem_block[A_PROGRAM].block[current_break_address - 3] = 1;
if (zero_case_label & 0xffff)
{
ins_long(0); /* not used */
ins_short(zero_case_label); /* the address */
}
else
{
ins_long(0); /* not used */
ins_short(default_addr); /* the address */
}
}
/* Dump the table */
{
struct case_heap_entry *ent, *end;
ent = (struct case_heap_entry *)
(mem_block[block_index].block + current_case_heap);
end = (struct case_heap_entry *)
(mem_block[block_index].block +
mem_block[block_index].current_size);
for (; ent < end; ent++)
{
ins_long(ent->key);
ins_short(ent->addr);
}
}
/* Break address */
upd_short(current_break_address + 1,
mem_block[A_PROGRAM].current_size);
mem_block[A_CASE_NUMBERS].current_size = current_case_number_heap;
mem_block[A_CASE_STRINGS].current_size = current_case_string_heap;
current_break_address = pop_address();
zero_case_label = pop_address();
current_case_string_heap = pop_address();
current_case_number_heap = pop_address();
}
case: F_CASE case_label ':'
{
/* Register label */
struct case_heap_entry temp;
if ( !( current_break_address & BREAK_FROM_CASE ) )
{
yyerror("Case outside switch");
break;
}
temp.key = $2.key;
temp.addr = mem_block[A_PROGRAM].current_size;
temp.line = current_line;
add_to_case_heap($2.block,&temp, NULL);
}
| F_CASE case_label F_RANGE case_label ':'
{
/* Register range label */
struct case_heap_entry temp1, temp2;
if ( !( current_break_address & BREAK_FROM_CASE ) )
{
yyerror("Case outside switch");
break;
}
if ($2.block != $4.block)
yyerror("Incompatible types in case label range bounds");
else
{
temp1.key = $2.key;
temp1.addr = -1;
temp1.line = current_line;
temp2.key = $4.key;
temp2.addr = mem_block[A_PROGRAM].current_size;
temp2.line = current_line;
add_to_case_heap($2.block, &temp1, &temp2);
}
}
case_label: constant
{
if ( !(zero_case_label & NO_STRING_CASE_LABELS) )
yyerror("Mixed case label list not allowed");
if ( $$.key = $1 )
zero_case_label |= SOME_NUMERIC_CASE_LABELS;
else
zero_case_label |= mem_block[A_PROGRAM].current_size;
$$.block = A_CASE_NUMBERS;
}
| string_constant
{
if ( zero_case_label & SOME_NUMERIC_CASE_LABELS )
yyerror("Mixed case label list not allowed");
zero_case_label &= ~NO_STRING_CASE_LABELS;
$$.key = (unsigned short)store_prog_string($1);
$$.block = A_CASE_STRINGS;
free($1);
}
constant: const1
| constant '|' const1 { $$ = $1 | $3; } ;
const1: const2
| const1 '^' const2 { $$ = $1 ^ $3; } ;
const2: const3
| const2 '&' const3 { $$ = $1 & $3; } ;
const3: const4
| const3 F_EQ const4 { $$ = $1 == $3; }
| const3 F_NE const4 { $$ = $1 != $3; } ;
const4: const5
| const4 '>' const5 { $$ = $1 > $3; }
| const4 F_GE const5 { $$ = $1 >= $3; }
| const4 '<' const5 { $$ = $1 < $3; }
| const4 F_LE const5 { $$ = $1 <= $3; } ;
const5: const6
| const5 F_LSH const6 { $$ = $1 << $3; }
| const5 F_RSH const6 { $$ = $1 >> $3; } ;
const6: const7
| const6 '+' const7 { $$ = $1 + $3; }
| const6 '-' const7 { $$ = $1 - $3; } ;
const7: const8
| const7 '*' const8 { $$ = $1 * $3; }
| const7 '%' const8 { $$ = $1 % $3; }
| const7 '/' const8 { $$ = $1 / $3; } ;
const8: const9
| '(' constant ')' { $$ = $2; } ;
const9: F_NUMBER
| '-' F_NUMBER { $$ = -$2; }
| F_NOT F_NUMBER { $$ = !$2; }
| '~' F_NUMBER { $$ = ~$2; } ;
default: F_DEFAULT ':'
{
if ( !( current_break_address & BREAK_FROM_CASE ) )
{
yyerror("Default outside switch");
break;
}
current_break_address &= ~(BREAK_FROM_CASE);
if ( read_short(current_break_address + 3 ) )
yyerror("Duplicate default");
upd_short(current_break_address + 3,
mem_block[A_PROGRAM].current_size);
current_break_address |= (BREAK_FROM_CASE);
} ;
comma_expr: expr0 { $$ = $1; }
| comma_expr { ins_f_byte(F_POP_VALUE); }
',' expr0
{ $$ = $4; } ;
expr0: expr01
| lvalue assign expr0
{
if (exact_types && !compatible_types($1, $3) &&
!($1 == TYPE_STRING && $3 == TYPE_NUMBER && $2 == F_ADD_EQ))
{
type_error("Bad assignment. Rhs", $3);
}
ins_f_byte($2);
$$ = $3;
}
| error assign expr01 { yyerror("Illegal LHS"); $$ = TYPE_ANY; };
expr01: expr1 { $$ = $1; }
| expr1 '?'
{
ins_f_byte(F_JUMP_WHEN_ZERO);
push_address();
ins_short(0);
}
expr01
{
int i;
i = pop_address();
ins_f_byte(F_JUMP); push_address(); ins_short(0);
upd_short(i, mem_block[A_PROGRAM].current_size);
}
':' expr01
{
upd_short(pop_address(), mem_block[A_PROGRAM].current_size);
if (exact_types && !compatible_types($4, $7)) {
type_error("Different types in ?: expr", $4);
type_error(" and ", $7);
}
if ($4 == TYPE_ANY) $$ = $7;
else if ($7 == TYPE_ANY) $$ = $4;
else if (TYPE($4, TYPE_MOD_POINTER|TYPE_ANY)) $$ = $7;
else if (TYPE($7, TYPE_MOD_POINTER|TYPE_ANY)) $$ = $4;
else $$ = $4;
};
assign: '=' { $$ = F_ASSIGN; }
| F_AND_EQ { $$ = F_AND_EQ; }
| F_OR_EQ { $$ = F_OR_EQ; }
| F_XOR_EQ { $$ = F_XOR_EQ; }
| F_LSH_EQ { $$ = F_LSH_EQ; }
| F_RSH_EQ { $$ = F_RSH_EQ; }
| F_ADD_EQ { $$ = F_ADD_EQ; }
| F_SUB_EQ { $$ = F_SUB_EQ; }
| F_MULT_EQ { $$ = F_MULT_EQ; }
| F_MOD_EQ { $$ = F_MOD_EQ; }
| F_DIV_EQ { $$ = F_DIV_EQ; };
return: F_RETURN
{
if (exact_types && !TYPE(exact_types, TYPE_VOID))
type_error("Must return a value for a function declared",
exact_types);
ins_f_byte(F_CONST0);
ins_f_byte(F_JUMP);
ins_label(return_label);
}
| F_RETURN comma_expr
{
if (exact_types && !TYPE($2, exact_types & TYPE_MASK))
type_error("Return type not matching", exact_types);
ins_f_byte(F_JUMP);
ins_label(return_label);
};
expr_list: /* empty */ { $$ = 0; }
| expr_list2 { $$ = $1; }
| expr_list2 ',' { $$ = $1; } ; /* Allow a terminating comma */
expr_list2: expr0 { $$ = 1; add_arg_type($1); }
| expr_list2 ',' expr0 { $$ = $1 + 1; add_arg_type($3); } ;
m_expr_list: /* empty */ { $$ = 0; }
| m_expr_list2 { $$ = $1; }
| m_expr_list2 ',' { $$ = $1; } ; /* Allow a terminating comma */
m_expr_list2: expr0 ':' expr1 { $$ = 2; add_arg_type($1); add_arg_type($3); }
| m_expr_list2 ',' expr0 ':' expr1 { $$ = $1 + 2; add_arg_type($3); add_arg_type($5); }
expr1: expr2 { $$ = $1; }
| expr2 F_LOR
{
ins_f_byte(F_DUP); ins_f_byte(F_JUMP_WHEN_NON_ZERO);
push_address();
ins_short(0);
ins_f_byte(F_POP_VALUE);
}
expr1
{
upd_short(pop_address(), mem_block[A_PROGRAM].current_size);
if ($1 == $4)
$$ = $1;
else
$$ = TYPE_ANY; /* Return type can't be known */
};
expr2: expr211 { $$ = $1; }
| expr211 F_LAND
{
ins_f_byte(F_DUP); ins_f_byte(F_JUMP_WHEN_ZERO);
push_address();
ins_short(0);
ins_f_byte(F_POP_VALUE);
}
expr2
{
upd_short(pop_address(), mem_block[A_PROGRAM].current_size);
if ($1 == $4)
$$ = $1;
else
$$ = TYPE_ANY; /* Return type can't be known */
} ;
expr211: expr212
| expr211 '|' expr212
{
if (exact_types && !TYPE($1,TYPE_NUMBER))
type_error("Bad argument 1 to |", $1);
if (exact_types && !TYPE($3,TYPE_NUMBER))
type_error("Bad argument 2 to |", $3);
$$ = TYPE_NUMBER;
ins_f_byte(F_OR);
};
expr212: expr213
| expr212 '^' expr213
{
if (exact_types && !TYPE($1,TYPE_NUMBER))
type_error("Bad argument 1 to ^", $1);
if (exact_types && !TYPE($3,TYPE_NUMBER))
type_error("Bad argument 2 to ^", $3);
$$ = TYPE_NUMBER;
ins_f_byte(F_XOR);
};
expr213: expr22
| expr213 '&' expr22
{
int t1 = $1 & TYPE_MASK, t3 = $3 & TYPE_MASK;
if (($1 & TYPE_MOD_POINTER && $3 & TYPE_MOD_POINTER) &&
(t1 == t3))
$$ = $1;
else if (((t1 == TYPE_ANY) && $3 & TYPE_MOD_POINTER) ||
($1 & TYPE_MOD_POINTER && (t3 == TYPE_ANY)))
$$ = TYPE_MOD_POINTER | TYPE_ANY;
else if ((t1 == TYPE_ANY) && (t3 == TYPE_ANY))
$$ = TYPE_ANY;
else
{
if (exact_types && !TYPE($1,TYPE_NUMBER))
type_error("Bad argument 1 to &", $1);
if (exact_types && !TYPE($3,TYPE_NUMBER))
type_error("Bad argument 2 to &", $3);
$$ = TYPE_NUMBER;
}
ins_f_byte(F_AND);
};
expr22: expr23
| expr24 F_EQ expr24
{
int t1 = $1 & TYPE_MASK, t2 = $3 & TYPE_MASK;
if (exact_types && t1 != t2 && t1 != TYPE_ANY && t2 != TYPE_ANY) {
type_error("== always false because of different types", $1);
type_error(" compared to", $3);
}
ins_f_byte(F_EQ);
$$ = TYPE_NUMBER;
};
| expr24 F_NE expr24
{
int t1 = $1 & TYPE_MASK, t2 = $3 & TYPE_MASK;
if (exact_types && t1 != t2 && t1 != TYPE_ANY && t2 != TYPE_ANY) {
type_error("!= always true because of different types", $1);
type_error(" compared to", $3);
}
ins_f_byte(F_NE);
$$ = TYPE_NUMBER;
};
expr23: expr24
| expr24 '>' expr24
{ $$ = TYPE_NUMBER; ins_f_byte(F_GT); };
| expr24 F_GE expr24
{ $$ = TYPE_NUMBER; ins_f_byte(F_GE); };
| expr24 '<' expr24
{ $$ = TYPE_NUMBER; ins_f_byte(F_LT); };
| expr24 F_LE expr24
{ $$ = TYPE_NUMBER; ins_f_byte(F_LE); };
expr24: expr25
| expr24 F_LSH expr25
{
ins_f_byte(F_LSH);
$$ = TYPE_NUMBER;
if (exact_types && !TYPE($1, TYPE_NUMBER))
type_error("Bad argument number 1 to '<<'", $1);
if (exact_types && !TYPE($3, TYPE_NUMBER))
type_error("Bad argument number 2 to '<<'", $3);
};
| expr24 F_RSH expr25
{
ins_f_byte(F_RSH);
$$ = TYPE_NUMBER;
if (exact_types && !TYPE($1, TYPE_NUMBER))
type_error("Bad argument number 1 to '>>'", $1);
if (exact_types && !TYPE($3, TYPE_NUMBER))
type_error("Bad argument number 2 to '>>'", $3);
};
expr25: expr27
| expr25 '+' expr27 /* Type checks of this case is complicated */
{ ins_f_byte(F_ADD); $$ = TYPE_ANY; };
| expr25 '-' expr27
{
int bad_arg = 0;
if (exact_types) {
if (!(TYPE($1, TYPE_NUMBER) || TYPE($1, TYPE_FLOAT)) &&
!($1 & TYPE_MOD_POINTER) ) {
type_error("Bad argument number 1 to '-'", $1);
bad_arg++;
}
if (!TYPE($3, $1) && !($3 & TYPE_MOD_POINTER) ) {
type_error("Bad argument number 2 to '-'", $3);
bad_arg++;
}
}
$$ = TYPE_ANY;
if (($1 & TYPE_MOD_POINTER) || ($3 & TYPE_MOD_POINTER))
$$ = TYPE_MOD_POINTER | TYPE_ANY;
if (!($1 & TYPE_MOD_POINTER) || !($3 & TYPE_MOD_POINTER)) {
if (exact_types && $$ != TYPE_ANY && !bad_arg)
yyerror("Arguments to '-' don't match");
$$ = ($1 & TYPE_MOD_POINTER)?$3:$1;
}
ins_f_byte(F_SUBTRACT);
};
expr27: expr28
| expr27 '*' expr3
{
if (exact_types && !(TYPE($1, TYPE_NUMBER) || TYPE($1, TYPE_FLOAT)))
type_error("Bad argument number 1 to '*'", $1);
if (exact_types && !TYPE($1, $3))
{
type_error("Bad argument number 2 to '*'", $3);
}
ins_f_byte(F_MULTIPLY);
$$ = $1;
};
| expr27 '%' expr3
{
if (exact_types && !TYPE($1, TYPE_NUMBER))
type_error("Bad argument number 1 to '%'", $1);
if (exact_types && !TYPE($3, TYPE_NUMBER))
type_error("Bad argument number 2 to '%'", $3);
ins_f_byte(F_MOD);
$$ = TYPE_NUMBER;
};
| expr27 '/' expr3
{
if (exact_types && !(TYPE($1, TYPE_NUMBER) || TYPE($1, TYPE_FLOAT)))
type_error("Bad argument number 1 to '/'", $1);
if (exact_types && !TYPE($3, $1))
type_error("Bad argument number 2 to '/'", $3);
ins_f_byte(F_DIVIDE);
$$ = $1;
};
expr28: expr3
| cast expr3
{
$$ = $1;
if (exact_types && $2 != TYPE_ANY && $2 != TYPE_UNKNOWN &&
$1 != TYPE_VOID)
type_error("Casts are only legal for type mixed, or when unknown", $2);
} ;
expr3: expr31
| F_INC lvalue
{
ins_f_byte(F_INC);
if (exact_types && !TYPE($2, TYPE_NUMBER))
type_error("Bad argument to ++", $2);
$$ = TYPE_NUMBER;
};
| F_DEC lvalue
{
ins_f_byte(F_DEC);
if (exact_types && !TYPE($2, TYPE_NUMBER))
type_error("Bad argument to --", $2);
$$ = TYPE_NUMBER;
};
| F_NOT expr3
{
ins_f_byte(F_NOT); /* Any type is valid here. */
$$ = TYPE_NUMBER;
};
| '~' expr3
{
ins_f_byte(F_COMPL);
if (exact_types && !TYPE($2, TYPE_NUMBER))
type_error("Bad argument to ~", $2);
$$ = TYPE_NUMBER;
};
| '-' expr3
{
ins_f_byte(F_NEGATE);
if (exact_types && !(TYPE($2, TYPE_NUMBER) || TYPE($2, TYPE_FLOAT)))
type_error("Bad argument to unary '-'", $2);
$$ = $2;
};
expr31: expr4
| lvalue F_INC
{
ins_f_byte(F_POST_INC);
if (exact_types && !TYPE($1, TYPE_NUMBER))
type_error("Bad argument to ++", $1);
$$ = TYPE_NUMBER;
};
| lvalue F_DEC
{
ins_f_byte(F_POST_DEC);
if (exact_types && !TYPE($1, TYPE_NUMBER))
type_error("Bad argument to --", $1);
$$ = TYPE_NUMBER;
};
expr4: function_call
| lvalue
{
int pos = mem_block[A_PROGRAM].current_size;
/* Some optimization. Replace the push-lvalue with push-value */
if (last_push_identifier == pos - 3)
mem_block[A_PROGRAM].block[last_push_identifier] =
F_IDENTIFIER - F_OFFSET;
else if (last_push_local == pos-2)
mem_block[A_PROGRAM].block[last_push_local] =
F_LOCAL_NAME - F_OFFSET;
else if (last_push_indexed == pos-1)
mem_block[A_PROGRAM].block[last_push_indexed] =
F_INDEX - F_OFFSET;
else if (last_push_indexed != 0)
fatal("Should be a push at this point !\n");
$$ = $1;
}
| expr4 '[' comma_expr F_RANGE comma_expr ']'
{
ins_f_byte(F_RANGE);
last_push_indexed = 0;
if (exact_types && !($1 & TYPE_MAPPING))
{
if (($1 & TYPE_MOD_POINTER) == 0 && !TYPE($1, TYPE_STRING))
type_error("Bad type to indexed value", $1);
if (!TYPE($3, TYPE_NUMBER))
type_error("Bad type of index", $3);
if (!TYPE($5, TYPE_NUMBER))
type_error("Bad type of index", $5);
}
if ($1 == TYPE_ANY)
$$ = TYPE_ANY;
else if (TYPE($1, TYPE_STRING))
$$ = TYPE_STRING;
else if ($1 & TYPE_MOD_POINTER)
$$ = $1;
else if (exact_types)
type_error("Bad type of argument used for range", $1);
};
| expr4 '[' F_RANGE { ins_f_byte(F_CONST0); } comma_expr ']'
{
ins_f_byte(F_RANGE);
last_push_indexed = 0;
if (exact_types && !($1 & TYPE_MAPPING))
{
if (($1 & TYPE_MOD_POINTER) == 0 && !TYPE($1, TYPE_STRING))
type_error("Bad type to indexed value", $1);
if (!TYPE($5, TYPE_NUMBER))
type_error("Bad type of index", $5);
}
if ($1 == TYPE_ANY)
$$ = TYPE_ANY;
else if (TYPE($1, TYPE_STRING))
$$ = TYPE_STRING;
else if ($1 & TYPE_MOD_POINTER)
$$ = $1;
else if (exact_types)
type_error("Bad type of argument used for range", $1);
};
| expr4 '[' comma_expr F_RANGE ']'
{
ins_f_byte(F_NUMBER);
ins_long(~(1<<31)); /* MAXINT */
ins_f_byte(F_RANGE);
last_push_indexed = 0;
if (exact_types && !($1 & TYPE_MAPPING))
{
if (($1 & TYPE_MOD_POINTER) == 0 && !TYPE($1, TYPE_STRING))
type_error("Bad type to indexed value", $1);
if (!TYPE($3, TYPE_NUMBER))
type_error("Bad type of index", $3);
}
if ($1 == TYPE_ANY)
$$ = TYPE_ANY;
else if (TYPE($1, TYPE_STRING))
$$ = TYPE_STRING;
else if ($1 & TYPE_MOD_POINTER)
$$ = $1;
else if (exact_types)
type_error("Bad type of argument used for range", $1);
};
| string | number
| real
| '(' comma_expr ')' { $$ = $2; }
| catch { $$ = TYPE_ANY; }
| sscanf { $$ = TYPE_NUMBER; }
| parse_command { $$ = TYPE_NUMBER; }
| '(' '{' expr_list '}' ')'
{
pop_arg_stack($3); /* We don't care about these types */
ins_f_byte(F_AGGREGATE);
ins_short($3);
$$ = TYPE_MOD_POINTER | TYPE_ANY;
}
| '(' '[' m_expr_list ']' ')'
{
pop_arg_stack($3);
ins_f_byte(F_M_AGGREGATE);
ins_short($3);
$$ = TYPE_MAPPING;
};
catch: F_CATCH { ins_f_byte(F_CATCH); push_address(); ins_short(0);}
'(' comma_expr ')'
{
ins_f_byte(F_POP_VALUE);
ins_f_byte(F_CONST0);
ins_f_byte(F_THROW);
upd_short(pop_address(),
mem_block[A_PROGRAM].current_size);
};
sscanf: F_SSCANF '(' expr0 ',' expr0 lvalue_list ')'
{
ins_f_byte(F_SSCANF); ins_byte($6 + 2);
}
parse_command: F_PARSE_COMMAND '(' expr0 ',' expr0 ',' expr0 lvalue_list ')'
{
ins_f_byte(F_PARSE_COMMAND); ins_byte($8 + 3);
}
lvalue_list: /* empty */ { $$ = 0; }
| ',' lvalue lvalue_list { $$ = 1 + $3; } ;
identifier: F_IDENTIFIER
| F_COLON_COLON identifier
{
$$ = xalloc(strlen($2) + 3);
sprintf($$, "::%s", $2);
free($2);
}
| F_IDENTIFIER F_COLON_COLON identifier
{
$$ = xalloc(strlen($1) + strlen($3) + 3);
sprintf($$, "%s::%s", $1, $3);
free($1);
free($3);
} ;
fun_identifier: F_IDENTIFIER
| F_LSH { $$ = DTOR_FUNC;}
| F_RSH { $$ = CTOR_FUNC;}
lvalue: identifier
{
int i = verify_declared($1);
last_push_identifier = mem_block[A_PROGRAM].current_size;
ins_f_byte(F_PUSH_IDENTIFIER_LVALUE);
ins_byte(variable_inherit_found);
ins_byte(variable_index_found);
free($1);
if (i == -1)
$$ = TYPE_ANY;
else
$$ = i & TYPE_MASK;
}
| F_LOCAL_NAME
{
last_push_local = mem_block[A_PROGRAM].current_size;
ins_f_byte(F_PUSH_LOCAL_VARIABLE_LVALUE);
ins_byte($1);
$$ = type_of_locals[$1];
}
| expr4 '[' comma_expr ']'
{
last_push_indexed = mem_block[A_PROGRAM].current_size;
ins_f_byte(F_PUSH_INDEXED_LVALUE);
if (exact_types && !($1 & TYPE_MAPPING)) {
if (($1 & TYPE_MOD_POINTER) == 0 && !TYPE($1, TYPE_STRING))
type_error("Bad type to indexed value", $1);
if (!TYPE($3, TYPE_NUMBER))
type_error("Bad type of index", $3);
}
if ($1 == TYPE_ANY)
$$ = TYPE_ANY;
else if (TYPE($1, TYPE_STRING))
$$ = TYPE_NUMBER;
else if ($1 == TYPE_MAPPING)
$$ = TYPE_ANY;
else
$$ = $1 & TYPE_MASK & ~TYPE_MOD_POINTER;
};
real: F_FLOATC
{
ins_f_byte(F_FLOATC);
ins_long(*((int *)&$<real>1));
$$ = TYPE_FLOAT;
};
string: F_STRING
{
ins_f_byte(F_STRING);
ins_short(store_prog_string($1));
free($1);
$$ = TYPE_STRING;
};
string_constant: string_con1
{
$$ = $1;
};
string_con1: F_STRING
| string_con1 '+' F_STRING
{
$$ = xalloc( strlen($1) + strlen($3) + 1 );
strcpy($$, $1);
strcat($$, $3);
free($1);
free($3);
};
function_call: function_name '(' expr_list ')'
{
/* Note that this code could be made a lot cleaner if some
* support functions were added. (efun_call() is a good one)
*/
int inherited_override = !!strchr($1, ':');
int efun_override = inherited_override && strncmp($1,"efun::", 6) == 0;
int is_sfun = 0;
int f;
$$ = TYPE_ANY; /* in case anything goes wrong we need a default type. /LA */
if (inherited_override && !efun_override)
{
struct function *funp;
/* Find the right function to call
This assumes max 255 inherited programs
and 32767 functions in one program.
*/
if (defined_function($1))
{
funp = &function_prog_found->functions[function_index_found];
$$ = funp->type_flags & TYPE_MASK;
ins_f_byte(F_CALL_NON_VIRT);
ins_byte (function_inherit_found);
ins_short (function_index_found);
ins_byte($3); /* Number of arguments */
}
else
{
char buff[100];
sprintf(buff, "Function %.50s undefined", $1);
yyerror(buff);
}
}
/* All simul_efuns are considered defined.
*/
else if (!efun_override &&
(defined_function ($1) || (is_sfun = 1) && is_simul_efun ($1)) )
{
struct function *funp;
unsigned short *arg_indices;
unsigned short *arg_types;
if (function_prog_found)
{
funp = &(function_prog_found->
functions[function_index_found]);
arg_indices = function_prog_found->type_start;
arg_types = function_prog_found->argument_types;
}
else
{
funp = FUNCTION(function_index_found);
/* Beware... these are pointers to volatile structures
*/
arg_indices = (unsigned short *) mem_block[A_ARGUMENT_INDEX].block;
arg_types = (unsigned short *) mem_block[A_ARGUMENT_TYPES].block;
/* Assumption: exact_types implies correct
values for arg_types
*/
}
/* Private functions in inherited programs may not be called.
*/
if (exact_types && function_prog_found &&
function_type_mod_found & TYPE_MOD_PRIVATE)
{
char buff[100];
sprintf (buff, "Function %.44s marked 'private'",
funp->name);
yyerror (buff);
}
$$ = funp->type_flags & TYPE_MASK;
if (is_sfun)
{
ins_f_byte(F_CALL_SIMUL);
store_reloc_data(R_CALL, mem_block[A_PROGRAM].current_size,
$1,0,0);
}
else if (funp->type_flags & TYPE_MOD_NO_MASK)
{
ins_f_byte(F_CALL_NON_VIRT);
}
else
{
ins_f_byte (F_CALL_VIRT);
if (function_prog_found)
store_reloc_data(R_CALL,
mem_block[A_PROGRAM].current_size,
$1,0,0);
}
ins_byte (function_inherit_found);
ins_short (function_index_found);
/* Insert function name into string list and code its index
*/
ins_byte ($3);
/*
* Check number of arguments.
*/
if ((funp->type_flags & NAME_STRICT_TYPES) && exact_types &&
funp->num_arg != $3 &&
/* An old varargs function */
!((funp->type_flags & TYPE_MOD_VARARGS) &&
$3 < funp->num_arg) &&
/* A true varargs function? */
!((funp->type_flags & TYPE_MOD_TRUE_VARARGS) &&
$3 + 1 >= funp->num_arg) &&
/* A function with default values for arguments? */
!($3 < funp->num_arg && funp->first_default <= $3))
{
char buff[100];
sprintf(buff, "Wrong number of arguments to %.60s", $1);
yyerror(buff);
}
/*
* Check the argument types.
*/
if (funp->type_flags & NAME_STRICT_TYPES &&
exact_types && arg_indices &&
arg_indices[function_index_found] != INDEX_START_NONE)
{
int i, first;
int num_check = funp->num_arg;
if (funp->type_flags & TYPE_MOD_TRUE_VARARGS)
num_check--;
first = arg_indices[function_index_found];
for (i=0; i < num_check && i < $3; i++)
{
int tmp = get_argument_type(i, $3);
if (!TYPE(tmp, arg_types[first + i]))
{
char buff[100];
sprintf(buff, "Bad type for argument %d %s", i+1,
get_two_types(arg_types[first+i], tmp));
yyerror(buff);
}
}
}
}
else if (efun_override || (f = lookup_predef($1)) != -1)
{
int min, max, def, *argp;
extern int efun_arg_types[];
if (efun_override)
f = lookup_predef($1+6);
if (f == -1) /* Only possible for efun_override */
{
char buff[100];
sprintf(buff, "Unknown efun: %s", $1+6);
yyerror(buff);
}
else
{
min = instrs[f-F_OFFSET].min_arg;
max = instrs[f-F_OFFSET].max_arg;
def = instrs[f-F_OFFSET].Default;
$$ = instrs[f-F_OFFSET].ret_type;
argp = &efun_arg_types[instrs[f-F_OFFSET].arg_index];
if (def && $3 == min-1)
{
ins_f_byte(def);
max--;
min--;
}
else if ($3 < min)
{
char bff[100];
sprintf(bff, "Too few arguments to %s",
instrs[f-F_OFFSET].name);
yyerror(bff);
}
else if ($3 > max && max != -1)
{
char bff[100];
sprintf(bff, "Too many arguments to %s",
instrs[f - F_OFFSET].name);
yyerror(bff);
}
else if (max != -1 && exact_types)
{
/*
* Now check all types of the arguments to efuns.
*/
int i, argn;
char buff[100];
for (argn=0; argn < $3; argn++)
{
int tmp = get_argument_type(argn, $3);
for(i=0; !TYPE(argp[i], tmp) && argp[i] != 0; i++)
;
if (argp[i] == 0)
{
sprintf(buff,
"Bad argument %d type to efun %s()",
argn+1, instrs[f-F_OFFSET].name);
yyerror(buff);
}
while(argp[i] != 0)
i++;
argp += i + 1;
}
}
ins_f_byte(f);
/* Only store number of arguments for instructions
* that allowed a variable number.
*/
if (max != min)
ins_byte($3); /* Number of actual arguments */
}
}
else
{
if (exact_types)
{
char buff[200];
sprintf (buff, "Undefined function: %.50s", $1);
yyerror (buff);
}
/* Function not found
*/
ins_f_byte(F_CALL_VIRT);
store_reloc_data(R_CALL, mem_block[A_PROGRAM].current_size,
$1,0,0);
ins_byte (255);
ins_short (-1);
ins_byte($3); /* Number of arguments */
$$ = TYPE_ANY; /* just a guess */
}
free($1);
pop_arg_stack($3); /* Argument types not needed more */
}
/* ident, not name. Calls to :: functions are not allowed anyway /Dark
*/
| expr4 F_ARROW F_IDENTIFIER
{
ins_f_byte(F_STRING);
ins_short(store_prog_string($3));
free($3);
}
'(' expr_list ')'
{
ins_f_byte(F_CALL_OTHER);
ins_byte($6 + 2);
$$ = TYPE_ANY; /* TYPE_UNKNOWN forces casts */
pop_arg_stack($6); /* No good need of these arguments */
};
function_name: identifier
cond: condStart
statement
{
int i;
i = pop_address();
ins_f_byte(F_JUMP); push_address(); ins_short(0);
upd_short(i, mem_block[A_PROGRAM].current_size);
}
optional_else_part
{ upd_short(pop_address(), mem_block[A_PROGRAM].current_size); } ;
condStart: F_IF '(' comma_expr ')'
{
ins_f_byte(F_JUMP_WHEN_ZERO);
push_address();
ins_short(0);
} ;
optional_else_part: /* empty */
| F_ELSE statement ;
%%
int link_errors;
static void ins_f_byte(unsigned int b)
{
if (b - F_OFFSET < 256)
ins_byte((char)(b - F_OFFSET));
else
{
ins_byte((char)(F_EXT - F_OFFSET));
ins_short((short)(b - F_OFFSET));
}
}
void
yyerror(char *str)
{
extern int num_parse_error;
char spos[500];
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);
num_parse_error++;
}
static int
check_declared(char *str)
{
struct variable *vp;
extern char *findstring (char *);
int offset;
int inh;
char *super_name = 0;
char *sub_name;
char *real_name;
char *search;
variable_index_found = variable_inherit_found = 255;
real_name = strrchr(str, ':') + 1;
sub_name = strchr(str, ':') + 2;
if(!(real_name = (findstring((real_name == (char *)1) ? str : real_name))))
return -1;
if (sub_name == (char *)2)
for (offset = 0; offset < mem_block[A_VARIABLES].current_size;
offset += sizeof (struct variable))
{
vp = (struct variable *)&mem_block[A_VARIABLES].block[offset];
/* Only index, prog, and type will be defined. */
if (real_name == vp->name)
{
variable_type_mod_found = vp->type;
variable_index_found = offset / sizeof (struct variable);
variable_inherit_found = 255;
return variable_index_found;
}
}
else
if (sub_name - str > 2)
{
super_name = xalloc(sub_name - str - 1);
memcpy(super_name, str, sub_name - str - 2);
super_name[sub_name - str - 2] = 0;
if (!strcmp(super_name, "this"))
return check_declared(sub_name);
}
else
str = sub_name;
/* Look for the variable in the inherited programs
*/
for (inh = mem_block[A_INHERITS].current_size / sizeof (struct inherit) - 1;
inh >= 0; inh -= ((struct inherit *)mem_block[A_INHERITS].block)[inh].prog->
num_inherited)
{
if (super_name &&
!strcmp(super_name, ((struct inherit *)mem_block[A_INHERITS].block)[inh].name))
search = sub_name;
else
search = str;
if (find_status (((struct inherit *)mem_block[A_INHERITS].block)[inh].prog,
search, TYPE_MOD_PRIVATE) != -1)
{
/* Adjust for inherit-type */
int type = ((struct inherit *)mem_block[A_INHERITS].block)[inh].type;
if (variable_type_mod_found & TYPE_MOD_PRIVATE)
type &= ~TYPE_MOD_PUBLIC;
if (variable_type_mod_found & TYPE_MOD_PUBLIC)
type &= ~TYPE_MOD_PRIVATE;
variable_type_mod_found |= type & TYPE_MOD_MASK;
variable_inherit_found += inh -
(((struct inherit *)mem_block[A_INHERITS].block)[inh].prog->
num_inherited - 1);
return 1;
}
}
return -1;
}
static int
verify_declared(char *str)
{
int r;
r = check_declared(str);
if (r == -1)
{
char buff[100];
(void)sprintf(buff, "Variable %s not declared !", str);
yyerror(buff);
return -1;
}
if (variable_inherit_found == 255)
return ((struct variable *)mem_block[A_VARIABLES].block)[variable_index_found].
type;
else
return ((struct inherit *)mem_block[A_INHERITS].block)[variable_inherit_found].
prog->variable_names[variable_index_found].type;
}
void
free_all_local_names()
{
int i;
for (i=0; i<current_number_of_locals; i++) {
free(local_names[i]);
local_names[i] = 0;
}
current_number_of_locals = 0;
}
int
add_local_name(char *str, int type)
{
if (current_number_of_locals == MAX_LOCAL)
yyerror("Too many local variables");
else {
type_of_locals[current_number_of_locals] = type;
local_names[current_number_of_locals++] = str;
}
return current_number_of_locals - 1;
}
int
find_inherit(struct program *prog1, struct program *prog)
{
int i;
for (i = 0; i < (int)prog1->num_inherited; i++)
if (prog1->inherit[i].prog == prog)
return i;
return -1;
}
static void
copy_inherits(struct program *from, int type, char *name)
{
int i;
struct inherit inh;
int j[256], k = 0;
char buf[256];
access_program(from);
for(i = 0; i < from->num_variables; i++)
if ((type | from->variable_names[i].type) & TYPE_MOD_NO_MASK &&
check_declared(from->variable_names[i].name) != -1 &&
(variable_inherit_found == 255 || ((struct inherit *)
(mem_block[A_INHERITS].block))[variable_inherit_found].prog != from))
{
sprintf(buf,"Redefinition of no_mask variable %s in program %s.\n",
from->variable_names[i].name,
from->name);
yyerror(buf);
}
for (i = 0; i < (int) from->num_functions; i++)
if ((type | from->functions[i].type_flags) & TYPE_MOD_NO_MASK &&
defined_function(from->functions[i].name) &&
function_prog_found != from)
{
sprintf(buf,"Redefinition of no_mask function %s in program %s.\n",
from->functions[i].name,
from->name);
yyerror(buf);
}
for (i = from->num_inherited - 2; i >= 0;
i -= from->inherit[i].prog->num_inherited)
j[k++] = i;
for (i = j[--k]; k >= 0; i = j[--k])
{
/* Correct the type */
int new_type = type;
int old_type = from->inherit[i].type;
if (old_type & TYPE_MOD_PRIVATE)
new_type &= ~TYPE_MOD_PUBLIC;
if (old_type & TYPE_MOD_PUBLIC)
new_type &= ~TYPE_MOD_PRIVATE;
copy_inherits(from->inherit[i].prog,
old_type | new_type,
from->inherit[i].name);
}
inh = from->inherit[from->num_inherited - 1]; /* Make a copy */
/* Adjust the info */
inh.name = make_shared_string(name);
inh.type = type;
add_to_mem_block (A_INHERITS, (char *)&inh, sizeof inh);
}
static int
check_inherits(struct program *from)
{
int i, update = 0;
struct object *ob;
int len = strlen(from->name) - 1;
char *ob_name = xalloc(len);
strncpy(ob_name, from->name, len - 1);
ob_name[len - 1] = 0;
ob = find_object2(ob_name);
free(ob_name);
if (!ob || ob->prog != from)
return 0;
for (i = from->num_inherited - 2; i >= 0;
i -= from->inherit[i].prog->num_inherited)
if (!check_inherits(from->inherit[i].prog))
update = 1;
if (update)
{
if (ob) destruct_object(ob);
return 0;
}
return 1;
}
void
hash_func (int size, struct function *from, struct function_hash *to)
{
int first_hole; /* Keep chained lists through the hash table */
int first_collision;
int last_collision, next_collision;
int i, probe;
int *back;
if (size <= 0)
return;
back = (int *) alloca(sizeof(int) * size);
/* Prepare the lists */
for (first_hole = 0, first_collision = -1, i = 0; i < size; i++)
{
to[i].next_hashed_function = i+1; /* forward */
back[i] = i-1; /* back */
to[i].name = 0; /* free entry */
}
to[size-1].next_hashed_function = -1;
/* Hash all non-collisions and mark collisions */
for (i = 0, last_collision = -1; i < size; i++)
{
probe = PTR_HASH(from[i].name, size);
if (!to[probe].name)
{ /* free */
if (back[probe] == -1)
first_hole = to[probe].next_hashed_function;
else
to[back[probe]].next_hashed_function =
to[probe].next_hashed_function;
if (to[probe].next_hashed_function != -1)
back[to[probe].next_hashed_function] = back[probe];
to[probe].name = from[i].name;
to[probe].func_index = i;
from[i].hash_idx = probe;
to[probe].next_hashed_function = -1;
}
else
{ /* collision */
if (first_collision == -1)
last_collision = first_collision = i;
else
{
from[last_collision].hash_idx = i;
last_collision = i;
}
from[i].hash_idx = -1;
}
}
/* Plug collisions into the holes */
for ( ; first_collision != -1;
first_collision = next_collision)
{
i = first_hole;
first_hole = to[i].next_hashed_function;
to[i].name = from[first_collision].name;
to[i].func_index = first_collision;
to[i].next_hashed_function = -1;
next_collision = from[first_collision].hash_idx;
from[first_collision].hash_idx = i;
for (probe = PTR_HASH (to[i].name, size);
to[probe].next_hashed_function != -1;
probe = to[probe].next_hashed_function)
;
to[probe].next_hashed_function = i;
}
/* Finished */
}
/*
* This function is called from lex.c for every new line read.
*/
void
store_line_number_info(int ifile, int line)
{
static int cur_pc, cur_line, cur_file;
static int prev_file, prev_line;
char delta, tmp;
if (ifile == -1)
{
cur_pc = cur_line = cur_file = 0;
prev_file = prev_line = 0;
return;
}
delta = mem_block[A_PROGRAM].current_size - cur_pc;
if (delta)
{
if (prev_file != cur_file || prev_line - cur_line < 1 ||
prev_line - cur_line > 0xff)
{
tmp = 0xfe;
add_to_mem_block(A_LINENUMBERS, &tmp, 1);
tmp = prev_file;
add_to_mem_block(A_LINENUMBERS, &tmp, 1);
tmp = prev_line >> 8;
add_to_mem_block(A_LINENUMBERS, &tmp, 1);
tmp = 0xff & prev_line;
add_to_mem_block(A_LINENUMBERS, &tmp, 1);
}
else if (prev_line - cur_line == 2)
{
tmp = 0;
add_to_mem_block(A_LINENUMBERS, &tmp, 1);
}
else if (prev_line - cur_line > 2)
{
tmp = 0xff;
add_to_mem_block(A_LINENUMBERS, &tmp, 1);
tmp = prev_line - cur_line - 1;
add_to_mem_block(A_LINENUMBERS, &tmp, 1);
}
add_to_mem_block(A_LINENUMBERS, &delta, 1);
cur_pc = mem_block[A_PROGRAM].current_size;
cur_line = prev_line;
cur_file = prev_file;
}
prev_line = line;
prev_file = ifile;
}
void
old_store_line_number_info(int ifile, int line)
{
static int old_offset = -1;
unsigned short offset = mem_block[A_PROGRAM].current_size;
unsigned short incfilenum = ifile;
unsigned short file_line = line;
#if 0
if (mem_block[A_LINENUMBERS].current_size >= 3 * sizeof(short) &&
offset == old_offset)
{
mem_block[A_LINENUMBERS].current_size -=
3 * sizeof(short);
}
old_offset = offset;
#endif
add_to_mem_block(A_LINENUMBERS, (char *)&offset, sizeof offset);
add_to_mem_block(A_LINENUMBERS, (char *)&incfilenum, sizeof incfilenum);
add_to_mem_block(A_LINENUMBERS, (char *)&file_line, sizeof file_line);
}
static void
store_reloc_data(char type, unsigned short address, char *name,
int value, char modifier)
{
struct reloc rel;
rel.type = type;
rel.modifier = modifier;
rel.address = address;
rel.name = string_copy(name);
rel.value = value;
add_to_mem_block(A_RELOC, (char *)&rel, sizeof(struct reloc));
}
static char *
get_type_name(int type)
{
static char buff[100];
static char *type_name[] = { "unknown", "int", "string",
"void", "object", "mixed", "mapping",
"float" };
int pointer = 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_MASK;
if (type & TYPE_MOD_POINTER) {
pointer = 1;
type &= ~TYPE_MOD_POINTER;
}
if (type >= sizeof type_name / sizeof type_name[0])
fatal("Bad type\n");
strcat(buff, type_name[type]);
strcat(buff," ");
if (pointer)
strcat(buff, "* ");
return buff;
}
void
type_error(char *str, int type)
{
static char buff[100];
char *p;
p = get_type_name(type);
if (strlen(str) + strlen(p) + 5 >= sizeof buff)
{
yyerror(str);
}
else
{
strcpy(buff, str);
strcat(buff, ": \"");
strcat(buff, p);
strcat(buff, "\"");
yyerror(buff);
}
}
int
remove_undefined_prototypes (int num_functions, struct function *functions)
{
int i;
for (i = 0; i < num_functions;i++)
{
if (functions[i].type_flags & NAME_PROTOTYPE)
{
char buff[500];
sprintf(buff, "Function %s declared but never defined",
functions[i].name);
yyerror(buff);
}
}
return num_functions;
}
/*
* Compile an LPC file.
*/
void
compile_file()
{
int yyparse();
prolog();
yyparse();
epilog();
}
static char *
get_two_types(int type1, int 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;
}
/*
This is used for two purposes. Both in the BINARIES package to store
change dates for includefiles in a compiled program.
Also as an index of includefiles for giving correct runtime error
messages references.
*/
void
remember_include(char *buf)
{
struct stat sbuf;
char number[128];
if (stat(buf, &sbuf)==-1)
fatal("LIB not able to stat open file %s\n",buf);
sprintf(number,"%d:", sbuf.st_mtime);
add_to_mem_block(A_INCLUDES, number, strlen(number));
add_to_mem_block(A_INCLUDES, buf, strlen(buf) + 1);
}
/*
* The program has been compiled. Prepare a 'struct program' to be returned.
*/
int current_id_number = 1;
#define H_OFFSET(arg) (((char *)&(((struct program *)0)->arg)) -\
((char *)((struct program *)0)))
static struct section_desc sec_hdr[] =
{
{A_HEADER, -1, -1, sizeof(struct program)},
{A_INHERITS, H_OFFSET(inherit), H_OFFSET(num_inherited),
sizeof(struct inherit)},
{A_FUNC_HASH, H_OFFSET(func_hash), -1, sizeof(struct function_hash)},
{-1, 0, 0, 0},
};
static struct section_desc sec_exe[] =
{
{A_PROGRAM, H_OFFSET(program), H_OFFSET(program_size), 1},
{A_RODATA, H_OFFSET(rodata), H_OFFSET(rodata_size), 1},
{A_FUNCTIONS, H_OFFSET(functions), H_OFFSET(num_functions),
sizeof(struct function)},
{A_VARIABLES, H_OFFSET(variable_names), H_OFFSET(num_variables),
sizeof(struct variable)},
{A_CFUN, H_OFFSET(cfuns), -1, sizeof(struct cfun_desc)},
{-1, 0, 0, 0},
};
static struct section_desc sec_dbg[] =
{
{A_LINENUMBERS, H_OFFSET(line_numbers),
H_OFFSET(sizeof_line_numbers), 1},
{A_INCLUDES, H_OFFSET(include_files),
H_OFFSET(sizeof_include_files), 1},
{-1, 0, 0, 0},
};
struct segment_desc segm_desc[] =
{
/* S_HDR */
-1, -1, H_OFFSET(total_size),sec_hdr,
/* S_EXEC */
H_OFFSET(program), H_OFFSET(swap_num), H_OFFSET(exec_size),sec_exe,
/* S_DBG */
H_OFFSET(line_numbers), H_OFFSET(swap_lineno_index),
H_OFFSET(debug_size),sec_dbg,
-1, -1, -1, (struct section_desc *)NULL,
};
char *
load_segments(struct segment_desc *seg, struct mem_block *mem_block)
{
char *hdr = 0;
int size;
char *block;
struct section_desc *sect;
for ( ; seg->sections != NULL; seg++)
{
size = 0;
for (sect = seg->sections; sect->section != -1; sect++)
size += align(mem_block[sect->section].current_size);
if (size)
block = xalloc(size);
else
block = xalloc(1);
if (!hdr)
hdr = block;
if (seg->ptr_offset != -1)
*(char **)(hdr + seg->ptr_offset) = block;
for (sect = seg->sections; sect->section != -1; sect++)
{
memcpy(block, mem_block[sect->section].block,
mem_block[sect->section].current_size);
if (sect->ptr_offset != -1)
*(char **)(hdr + sect->ptr_offset) = block;
if (sect->num_offset != -1)
*(unsigned short *)(hdr + sect->num_offset) =
mem_block[sect->section].current_size /
sect->ent_size;
block += align(mem_block[sect->section].current_size);
}
if (seg->size_offset != -1)
*(int *)(hdr + seg->size_offset) = size;
}
return hdr;
}
static int
process_reloc(struct reloc *reloc, int num_relocs, int num_inherited)
{
unsigned int i, j;
char *name;
unsigned short fix;
int psize;
psize = mem_block[A_PROGRAM].current_size;
link_errors = 0;
for (i = 0; i < num_relocs; i++, reloc++)
{
if (reloc->address >= psize)
fatal("Corrupt relocation address.\n");
name = reloc->name;
switch (reloc->type)
{
int call_efun;
case R_CALL:
call_efun = 0;
if (!defined_function(name) ||
function_type_mod_found & TYPE_MOD_PRIVATE &&
function_inherit_found != num_inherited)
{
if (is_simul_efun(name))
{
call_efun = F_CALL_SIMUL;
function_index_found = store_prog_string(name);
function_inherit_found = 0;
}
else
{
link_errors++;
fprintf(stderr,"%s Function %s doesn't exist.\n",
inner_get_srccode_position(
reloc->address,
mem_block[A_LINENUMBERS].block,
mem_block[A_LINENUMBERS].current_size,
mem_block[A_INCLUDES].block,
current_file), name);
fflush(stderr);
break;
}
}
else if (strchr(name,':') || function_type_mod_found & TYPE_MOD_NO_MASK)
call_efun = F_CALL_NON_VIRT;
else
call_efun = F_CALL_VIRT;
fix = function_index_found;
mem_block[A_PROGRAM].block[reloc->address - 1] =
call_efun - F_OFFSET;
mem_block[A_PROGRAM].block[reloc->address] =
function_inherit_found;
mem_block[A_PROGRAM].block[reloc->address + 1] =
((char *)&fix)[0];
mem_block[A_PROGRAM].block[reloc->address + 2] =
((char *)&fix)[1];
break;
default:
fatal("Unsupported reloc data (%d).\n", reloc->type);
}
}
return link_errors;
}
int
link_C_functions(char *name)
{
int i, j, errors = 0;
struct cfun_desc cfun;
int num_inherited;
num_inherited =
mem_block[A_INHERITS].current_size /
sizeof(struct inherit);
for(i = 0; interface[i]; i++)
if (!strcmp(interface[i]->program, name))
for(j = 0; interface[i]->vars[j]; j++)
{
if (check_declared(interface[i]->vars[j]->name)
== -1)
{
char buf[100];
sprintf(buf,
"Variable %s (referenced from cfun) not defined.\n",
interface[i]->vars[j]->name);
current_line = -1;
yyerror(buf);
}
if (variable_inherit_found == 255)
variable_inherit_found = num_inherited;
cfun.idx = variable_index_found - num_inherited;
cfun.inh = variable_inherit_found;
add_to_mem_block(A_CFUN, (char *)&cfun, sizeof(cfun));
}
return errors;
}
void
epilog()
{
int size, i, j, ix, psize;
char *p;
struct function *funp;
extern int pragma_resident;
extern int current_time;
int functions_left; /* Functions left after removing dangling prototypes */
extern total_program_size;
char *l;
int has_invariant = -1;
int lsize;
struct inherit inherit_self;
int has_dtor, has_ctor;
#ifdef DEBUG
if (num_parse_error == 0 && type_of_arguments.current_size != 0)
fatal("Failed to deallocate argument type stack\n");
#endif
/*
* Define the .CTOR function, but only if there was any code
* to initialize.
*/
if (defined_function(".CTOR") && !function_prog_found)
{
has_ctor = function_index_found;
}
else
has_ctor = -1;
if (defined_function(".DTOR") && !function_prog_found)
{
has_dtor = function_index_found;
}
else
has_dtor = -1;
if (first_last_initializer_end != last_initializer_end)
{
if (has_ctor != -1)
{
struct function *funp;
funp = &((struct function *)
mem_block[A_FUNCTIONS].block)[has_ctor];
upd_short(last_initializer_end, funp->offset);
funp->offset = 0;
}
else
{
has_ctor = mem_block[A_FUNCTIONS].current_size /
sizeof(struct function);
define_new_function(".CTOR", 0, 0, 0,
TYPE_MOD_PRIVATE | TYPE_VOID, 0);
/*
* Change the last jump after the last initializer into a
* return(1) statement.
*/
mem_block[A_PROGRAM].block[last_initializer_end - 1] =
F_DO_INVARIANTS - F_OFFSET;
mem_block[A_PROGRAM].block[last_initializer_end] =
F_CONST1 - F_OFFSET;
mem_block[A_PROGRAM].block[last_initializer_end + 1] =
F_RETURN - F_OFFSET;
}
}
if (invariant_last_address)
{
has_invariant = mem_block[A_FUNCTIONS].current_size /
sizeof(struct function);
define_new_function(".INV", 0, 0, invariant_first_address,
TYPE_MOD_PRIVATE | TYPE_VOID, 0);
mem_block[A_PROGRAM].block[invariant_last_address - 1] =
F_CONST1 - F_OFFSET;
mem_block[A_PROGRAM].block[invariant_last_address] =
F_RETURN - F_OFFSET;
}
else
has_invariant = -1;
functions_left = remove_undefined_prototypes (
mem_block[A_FUNCTIONS].current_size / sizeof (struct function),
(struct function *)mem_block[A_FUNCTIONS].block);
/* I don't like doing this, but I see no other way. |D| */
mem_block[A_FUNCTIONS].current_size =
functions_left * sizeof (struct function);
if (!(num_parse_error || inherit_file))
{
link_C_functions(current_file);
link_errors = 0;
process_reloc((struct reloc *)mem_block[A_RELOC].block,
mem_block[A_RELOC].current_size / sizeof(struct reloc),
mem_block[A_INHERITS].current_size / sizeof(struct inherit));
num_parse_error += link_errors;
}
{
int c;
for (c = 0;
c < mem_block[A_RELOC].current_size / sizeof(struct reloc);
c++)
free(((struct reloc *)mem_block[A_RELOC].block)[c].name);
}
inherit_self.type = 0;
inherit_self.name = make_shared_string("this");
add_to_mem_block(A_INHERITS, (char *) &inherit_self, sizeof(struct inherit));
add_to_mem_block(A_HEADER, (char *)&NULL_program, sizeof(NULL_program));
{
int num_func =
mem_block[A_FUNCTIONS].current_size / sizeof(struct function);
mem_block[A_FUNC_HASH].current_size = num_func *
sizeof(struct function_hash);
if (num_func)
{
mem_block[A_FUNC_HASH].block =
realloc((char *)mem_block[A_FUNC_HASH].block, num_func *
sizeof(struct function_hash));
mem_block[A_FUNC_HASH].max_size =
mem_block[A_FUNC_HASH].current_size;
}
hash_func(num_func, (struct function *)mem_block[A_FUNCTIONS].block,
(struct function_hash *)mem_block[A_FUNC_HASH].block);
}
prog = (struct program *)load_segments(segm_desc, mem_block);
prog->ref = 0;
prog->swap_num = 0;
prog->invariant = has_invariant;
prog->ctor_index = has_ctor;
prog->dtor_index = has_dtor;
prog->mod_time = current_time;
prog->name = string_copy(current_file);
prog->id_number = current_id_number++;
prog->cpu = 0;
prog->swap_lineno_index = 0;
prog->flags = (pragma_no_inherit ? PRAGMA_NO_INHERIT : 0) |
(pragma_no_clone ? PRAGMA_NO_CLONE : 0) |
(pragma_resident ? PRAGMA_RESIDENT : 0);
prog->inherit[prog->num_inherited - 1].prog = prog;
for (i = ix = 0; i < (int)prog->num_inherited; i++)
{
int inh = find_inherit(prog, prog->inherit[i].prog);
if (inh == i)
{
prog->inherit[i].variable_index_offset = ix;
ix += prog->inherit[i].prog->num_variables;
prog->inherit[i].type &= ~TYPE_MOD_SECOND;
}
else
{
prog->inherit[i].variable_index_offset =
prog->inherit[inh].variable_index_offset;
prog->inherit[i].type |= TYPE_MOD_SECOND;
}
}
/* don't forget the following:
* prog->sizeof_argument_types =
* mem_block[A_ARGUMENT_TYPES??].current_size);
* if you have fixed it one day .... ok ? :-=)
* remember to remove the above change to total_size !!!!!!!!
*/
prog->sizeof_argument_types=0;
/* NOTE: Don't forget to hash the argument types along with the functions
*/
prog->argument_types = 0; /* For now. Will be fixed someday */
prog->type_start = 0;
for (i = 0; i < prog->num_inherited; i++)
{
reference_prog (prog->inherit[i].prog, "inheritance");
}
prog->load_time = current_time;
register_program(prog);
/* 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
*/
total_program_size += prog->exec_size;
total_prog_block_size += prog->total_size;
total_num_prog_blocks += 1;
for (i=0; i < A_NUM; i++)
free((char *)mem_block[i].block);
if (num_parse_error || inherit_file)
{
free_prog(prog, 0);
prog = 0;
}
return;
}
/*
* 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_push_indexed = -1;
last_push_local = -1;
last_push_identifier = -1;
prog = 0; /* 0 means fail to load. */
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;
}
add_new_init_jump();
first_last_initializer_end = last_initializer_end;
}
/*
* 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);
}
int
search_for_ext_function(char *name, struct program *prog)
{
char *ix;
int i, res;
ix = strchr(name, ':');
if (ix == NULL)
{
/* its a simple name so search for it the normal way */
return search_for_function(name, prog);
}
if (ix - name == 4 && !strncmp(name, "this", 4))
return search_for_ext_function(ix + 2, prog);
for (i = prog->num_inherited - 2; i >= 0; i--)
{
if (ix == name || strlen(prog->inherit[i].name) == ix - name &&
strncmp(prog->inherit[i].name, name, ix - name) == 0)
{
res = search_for_ext_function(ix + 2, prog->inherit[i].prog);
if (res)
{
int type_mod;
/* adjust values and return */
function_inherit_found += i -
(prog->inherit[i].prog->num_inherited - 1);
type_mod = prog->inherit[function_inherit_found].type;
/* Correct function_type_mod_found */
if (function_type_mod_found & TYPE_MOD_PRIVATE)
type_mod &= ~TYPE_MOD_PUBLIC;
if (function_type_mod_found & TYPE_MOD_PUBLIC)
type_mod &= ~TYPE_MOD_PRIVATE;
function_type_mod_found |= type_mod;
return res;
}
else
{
/* skip program and continue */
i -= prog->inherit[i].prog->num_inherited - 1;
}
}
}
return 0;
}