2226 lines (2029 with data), 51.9 kB
%{
/*
* $Id: mud.y,v 1.20 2012/06/10 13:07:35 dredd Exp $
*
* Shattered Mud Language.
*
* An LPC derivative language.
*
* A word on the type hacks below
* o designed to minimise changes the rest of the system
* (this will be fixed in due course).
* o Assume 32 bit ints.
* top 8 bits struct no (max 255 structs)
* next 8 bits (pointer depth max 255)
* next 8 bits (special types static, private etc)
* next 8 bits (basic types)
*
* (should be done using a struct; driver should support
* a fully "distributable" type system - these will all
* be done when I work out how :-)
*
* Geoff Wong (C) 1993, 1999
*/
#include <limits.h>
#include <stdlib.h>
#include <unistd.h>
#include <malloc.h>
#include <assert.h>
#include "stack.h"
#include "opcodes.h"
#include "lpc.h"
#include "lexer.h"
#include "build.h"
#include "lexical.h"
#include "consts.h"
/* runtime stuff */
#include "../runtime/hash.h"
#define YYMAXDEPTH 600
struct field {
unsigned int type;
short offset;
};
Val * find_const2(Class ** io, Shared *s);
void yyerror(), free_local_names_from();
extern int yylex();
void init_globals(), print_type(int), free_locals();
void free_type_list();
int variable_count; /* global vars */
int static_variable_flag;
extern char * zero;
Func * prog;
extern int current_line, uinstr, puinstr;
extern Obj * Emulate;
int lang_debug = 0;
int last_type = 0;
/*
* '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.
* 'inherit_ob' will point to the super class object. This value is saved
* so that load_object() can set up pointers to it.
*/
extern char
* current_file
;
extern Shared
** inherit_file
;
int
file_number = 0,
inherit_number = 0
;
Class
** inherit_ob = NULL
;
#define MAX_BLOCK_DEPTH 16 /* big! */
int labelstack[100];
int switchstack[MAX_BLOCK_DEPTH];
int switch_depth = 0;
int LD = 0;
union
{
float r;
int i;
lexar * s;
} ultima, penultima;
int block_depth = 0, max_locals = 0;
int num_args, current_type = 0;
int no_of_classes = 0;
Func *prog_head = 0, *CPD = 0;
Func *initialise_func = 0;
Val **global_table = 0;
CVal **constant_table = 0;
struct var_def *arg_head = 0;
/* globals stuff */
struct var_def
* global_head = 0,
* global_tail = 0
;
int num_globals = 0;
int num_constants = 0;
/* local variable stuff */
struct var_def *local_head = 0;
int num_locals;
int num_block_locals[MAX_BLOCK_DEPTH];
#define STRING_BLOCK 100
#define INITIAL_FUNC_SIZE 200
%}
%token TOK_STATIC TOK_PRIVATE TOK_TYPE TOK_CLASS TOK_SELF
%token TOK_ARRAY TOK_OBJECT TOK_STRING_DECL TOK_REALT TOK_INT
%token TOK_NUMBER TOK_STRING TOK_REAL TOK_SWITCH TOK_CASE TOK_DEFAULT
%token TOK_IDENTIFIER TOK_TYNAME TOK_NEW TOK_VOID
%token TOK_INHERIT TOK_COLON_COLON TOK_ENUM
%token TOK_AS TOK_IMPORT TOK_END TOK_MODULE
%token TOK_CATCH TOK_THROW TOK_GENERIC TOK_ABSTRACT
%token TOK_DOTDOT TOK_LEFT_ARR TOK_RIGHT_ARR
%token TOK_IF TOK_THEN TOK_ELSE
%token TOK_WHILE TOK_DO TOK_FOR TOK_BREAK TOK_CONTINUE
%token TOK_RETURN TOK_CONST
%token TOK_LSH_EQ TOK_RSH_EQ TOK_LARROW
%token TOK_AND_EQ TOK_OR_EQ TOK_XOR_EQ
%token TOK_ADD_EQ TOK_SUB_EQ TOK_MULT_EQ TOK_DIV_EQ TOK_MOD_EQ
%union
{
Func *lnode;
int number;
char *string;
Shared * shared;
float real;
lexar *lexstr;
Val * val;
}
%type <number> expr_list function_call expr import_list in_options
%type <number> constant_expr bracket_list prefix stmt_expr
%type <number> string TOK_NUMBER TOK_REAL
%type <number> comma_expr for_expr
%type <number> switch_expr
%type <number> number
%type <real> realnumber
%type <number> statements statement simple_stmt return
%type <lnode> function_def new_global_name_decl program switch switch_case
%type <number> local_list locid_decl global_name_list
%type <number> arglist fun_arglist new_fun_arg
%type <number> static op_assign type possible_type typelist
%type <number> basetype statprivtype variable
%type <number> while for do block ifstmt if_expr local_declaration
%type <number> blktmp import
%type <string> TOK_IDENTIFIER TOK_STRING
%type <shared> identifier function_name newlocid new_global_name
%type <val> constant_expr2
%right TOK_CATCH
%right OPASSIGN
%right '='
%nonassoc ':'
%right '?'
%left TOK_LOR
%left TOK_LAND
%left '|'
%left '^'
%left '&'
%nonassoc TOK_EQ TOK_NE
%nonassoc '>' TOK_GE '<' TOK_LE
%left TOK_LSH TOK_RSH
%left '+' '-'
%left '*' '%' '/'
%left POSTINC POSTDEC
%right TOK_INC TOK_DEC
%right '!' '~' UMINUS
%nonassoc '@' '[' ']'
%left TOK_ARROW
%left '.'
%%
all:
{
/* initialise here! */
prog_head = 0;
CPD = 0;
num_globals = 0;
num_constants = 0;
global_head = 0;
free_type_list();
penultima.s = 0;
ultima.s = 0;
}
in_options
{
Func *p;
/*
* should check inherit_file and return if there are some
* files to be loaded
*/
if (inherit_file != NULL)
{
inherit_file[file_number] = 0;
return 0;
}
if (inherit_ob != NULL) {
inherit_ob[inherit_number] = 0;
}
p = alloc_function(0, shared_string_copy(C("*InitGlobals")), INITIAL_FUNC_SIZE, 0);
p->next = 0;
p->num_arg = 0;
CPD = p;
emit(S_ENTER, 0);
if (inherit_ob != NULL || inherit_file != NULL)
{
Shared * v;
char pname[1024];
int i;
for (i = 0; inherit_ob[i]; i++)
{
emit(S_PUSH8, 0);
emit(S_PUSHCARGS, 0);
emit(S_PUSHCOFF, 0);
emit(S_ADDSP, 0);
strcpy(pname, inherit_ob[i]->name->str);
strcat(pname, "::*InitGlobals");
v = string_copy(pname);
add_patch(CPD, P_CALLU, v);
/* printf("S_CALLU: %s\n", v); */
emit64(S_CALLU, (char *)&(v));
}
}
initialise_func = p;
prog_head = p;
init_globals();
CPD = initialise_func;
}
program
/* global initialisation function */
{
initialise_func->next = 0;
CPD = initialise_func;
/* copy initialise code block to a non-global one */
emit(S_PUSH8, 0);
emits(S_RETURN);
emits(S_END);
CPD->block = code_size_fix(CPD);
CPD->num_var = 0;
prog_head = $4;
if (!prog_head)
{
printf("No program returned!\n");
}
make_global_tables();
}
;
program: /* empty */
{ $$ = prog_head; /* start of program */ }
| program
{
block_depth = 0;
penultima.s = 0;
ultima.s = 0;
}
function_def
{
if ($3 != 0)
{
Func *p = (Func *)$3;
p->next = (Func *)$1;
$$ = p;
/* should this also check efuns & emulatefuns? */
if (defined_function(p->name->str))
{
yyerror("Illegal to redeclare function.");
}
}
else
{
$$ = $1;
}
}
;
/*
moddef: TOK_MODULE identifier module TOK_END identifier ';'
module: program ;
*/
in_options: /* empty */
{ $$ = 0; }
| import_list
{ $$ = 0; }
| inheritance_list
{ $$ = 0; }
| inheritance_list import_list
{ $$ = 0; }
;
import_list:
import
{ $$ = $1; }
| import_list import
{ $$ = $2; }
;
inheritance_list:
inheritance
| inheritance_list inheritance
;
inheritance:
TOK_INHERIT TOK_STRING ';'
{
/* FIX:: MAX_INHERIT is non-dynamic brain damage */
if (inherit_number >= MAX_INHERIT)
{
free($<lexstr>2);
yyerror("Too many files inherited.\n");
}
else
{
Shared * inhs = to_Cstring($<lexstr>2);
free($<lexstr>2);
if (inherit_ob == NULL)
{
inherit_ob = (Class **)
malloc(sizeof(Class *) * (MAX_INHERIT+1));
inherit_number = 0;
}
/* External dependency! */
//printf("find class: %s\n", inhs->str);
inherit_ob[inherit_number] = find_class(inhs);
//if (inherit_ob[inherit_number]) printf("found: (%d) %s\n",
// inherit_number, inherit_ob[inherit_number]->name->str);
if (inherit_ob[inherit_number] == 0)
{
if (inherit_file == NULL)
{
inherit_file = (Shared **)
malloc(sizeof(Shared *) * (MAX_INHERIT+1));
file_number = 0;
}
inherit_file[file_number++] = inhs;
inherit_file[file_number] = 0;
}
else
{
inherit_number++;
free_string(inhs);
}
}
}
;
import:
TOK_IMPORT TOK_STRING identifier ';'
{
Shared * inhs = to_Cstring($<lexstr>2);
Class *iobj;
free($<lexstr>2);
/* need to insure stuff is loaded. fuck fuck fuck */
iobj = find_class(inhs);
if (!iobj)
{
/* sigh - nasty piece of work. */
if (!inherit_file)
{
inherit_file = (Shared **)
malloc(sizeof(char *) * (MAX_INHERIT+1));
file_number = 0;
}
inherit_file[file_number++] = inhs;
inherit_file[file_number] = 0;
free_string($3);
}
else
{
add_type_list($3, iobj);
}
$$ = 0;
}
|
TOK_IMPORT TOK_SELF identifier ';'
{
/* FIX:: self importing */
add_type_list($3, 0);
$$ = 0;
}
;
number: TOK_NUMBER
{
emit_number($1);
$$ = (int)$1;
}
;
realnumber:
TOK_REAL
{
char * x;
$<real>$ = $<real>1;
x = (char *)(&$<real>$);
emit32(S_PUSHr, x);
#if 0
printf("real yacc: %f (%x %x %x %x)\n", $<real>$, x[0], x[1], x[2], x[3]);
#endif
}
;
function_def: statprivtype identifier '('
{
block_depth++;
$<lnode>$ = alloc_function($1, $2, INITIAL_FUNC_SIZE, 0);
CPD = $<lnode>$;
new_function();
}
arglist ')'
{
struct var_def *t = arg_head;
/* haven't taken into account ret addr and old bp on stack */
if (arg_head != NULL)
{
/* emit(S_COPY, num_args); */
while (t) {
emit16(S_TYPEC, t->type);
/*
if (t->type != T_ANY)
emit16(S_TYPEC, t->type);
else
emit(S_ADDSP, -1);
*/
t = t->next;
}
}
emit(S_ENTER, 0);
CPD->num_arg = num_args;
$<number>$ = CPD->current_I;
}
block
{
Func *p = $<lnode>4;
patch8($<number>7 - 1, max_locals);
/* p->num_arg = num_args; */
/* p->type = p->type | $1; */
$$ = p;
CPD = $$;
/* free the local and arg space */
free_locals();
emit(S_PUSH8,0);
emits(S_RETURN);
emits(S_END);
p->block = code_size_fix(p);
p->num_var = max_locals;
block_depth--;
if (block_depth == 0) CPD = initialise_func;
}
| statprivtype global_name_list ';'
{ $$ = 0; }
| TOK_CONST new_global_name '=' constant_expr2 ';'
{
/* + these could be copy propagated later? */
/* + need to redefine global_table in object */
/* + copy in values when creating variable table */
/* + also must ensure these aren't assigned to! */
add_global_variable($2, $<val>4->type | TY_CONSTANT, $<val>4);
$$ = 0;
}
/* | simple_stmt { $$ = 0; } */
;
statprivtype: static possible_type
{
/* $$ = $2; 41093 */
current_type = $1 | $2;
$$ = current_type;
static_variable_flag = $$;
}
;
static: TOK_STATIC { $$ = TY_STATIC; }
| /* empty */ { $$ = 0; }
| TOK_PRIVATE { $$ = TY_PRIVATE; }
| TOK_STATIC TOK_PRIVATE { $$ = TY_STATIC | TY_PRIVATE; }
| TOK_PRIVATE TOK_STATIC { $$ = TY_STATIC | TY_PRIVATE; } /* hack alert */
;
arglist: /* empty */ { $$ = 0; }
| fun_arglist { $$ = $1; }
;
fun_arglist: new_fun_arg
| new_fun_arg ',' fun_arglist
;
new_fun_arg: possible_type identifier
{
/* only called when processing args */
if (find_argument($2))
yyerrorf("Name \"%s\"appears twice in function parameter list\n", $2->str);
else
add_argument($2, current_type);
$$ = 0;
}
;
possible_type:
/* empty */ { $$ = T_ANY; current_type = T_ANY; }
| type { $$ = $1; current_type = $1; }
;
type: basetype { $$ = $1; }
| '(' typelist ')' { $$ = $2; }
;
basetype: TOK_INT { $$ = T_NUMBER; }
| TOK_STRING_DECL { $$ = T_STRING; }
| TOK_ARRAY { $$ = T_POINTER; }
| TOK_REALT { $$ = T_REAL; }
| TOK_OBJECT { $$ = T_OBJECT; }
| TOK_VOID { $$ = T_VOID; }
| TOK_CLASS identifier
{
struct field * x;
x = find_type($2);
if (x)
{
$$ = x->type;
free(x);
}
else $$ = 0;
free_string($2);
}
;
typelist: basetype { $$ = $1; }
| typelist '|' basetype { $$ = $1 | $3; }
;
global_name_list: new_global_name_decl { $$ = 0; }
| global_name_list ',' new_global_name_decl { $$ = 0; }
;
new_global_name_decl: new_global_name
{
add_global_variable($1, current_type, 0);
}
| new_global_name '['
{
$<lnode>$ = CPD;
CPD = initialise_func;
}
expr_list ']'
{
int x, y;
y = current_type | ($4 << 16);
#if 0
printf("adding type %d,%d = %d\n", $4, current_type, y);
#endif
x = add_global_variable($1, y, 0);
emit_number($4);
emits(S_ARR_ALLOC);
emit(S_POPG, x-1);
type_check($4, T_ANY, T_NUMBER, "array declaration");
CPD = $<lnode>3;
}
| new_global_name '='
{
$<lnode>$ = CPD;
CPD = initialise_func;
add_global_variable($1, current_type, 0);
}
expr
{
int x = find_global_variable($1);
/* printf("Global no: %d.\n", x); */
emit(S_POPG, x - 1);
type_check($4, T_ANY, current_type, "global assignment");
CPD = $<lnode>3;
}
;
new_global_name: identifier
{
if (find_global_variable($1))
yyerrorf("Redeclaration of global variable \"%s\"\n", $1->str);
$$ = $1;
}
;
block: '{' blktmp statements '}'
{
block_depth--;
num_locals = $<number>2;
}
;
blktmp: /* empty */
{
$$ = num_locals;
block_depth++; /* re-set in 'block' */
}
;
/*
* Declarations and statements can be intermingled;
* decls are statements in miniature (a block of value assignments).
*/
local_declaration: type { current_type = $1; } local_list ';' { $$ = $3; } ;
local_list: locid_decl
| locid_decl ',' local_list
;
locid_decl: newlocid
{
int x = add_local_variable($1, current_type);
emit(S_PUSH8, 0);
emit(S_POPL, x - 1);
}
| newlocid '[' expr_list ']'
{
int x, y;
y = current_type | ($3 << 16);
x = add_local_variable($1, y);
emit_number($3);
emits(S_ARR_ALLOC);
emit(S_POPL, x - 1);
}
| newlocid '=' expr
{
int x = add_local_variable($1, current_type);
emit(S_POPL, x - 1);
}
;
newlocid: identifier
{
if (find_local_block($1))
yyerrorf("Redefinition of \"%s\" within the same block", $1->str);
$$ = $1;
}
;
statements: /* empty */
{ $$ = 0; }
| statement
{
end_of_statement();
}
statements
| error ';' { yyerror("Illegal statement"); $$ = 0; }
;
simple_stmt:
ifstmt
| while
| for
| do
| switch { $$ = 0; }
| return ';' { $$ = 0; }
| expr ';' { $$ = 0; }
| block { $$ = 0; }
;
statement:
simple_stmt
| TOK_THROW comma_expr ';'
{
emits(S_THROW);
$$ = 0;
}
| TOK_BREAK ';'
{
if ((LD == 0) && (switch_depth == 0))
{
yyerror("Break outside while, for, do, or switch construct.\n");
}
add_break_patch(CPD->current_I);
emit16(S_JUMPU, 0);
$$ = 0;
}
| TOK_CONTINUE ';'
{
if (LD == 0)
{
yyerror("Continue outside while, for, or do loop.\n");
}
emit16(S_JUMP, labelstack[LD-1] - CPD->current_I - 3);
$$ = 0;
}
| local_declaration { $$ = 0; }
;
while: TOK_WHILE
{
labelstack[LD++] = CPD->current_I;
$<number>$ = CPD->current_I;
}
'(' expr ')'
{
emit16(S_JZERO,0);
$<number>$ = CPD->current_I;
}
statement
{
end_of_statement();
emits(S_OFLOW_CHECK);
emit16(S_JUMP, $<number>2 - CPD->current_I - 3);
patch16((int)$<number>6 - 2, CPD->current_I - $<number>6);
do_break_patch($<number>2, CPD->current_I);
LD--;
}
;
do: TOK_DO
{
$<number>$ = CPD->current_I;
labelstack[LD++] = CPD->current_I;
}
statement {
end_of_statement();
}
TOK_WHILE '(' expr ')'
';'
{
emits(S_OFLOW_CHECK);
emit16(S_JNZERO, $<number>2 - CPD->current_I - 3);
do_break_patch($<number>2, CPD->current_I);
LD--;
}
;
for: TOK_FOR '(' for_expr ';'
{
$<number>$ = CPD->current_I;
}
for_expr ';'
{
emit16(S_JZERO, 0);
emit16(S_JUMP, 0);
$<number>$ = CPD->current_I;
labelstack[LD++] = CPD->current_I;
}
for_expr ')'
{
emit16(S_JUMP, $<number>5 - CPD->current_I - 3);
patch16((int)($<number>8 - 2), CPD->current_I - $<number>8);
}
statement
{
end_of_statement();
emits(S_OFLOW_CHECK);
emit16(S_JUMP, $<number>8 - CPD->current_I - 3);
patch16((int)($<number>8 - 5), CPD->current_I - $<number>8 + 3);
do_break_patch($<number>5, CPD->current_I);
LD--;
}
;
for_expr: /* EMPTY */
{ emit(S_PUSH8, 1); }
| comma_expr
;
switch: TOK_SWITCH
{
$<number>$ = CPD->current_I;
}
'(' expr ')'
{
int x;
/* add a global *switch[X] */
/* this will be an array ({ const, line num, const etc }) */
x = add_global_variable(make_next_switch(),TY_STATIC|T_ANY,0);
emit(S_SWITCH, x - 1); /* switch on global */
switchstack[switch_depth++] = CPD->current_I;
/* set up the constants */
$<lnode>$ = CPD;
CPD = initialise_func;
emit_push(GLOBAL, x);
CPD = $<lnode>$;
$<lnode>$ = x;
}
'{' switch_expr '}'
{
int x = $8, y;
/* once we've emitted all the statements emit switch table */
$$ = CPD;
y = CPD->current_I - switchstack[switch_depth-1];
CPD = initialise_func;
x = x * 2 + 2;
/* we don't need to emit this IF we emitted
a default: case */
emit(S_PUSH8, -2); /* no match marker.. */
emit_number(y);
assert(x >= 0);
emit16(S_AGGREGATE,x);
emits(S_POPO);
CPD = $$;
$$ = 0;
switch_depth--;
do_break_patch($<number>2, CPD->current_I);
}
;
switch_expr: switch_case
{ $$ = 1; }
| switch_expr switch_case
{ $$ = $1 + 1; }
;
switch_case: TOK_CASE
{
#if 1
/* record the last line */
$<lnode>$ = CPD;
CPD = initialise_func;
#endif
}
constant_expr
':'
{
#if 1
int x;
/* put the offset line number (next for code) */
CPD = $<lnode>2;
x = CPD->current_I - switchstack[switch_depth-1];
CPD = initialise_func;
emit_number(x);
CPD = $<lnode>2;
#endif
}
statements
{
/* return line number? */
$$ = 0;
}
| TOK_DEFAULT ':'
{
/* two defaults should generate an error; it doesn't yet */
int y;
$<lnode>$ = CPD;
y = -(CPD->current_I-switchstack[switch_depth-1]) - 1;
/* number is negative so we recognise it! */
CPD = initialise_func;
emit(S_PUSH8, -1);
emit_number(y);
CPD = $<lnode>$;
}
statements
{
$$ = 0;
}
;
comma_expr: expr
| comma_expr ',' expr
{
$$ = $3;
}
;
prefix: TOK_INC expr
{
emit(S_COPY, 1);
emit(S_PUSH8, 1);
emits(S_PLUS);
emit_pop($2);
type_check($2, T_ANY, T_NUMBER, "pre ++");
$$ = $2;
}
| TOK_DEC expr
{
emit(S_COPY, 1);
emit(S_PUSH8, -1);
emits(S_PLUS);
emit_pop($2);
type_check($2, T_ANY, T_NUMBER, "pre --");
$$ = $2;
}
;
stmt_expr: variable '=' expr
{
type_check($1, $3, T_ANY, "variable assignment");
$$ = $1;
emit_pop($1);
}
| variable
{
emit(S_COPY, 1);
}
op_assign expr %prec OPASSIGN
{
type_check($1, $4, T_ANY, "variable op= assignment");
$$ = $1;
emits($3);
emit_pop($1);
}
| TOK_CATCH
{
emit16(S_CATCH, 0);
$<number>$ = CPD->current_I;
}
statement
{
end_of_statement();
/* back patch the correct line */
emits(S_POPCATCH);
patch16($<number>2 - 2, CPD->current_I - $<number>2);
$$ = T_ANY;
}
| expr '?'
{
emit16(S_JZERO, 0);
$<number>$ = CPD->current_I;
/* $$ is just after jmp offset */
}
expr
{
emit16(S_JUMP, 0);
$<number>$ = CPD->current_I;
patch16((int)$<number>3 - 2, CPD->current_I - $<number>3);
}
':' expr
{
patch16((int)$<number>5 - 2, CPD->current_I - $<number>5);
type_check($<number>4, $<number>7, T_ANY, "conditional operator");
$$ = $<number>4;
}
| variable TOK_INC %prec POSTINC
{
emit(S_COPY, 1);
emit(S_PUSH8, 1);
emits(S_PLUS);
emit_pop($1);
emit(S_PUSH8, 1);
emits(S_MINUS);
type_check($1, T_ANY, T_NUMBER, "post inc");
$$ = $1;
}
| variable TOK_DEC %prec POSTDEC
{
emit(S_COPY, 1);
emit(S_PUSH8, 1);
emits(S_MINUS);
emit_pop($1);
emit(S_PUSH8, 1);
emits(S_PLUS);
type_check($1, T_ANY, T_NUMBER, "post dec");
$$ = $1;
}
| function_call { $$ = $1; }
;
expr:
'[' expr_list ']'
{
emit16(S_AGGREGATE, (short) $<number>2);
$$ = T_POINTER;
}
|
'(' '{' expr_list '}' ')'
{
emit16(S_AGGREGATE, (short) $<number>3);
$$ = T_POINTER;
}
| variable { $$ = $1; }
| TOK_NEW identifier
{
struct field * x;
x = find_type($2);
if (x)
{
emit(S_PUSH8, x->offset);
emit(S_PUSH8, 1);
emits(S_ARR_ALLOC);
$$ = x->type;
free(x);
}
free_string($2);
}
| '(' comma_expr ')'
{ $$ = $2; }
| constant_expr
| expr '[' TOK_DOTDOT
{
emit(S_PUSH8, 0);
}
expr ']'
{
/* emits(S_EXTRACT); */
emit(S_EFUND, F_EXTRACT);
type_check($1, T_ANY, T_POINTER|T_STRING, "extract arg 1");
type_check($5, T_ANY, T_NUMBER, "extract arg 3");
$$ = $1;
}
| expr '[' expr TOK_DOTDOT ']'
{
int x = INT_MAX;
emit32(S_PUSHi, (char *)&x);
/* emits(S_EXTRACT); */
emit(S_EFUND, F_EXTRACT);
type_check($1, T_ANY, T_POINTER|T_STRING, "extract arg 1");
type_check($3, T_ANY, T_NUMBER, "extract arg 2");
$$ = $1;
}
| expr '[' expr TOK_DOTDOT expr ']'
{
/* emits(S_EXTRACT); */
emit(S_EFUND, F_EXTRACT);
type_check($1, T_ANY, T_POINTER|T_STRING, "extract arg 1");
type_check($3, T_ANY, T_NUMBER, "extract arg 2");
type_check($5, T_ANY, T_NUMBER, "extract arg 3");
$$ = $1;
}
| expr TOK_LOR
{
emit(S_COPY, 1);
emit16(S_JNZERO, 0);
$<number>$ = CPD->current_I;
}
expr
{
/* type_check($1, $4, T_ANY); */
$$ = T_NUMBER;
emits(S_LOR);
patch16($<number>3 -2, CPD->current_I - $<number>3);
}
| expr TOK_LAND
{
emit(S_COPY, 1);
emit16(S_JZERO, 0);
$<number>$ = CPD->current_I;
}
expr
{
/* type_check($1, $4, T_ANY); */
$$ = T_NUMBER;
emits(S_LAND);
patch16($<number>3 -2, CPD->current_I - $<number>3);
}
| expr '|' expr
{
type_check($1, $3, T_NUMBER, "arithmetic or");
$$ = $1;
emits(S_OR);
}
| expr '^' expr
{
type_check($1, $3, T_NUMBER, "arithmetic xor");
$$ = $1;
emits(S_XOR);
}
| expr '&' expr
{
type_check($1, $3, T_NUMBER, "arithmetic and");
$$ = $1;
emits(S_AND);
}
| expr TOK_EQ expr
{
type_check($1, $3, T_ANY, "equals");
$$ = T_NUMBER;
emits(S_EQ);
}
| expr TOK_NE expr
{
type_check($1, $3, T_ANY, "not equals");
$$ = T_NUMBER;
emits(S_NE);
}
| expr '>' expr
{
type_check($1, $3, T_STRING|T_REAL|T_NUMBER, ">");
$$ = T_NUMBER;
emits(S_GT);
}
| expr TOK_GE expr
{
type_check($1, $3, T_STRING|T_REAL|T_NUMBER, ">=");
$$ = T_NUMBER;
emits(S_GE);
}
| expr '<' expr
{
type_check($1, $3, T_STRING|T_REAL|T_NUMBER, "<");
$$ = T_NUMBER;
emits(S_LT);
}
| expr TOK_LE expr
{
type_check($1, $3, T_STRING|T_REAL|T_NUMBER, "<=");
$$ = T_NUMBER;
emits(S_LE);
}
| expr TOK_LSH expr
{
type_check($1, $3, T_NUMBER, "lsh");
$$ = T_NUMBER;
emits(S_LSH);
}
| expr TOK_RSH expr
{
type_check($1, $3, T_NUMBER, "rsh");
$$ = T_NUMBER;
emits(S_RSH);
}
| expr '+' expr
{
/* const fix hack should do constant check on last 2 pushes,
if both strings or numbers then add them remove 2 instrs
and add the new push */
if (!constant_fold(S_PLUS))
{
emits(S_PLUS);
type_check($1,T_ANY,T_REAL|T_NUMBER|T_STRING|T_POINTER, "plus");
type_check($3,T_ANY,T_REAL|T_NUMBER|T_STRING|T_POINTER, "plus");
if (($1 & T_POINTER) || ($3 & T_POINTER))
{
if (!($1 & $3)) yyerror("Illegal array addition\n");
}
$$ = ($1 > $3) ? $1 : $3;
}
}
| expr '-' expr
{
if (!constant_fold(S_MINUS)) {
emits(S_MINUS);
type_check($1, $3, T_REAL|T_NUMBER, "minus");
$$ = $1;
}
}
| expr '*' expr
{
/* if (!constant_fold(S_MULT)) */
emits(S_MULT);
type_check($1, $3, T_REAL|T_NUMBER, "multiply");
$$ = $1;
}
| expr '%' expr
{
/* if (!constant_fold(S_MOD)) */
emits(S_MOD);
type_check($1, $3, T_NUMBER, "modulo");
$$ = $1;
}
| expr '/' expr
{
/* if (!constant_fold(S_DIVIDE)) */
emits(S_DIVIDE);
type_check($1, $3, T_REAL|T_NUMBER, "divide");
$$ = $1;
}
| prefix
| '!' expr
{
emits(S_LNOT);
$$ = T_NUMBER;
}
| '~' expr
{
type_check($2, T_ANY, T_NUMBER, "arithmetic not");
$$ = T_NUMBER;
emits(S_NOT);
}
| '-' expr %prec UMINUS
{
type_check($2, T_ANY, T_NUMBER | T_REAL, "negate");
$$ = $2;
#if 1
if (uinstr == S_PUSH8) {
char x;
x = -(CPD->block[CPD->current_I-1]);
CPD->block[CPD->current_I-1] = x;
}
/* should also do PUSHi & PUSHr */
else
#endif
emits(S_NEGATE);
}
| stmt_expr
;
op_assign: TOK_AND_EQ { $$ = S_AND; }
| TOK_OR_EQ { $$ = S_OR; }
| TOK_XOR_EQ { $$ = S_XOR; }
| TOK_LSH_EQ { $$ = S_LSH; }
| TOK_RSH_EQ { $$ = S_RSH; }
| TOK_ADD_EQ { $$ = S_PLUS; }
| TOK_SUB_EQ { $$ = S_MINUS; }
| TOK_MULT_EQ { $$ = S_MULT; }
| TOK_MOD_EQ { $$ = S_MOD; }
| TOK_DIV_EQ { $$ = S_DIVIDE; }
;
return: TOK_RETURN
{
emit(S_PUSH8, 0);
emits(S_RETURN);
}
| TOK_RETURN comma_expr
{
type_check($2, T_ANY, CPD->type, "return type of function");
emits(S_RETURN);
}
;
expr_list: /* empty */ { $$ = 0; }
| expr { $$ = 1; }
| expr_list ',' expr { $$ = $1 + 1; }
;
constant_expr: string
{
penultima.s = ultima.s;
ultima.s = $<lexstr>1;
$$ = T_STRING;
}
| number
{
penultima.i = ultima.i;
ultima.i = $1;
if (!($1)) $$ = T_ANY; /* zero hack :( */
else $$ = T_NUMBER;
}
| realnumber
{
/*
penultima.r = ultima.r;
ultima.r = $<real>1;
$$ = $<real>1;
*/
$$ = T_REAL;
}
;
constant_expr2: TOK_STRING
{
$$ = share_Cstring(to_Cstring($<lexstr>1));
free($<lexstr>1);
}
| TOK_NUMBER
{
$$ = alloc_value();
$$->type = T_NUMBER;
$$->u.number = $1;
}
| '-' TOK_NUMBER
{
$$ = alloc_value();
$$->type = T_NUMBER;
$$->u.number = - $2;
}
| TOK_REAL
{
$$ = alloc_value();
$$->type = T_REAL;
$$->u.number = $1;
}
| '-' TOK_REAL
{
$$ = alloc_value();
$$->type = T_REAL;
$$->u.number = - $2;
}
| identifier
{
Val * x;
if ((x = find_constant($1)))
{
/* printf("Global no: %d.\n", $$); */
$$ = alloc_value();
// FIX: look up global
assign_value($$, x);
}
else
{
yyerror("Only constant values maybe used in switch expressions\n");
}
free_string($1);
}
;
/* "variable" == things which can be written as lvalues. */
variable: identifier
{
int x;
Val * v;
if ((x = find_local_variable($1)))
{
emit_push(LOCAL, x-1);
}
else if ((x = find_argument($1)))
{
emit_push(LOCAL, x);
}
else if ((x = find_global_variable($1)))
{
emit_push(GLOBAL, x);
/* printf("Global no: %d.\n", $$); */
}
else if ((v = find_constant($1)))
{
/* what should we do? */
emit_constant(v);
}
else yyerrorf("Identifier %s used but not declared", $1->str);
free_string($1);
$$ = last_type;
}
| expr '[' expr ']'
{
int t, r;
/* ADDIND should typecheck too! */
emits(S_ADDIND);
$$ = 0;
type_check($3, T_ANY, T_NUMBER, "array access arg 2");
t = ($1 & 0x00ff0000) >> 16;
if (!t) {
if ($1 & 0xff000000)
yyerror("Non class accessed\n");
else {
$$ = T_ANY;
type_check($1,T_ANY,T_POINTER|T_STRING,
"array access arg 1");
}
}
else {
r = $1 & 0xff00ffff;
t--;
$$ = (t << 16) | r;
}
}
| expr '.' identifier
{
struct field * x;
x = find_type_info($1, $3);
if (x) {
emit(S_PUSH8, x->offset);
emits(S_ADDIND);
type_check($1, T_ANY, T_POINTER, "class access arg 1");
$$ = x->type;
free(x);
}
else $$ = 0;
free_string($3);
}
;
string: TOK_STRING
{ /* blech */
add_patch(CPD, P_STRING, $<lexstr>1);
emit64(S_PUSHs, zero);
/* $<lexstr>$ = (lexstr *)p; */
$<lexstr>$ = $<lexstr>1;
}
;
bracket_list:
'(' expr_list ')'
{ $$ = $2; }
;
function_call:
function_name
{
struct keyword * x = 0;
x = lookup_emulate($1);
if (!x) x = lookup_predef($1->str);
if (x && (x->token == F_EMULATE))
{
Shared * v;
/* make it a call_other to Emulate.. */
/* argh need a S_PUSHo opcode now.. */
v = string_copy(EMULATE_EFUN);
/* add_patch(CPD, P_CSTRING, v); */
emit64(S_PUSHs, (char *) &(v));
// v = shared_string_copy($1);
/* add_patch(CPD, P_CSTRING, v); */
// emit32(S_PUSHs, (char *) &(v));
}
else if (!x || (x && (x->token != F_CALL_OTHER)))
{
emit(S_PUSH8, 0); /* dummy this_object() */
}
$<lnode>$ = x;
}
bracket_list
{
struct keyword * x;
int p, n;
x = (struct keyword *)$<string>2;
if (x)
{
// check the no. of parameters is correct */
p = x->params;
if (p > 0)
{
n = $3;
while (n < p)
{
emit(S_PUSH8, 0);
n++;
}
if (n > p)
{
emit(S_ADDSP, n - p);
}
}
emit(S_PUSHCARGS, $3);
if (x->token == F_CALL_OTHER)
{
/* special case for call_other efun() */
byte n = $3 - 2;
/* patch no of args to be correct */
if ($3 < 2) {
yyerror("Not enough args to call_other()");
}
/* adjust number of params */
CPD->block[CPD->current_I-1] = n;
emits(S_CALLOF);
}
else if (x->token == F_EMULATE)
{
Shared * ss = shared_string_copy($1);
/* string should be added to patch list */
/* add_patch(CPD, P_CSTRING, x); */
emit64(S_CALLO, (char *)&(ss));
free(x);
}
else
{
//emit(S_PUSHCARGS, $3); /* no of params */
emit(S_EFUN, (char)x->token);
}
}
else
{
/* It's a local function call. */
Shared * v;
emit(S_PUSHCARGS, $3);
emit(S_PUSHCOFF, 0);
emit(S_ADDSP, 0); /* varargs fix - blech */
v = shared_string_copy($1);
add_patch(CPD, P_CALLU, v);
emit64(S_CALLU, (char *)&(v));
}
/*
* check function calls later
* should be able to do this without
* checking the function list again
*/
free_string($1);
$$ = T_ANY;
}
| expr TOK_ARROW identifier bracket_list
{
Shared * x = shared_string_copy($3);
emit(S_PUSHCARGS, $4);
/* string should be added to patch list */
/* add_patch(CPD, P_CSTRING, x); */
emit64(S_CALLO, (char *)&(x));
free_string($3);
$$ = T_ANY;
}
| expr TOK_ARROW '(' expr ')' bracket_list
{
emit(S_PUSHCARGS, $6);
emits(S_CALLOF);
$$ = T_ANY;
}
| expr '@' '(' expr ')' TOK_ARROW identifier '(' expr ')'
{
/* an expr_list in the brackets would be nice.. */
/* need to re-order stack so that $1 is on top */
/* also identifier probably needs to be on the stack */
/* emits(S_CALL_OUT); */
emit(S_EFUND, F_NCALL_OUT);
$$ = T_ANY;
}
;
function_name: identifier
{ $$ = $1; }
| TOK_STRING TOK_COLON_COLON identifier
{
/* are the following space leaks? (or fuck up counts anyway?) */
/* perhaps all should use string_copy and we should free elsewhere. */
Shared *t = to_Cstring($<lexstr>1);
char *p = (char *)malloc($3->length + t->length + 3);
strcpy(p, t->str); strcat(p, "::"); strcat(p, $3->str);
$$ = string_copy(p);
free_string(t);
free($<lexstr>1);
free_string($3);
free(p);
}
| TOK_COLON_COLON identifier
{
char *p = (char *)malloc($2->length + 3);
strcpy(p, "::");
strcat(p, $2->str);
$$ = string_copy(p);
free_string($2);
free(p);
}
;
ifstmt: TOK_IF if_expr
statement
{
patch16((int)$<number>2 - 2, CPD->current_I - $<number>2);
}
| TOK_IF if_expr
statement
TOK_ELSE
{
emit16(S_JUMP, 0);
patch16((int)$<number>2 - 2, CPD->current_I - $<number>2);
$<number>$ = CPD->current_I;
}
statement
{
patch16((int)$<number>5 - 2, CPD->current_I - $<number>5);
}
;
if_expr: '(' expr ')'
{
emit16(S_JZERO, 0);
$$ = CPD->current_I;
}
;
identifier: TOK_IDENTIFIER
{
$$ = string_copy($1);
}
;
%%
int defined_function(char *s)
{
Func *p;
for(p = prog_head; p; p = p->next)
{
if (strcmp(p->name->str, s) == 0)
return 1;
}
return 0;
}
/*
* All the code below here is
* Copyright (C), Geoff Wong, June 1993.
* geoff@serc.rmit.edu.au
*/
int inherited_globals = 0;
void init_globals()
{
int i;
inherited_globals = 0;
#if 1
if (inherit_ob == NULL) return;
for (i = 0; inherit_ob[i]; i++) {
inherited_globals += inherit_ob[i]->num_variables;
}
#endif
}
/* tail insertion */
int add_global_variable(Shared * s, int type, Val * val)
{
struct var_def *t;
if (lang_debug) printf("D: add global %s\n", s->str);
t = (struct var_def *)malloc(sizeof(struct var_def));
t->name = s;
if (!type) type = 1;
t->type = type;
t->next = 0;
t->v = val;
if (!global_head) {
global_tail = t;
global_head = t;
}
else {
global_tail->next = t;
global_tail = t;
}
if (type & TY_CONSTANT) {
num_constants++;
}
else num_globals++;
return num_globals + inherited_globals;
}
int find_global_variable(Shared * s)
{
struct var_def *t = global_head;
int d = 0, i, j, count = 1;
while (t)
{
if ((t->type & TY_CONSTANT) == 0)
{
d++;
if (t->name == s)
{
/* printf("find_global %s\n", t->name); */
last_type = t->type & 0xffff00ff;
/* get rid of static */
return d + inherited_globals;
}
}
t = t->next;
}
#if 1 /* if we want to access inherited vars directly */
if (!inherit_ob) return 0;
/* all globals are copied into each level of the object */
for (i = 0; inherit_ob[i]; i++)
{
for (j = 0; j < inherit_ob[i]->num_variables; j++) {
if (inherit_ob[i]->global_table[j]->u.string == s) {
last_type = inherit_ob[i]->global_table[j]->type;
return count;
}
count++;
}
}
#endif
return 0;
}
Val * find_constant(Shared * s)
{
struct var_def *t = global_head;
Val * v;
while (t)
{
if ((t->name == s) && (t->type & TY_CONSTANT)) {
/* printf("find_constant %s\n", t->name); */
last_type = t->type & 0xffff00ff;
/* get rid of static (const etc) */
return t->v;
}
t = t->next;
}
if (!inherit_ob) return 0;
/* have to recurse into the objects */
v = find_const2(inherit_ob, s);
return v;
}
Val * find_const2(Class ** io, Shared * s)
{
int i, j;
Val * v;
for (i = 0; io[i]; i++) {
for (j = 0; j < io[i]->num_constants; j++) {
if (io[i]->constant_table[j]->name == s) {
last_type =
io[i]->constant_table[j]->type;
return io[i]->constant_table[j]->val;
}
}
if (io[i]->inherit) {
v = find_const2(io[i]->inherit, s);
if (v) return v;
}
}
return 0;
}
void make_global_tables()
{
struct var_def *t = global_head, *x;
int d = 0, ct = 0;
Val **table = 0;
CVal ** consttable = 0;
#if 0
printf("%s : num = %d\n", current_file, num_globals);
#endif
if (!num_globals) table = 0;
else table = (Val **) malloc(sizeof(Val *) * (num_globals + 1));
if (!num_constants) consttable = 0;
else consttable = (CVal **) malloc(sizeof(CVal *) * (num_constants + 1));
while (t && (d < num_globals || ct < num_constants))
{
if (t->type & TY_CONSTANT)
{
consttable[ct++] =
make_const(t->name, t->v, t->type);
}
else
{
table[d++] = share_Cstring(t->name);
table[d-1]->type = t->type;
}
x = t;
t = t->next;
free(x);
}
global_table = table;
constant_table = consttable;
return;
}
/* arguments name stuff */
/* head insertion */
int find_argument(Shared *s)
{
int d;
struct var_def *t = arg_head;
d = 0;
while (t && d < num_args)
{
d++;
if (t->name == s) {
last_type = t->type;
return -d;
}
t = t->next;
}
return 0;
}
int add_argument(Shared *s, int type)
{
struct var_def *t;
if (lang_debug) printf("D: add argument %s (%d)\n", s->str, type);
t = (struct var_def *)malloc(sizeof(struct var_def));
t->name = s;
t->v = 0;
t->next = arg_head;
t->type = type;
arg_head = t;
num_args++;
return num_args;
}
/* head insertion for locals. */
int add_local_variable(Shared *s, int type)
{
struct var_def *t;
if (lang_debug) printf("D: add local %s\n", s->str);
t = (struct var_def *)malloc(sizeof(struct var_def));
t->name = s;
t->next = local_head;
t->v = 0;
t->type = type;
local_head = t;
num_locals++;
max_locals++;
num_block_locals[block_depth]++;
return max_locals;
}
int find_local_variable(Shared *s)
{
struct var_def *t;
int d = max_locals;
t = local_head;
#if 0
while (t && d > num_locals) {
d--;
t = t->next;
}
#endif
while (t && d > 0) {
if (t->name == s) {
/* printf("find_local %s\n", t->name); */
last_type = t->type;
return d;
}
t = t->next;
d--;
}
return 0;
}
int find_local_block(Shared *s)
{
struct var_def *t;
int d = max_locals, i = 0;
t = local_head;
while (t && d > num_locals)
{
d--;
t = t->next;
}
while (t && i < num_block_locals[block_depth])
{
i++;
d--;
if (t->name == s) return d;
t = t->next;
}
return 0;
}
void free_locals()
{
struct var_def *x, *t = local_head;
while (t)
{
x = t;
t = t->next;
free(x);
}
t = arg_head;
while (t)
{
x = t;
t = t->next;
free(x);
}
local_head = 0;
arg_head = 0;
}
int constant_fold(int type)
{
int size = 10, flag = 0, r;
if (type == S_PLUS)
{
if (puinstr == S_PUSHs &&
uinstr == S_PUSHs)
{
#if 0
return 0;
printf("constant fold %s + %s\n", penultima.s,
ultima.s;
#endif
/* should this ever happen?? */
if (!penultima.s || !ultima.s) return 0;
lex_strcat(penultima.s, ultima.s);
/* nuke off folded instructions */
CPD->current_I = CPD->current_I - (sizeof(Shared *)*2 + 2);
/* need to nuke off last 2 from patch list */
remove_patch(CPD);
remove_patch(CPD);
#if 0
Patch *old;
old = ((Patch *)CPD->patch);
CPD->patch = (char **)((Patch *)CPD->patch)->next->next;
CPD->num_str = CPD->num_str - 2;
free(old->next);
free(old);
#endif
add_patch(CPD, P_STRING, penultima.s);
emit64(S_PUSHs, zero);
ultima.s = penultima.s;
penultima.s = 0;
return 1;
}
}
return 0;
if ( (puinstr == S_PUSHi && uinstr == S_PUSH8) ||
(puinstr == S_PUSH8 && uinstr == S_PUSHi) ) {
size = 7;
flag = 1;
}
if (puinstr == S_PUSH8 && uinstr == S_PUSH8) {
size = 4;
flag = 1;
}
if (flag || (puinstr == S_PUSHi &&
uinstr == S_PUSHi)) {
switch(type)
{
case S_PLUS:
r = ultima.i + penultima.i;
#if 0
printf("constant fold %d + %d in %s\n", penultima.i, ultima.i, current_file);
#endif
break;
case S_MULT:
r = penultima.i * ultima.i;
break;
case S_DIVIDE:
r = penultima.i / ultima.i;
break;
case S_MOD:
r = penultima.i % ultima.i;
break;
case S_MINUS:
r = penultima.i - ultima.i;
default:
break;
}
CPD->current_I = CPD->current_I - (short)size;
if (r <= MAXFIXEDINT && r >= MINFIXEDINT)
{
emit(S_PUSH8, r);
}
else
{
emit32(S_PUSHi, (char *)&r);
}
puinstr = 0;
ultima.i = r;
penultima.i = 0;
return 1;
}
#if 0
if (CPD->block[p-11] == S_PUSHr &&
CPD->block[p-6] == S_PUSHr) {
switch(type)
{
case S_PLUS:
z = ultima.r + penultima.r;
break;
case S_MULT:
z = ultima.r * penultima.r;
break;
case S_DIVIDE:
z = ultima.r / penultima.r;
break;
case S_MOD:
yyerror("Illegal modulo on type real.\n");
break;
case S_MINUS:
z = ultima.r - penultima.r;
break;
default:
break;
}
CPD->current_I = CPD->current_I - size;
emit32(S_PUSHr, (char *)&z);
return 1;
}
#endif
return 0;
}
int type_check(int a, int b, int c, char * where)
{
return 1;
/* FIX: ALERT: this isn't correct for pointer offsets and structs */
if (!(a & b)) {
yyerrorf("Types don't match in %s\n", where);
#if 0
fprintf(stderr,"NM on a "); print_type(a);
fprintf(stderr,"NM on b "); print_type(b);
#endif
return 0;
}
if (!(a & c)) {
#if 0
printf("type expr = %d\n", a);
fprintf(stderr,"IT on a "); print_type(a);
#endif
yyerrorf("Illegal type present in %s\n", where);
return 0;
}
return 1;
}
void print_type(int x)
{
switch (x) {
case T_NUMBER:
fprintf(stderr,"type integer\n");
break;
case T_REAL:
fprintf(stderr,"type real\n");
break;
case T_POINTER:
fprintf(stderr,"type pointer\n");
break;
case T_OBJECT:
fprintf(stderr,"type object\n");
break;
case T_ANY:
fprintf(stderr,"type any\n");
break;
case T_STRING:
fprintf(stderr,"type string\n");
break;
default:
fprintf(stderr,"Unknown type %d\n", x);
break;
}
}
typedef struct TL
{
Shared * name;
Class * obj;
} Type_list;
#define MAX_CLASSES 16 /* I know - small to start with
but hey this many unloaded classes would fuck up! */
Type_list * type_list[MAX_CLASSES];
void
add_type_list(Shared * name, Class * object)
{
Type_list * tmp;
// FIX: space leak .. these never get freed
tmp = (Type_list *) malloc (sizeof(Type_list));
tmp->name = name;
tmp->obj = object;
type_list[no_of_classes] = tmp;
no_of_classes++;
}
void free_type_list()
{
int i;
for (i = 0; i < no_of_classes; i++)
{
if (type_list[i]) free_string(type_list[i]->name);
free(type_list[i]);
type_list[i] = 0;
}
no_of_classes = 0;
}
/*
we overload struct field (blech!)
using offset for the size we want
and
*/
struct field * find_type(Shared * name)
{
struct field * tmp;
int i;
#if 0
printf("find_type\n");
#endif
for (i = 0; i < no_of_classes; i++) {
if (type_list[i]->name == name) {
tmp = (struct field *)malloc(sizeof(struct field));
tmp->offset = type_list[i]->obj->num_variables;
tmp->type = ((i+1) << 24) | T_POINTER;
return tmp;
}
}
yyerrorf("No such class: %s imported.\n", name->str);
return 0;
}
/*
returns a struct of "offset" and type of offset
*/
struct field * find_type_info(unsigned int typestuff, Shared * fieldname)
{
unsigned int classnum;
struct field * tmp;
Class * tobj;
int i;
if (typestuff & 0x00ff0000)
{
yyerror("Type error accessing an array as a class.\n");
return 0;
}
classnum = ((typestuff & 0xff000000) >> 24) -1 ;
if (classnum >= no_of_classes) {
yyerror("Failed to resolve class type correctly.\n");
return 0;
}
tmp = (struct field *)malloc(sizeof(struct field));
#if 0
printf("find_type_info %d.\n", classnum);
#endif
tobj = type_list[classnum]->obj;
/* printf("find_type_info: %s.\n", tobj->name); */
for (i = 0; i < (int)tobj->num_variables; i++) {
#if 0
printf("type info: %s\n", tobj->global_table[i]->u.string);
#endif
if (tobj->global_table[i]->u.string == fieldname) {
tmp->offset = i;
tmp->type = tobj->global_table[i]->type & 0xff;
return tmp;
}
}
yyerrorf("Unknown fieldname used in class %s.\n", tobj->name->str);
return 0;
}
/*
The emulate file contains emulation functions only at
the "top" level (inherited files do not have their functions
added to the emulation).
(this could be changed using "find_program" - but this
has other side effects and is slow compared to 1 hash lookup).
Should return 0 if the fun is "::<something>"
so we can do direct calls to the driver and ignore the
simulated efuns.
*/
struct keyword * lookup_emulate(Shared * fun)
{
struct keyword * retval;
Func * pr = 0;
if (!Emulate) return NULL;
pr = Hfunction(fun, Emulate->name);
if (!pr) return 0;
retval = (struct keyword *) malloc(sizeof(struct keyword));
retval->word = pr->name;
retval->token = (short)F_EMULATE;
retval->params = -1;
return retval;
}
void end_of_statement()
{
if (uinstr == S_POPI)
{
CPD->block[CPD->current_I-1] = S_POPO;
uinstr = S_POPI;
}
}