{$ifdef tp}
{E+,N+}
{$endif}
{****************************************************************************
Copyright (c) 1993,96 by Florian Klämpfl
****************************************************************************}
unit parser;
interface
uses
objects,scanner,globals,systems,symtable,tree,cobjects,asmgen,codegen,
asmbl,tempad,dos,types,strings,opt,pass_1,hcodegen;
procedure compile(const path,filename : string);
const
heapsize : longint = 4000000;
stacksize : longint = 8096;
implementation
{$I innr.inc}
var
token : ttoken;
datasize : longint; { Größe des Datensegmentes, wird von proc_unit }
{ oder proc_program gesetzt }
refsymtable : psymtable; { Symboltabelle in welcher die }
{ Unitreferenzen abgelegt werden sollen }
parse_only : boolean; { wird auf true gesetzt, wenn }
{ nur Funktionsköpfe geparst werden sollen }
function befehlsblock : ptree;forward;
function anweisung : ptree;forward;
function typ(const name : stringid) : pdef;forward;
function expr : ptree;forward;
function block : ptree;forward;
procedure proc_head;forward;
procedure formal_parameter_list;forward;
{ versucht das Token i zu consumieren, paßt }
{ das Token nicht, so wird ein Syntaxfehler }
{ ausgegeben }
procedure consume(i : ttoken);
{ gibt einen Syntaxfehler aus }
procedure syntaxerror(const s : string);
begin
exterror:=strpnew(s+' erwartet. ');
error(syntax_error);
end;
const tokens : array[PLUS..CCHAR] of string[12] = (
'+','-','*','/','=','>','<','[',']',
'.',',','(',')',':',';','^',
'@',':=','<>','>=','<=','..',
'Bezeichner','real. Konst.','Dateiende',
'ord. Konst.','Stringkonst.','Charkonst.');
var
j : integer;
begin
if token<>i then
begin
if i<_ABSOLUTE then
syntaxerror(tokens[i])
else
begin
{ um die Programmgröße klein zu halten, }
{ wird für ein Schlüsselwort-Token der }
{ "Text" in der Schlüsselworttabelle }
{ des Scanners nachgeschaut }
for j:=1 to anz_keywords do
if keyword_token[j]=i then
syntaxerror(keyword[j])
end;
end
else
token:=yylex;
end;
{ liest eine Liste durch Komma getrennter Bezeichner }
{ in eine Stringcontainer ein }
function idlist : pstringcontainer;
var
sc : pstringcontainer;
begin
sc:=new(pstringcontainer,init);
repeat
sc^.insert(pattern);
consume(ID);
if token=COMMA then consume(COMMA)
else break
until false;
idlist:=sc;
end;
procedure label_dec;
begin
consume(_LABEL);
if not(cs_support_goto in aktswitches )
then error(goto_label_not_support);
repeat
if (token<>ID) and (token<>INTCONST) then
consume(ID)
else
begin
symtablestack^.insert(new(plabelsym,init(pattern,getlabel)));
consume(token);
end;
if token<>SEMICOLON then consume(COMMA);
until (token<>ID) and (token<>INTCONST);
consume(SEMICOLON);
end;
{ fügt die Symbole aus sc mit def in st ein }
{ entfernt sc! }
procedure insert_syms(st : psymtable;sc : pstringcontainer;def : pdef);
var
s : string;
begin
s:=sc^.get;
while s<>'' do
begin
st^.insert(new(pvarsym,init(s,def)));
s:=sc^.get;
end;
dispose(sc,done);
end;
{ liest einen einzelnen Stringtyp mit optionaler }
{ Längenangabe und gibt einen Pointer auf die }
{ Definition zurück }
function stringtyp : pdef;
var
p : ptree;
d : pdef;
begin
consume(_STRING);
if token=LECKKLAMMER then
begin
consume(LECKKLAMMER);
p:=expr;
do_firstpass(p);
if not is_constintnode(p) then
error(error_in_expression);
if (p^.value<1) or (p^.value>255) then
begin
error(string_too_long);
p^.value:=255;
end;
consume(RECKKLAMMER);
d:=new(pstringdef,init(p^.value));
end
else d:=new(pstringdef,init(255));
stringtyp:=d;
end;
var
{ Zeiger auf das zuletzt gelesene Typsymbol }
{ (für "forward"-Typen) }
lasttypesym : ptypesym;
{ "Krücken"konstruktion um das Problem zu beheben, daß }
{ der Typ der momentan geparst werdenden Objektdeklaration }
{ als Funktionsparameter verwendet werden kann }
testaktobject : byte;
aktobjectname : stringid;
aktobjectdef : pdef;
{ liest einen Typbezeichner und gibt einen }
{ Pointer auf die Definition zurück }
{ s ist der Name des Typs }
function id_type(var s : string) : pdef;
begin
s:=pattern;
consume(ID);
if (testaktobject=2) and (aktobjectname=pattern) then
begin
id_type:=aktobjectdef;
exit;
end;
getsym(s,true);
if assigned(srsym) then
begin
if srsym^.typ=unitsym then
begin
consume(POINT);
getsymonlyin(punitsym(srsym)^.unitsymtable,pattern);
s:=pattern;
consume(ID);
end;
if srsym^.typ<>typesym then
begin
error(type_id_expect);
lasttypesym:=ptypesym(srsym);
id_type:=generrordef;
exit;
end;
end;
lasttypesym:=ptypesym(srsym);
id_type:=ptypesym(srsym)^.definition;
end;
{ liest einen String oder Typbezeichner }
{ und gibt einen Pointer auf die }
{ Definition zurück }
function single_type(var s : string) : pdef;
begin
case token of
_STRING : begin
single_type:=stringtyp;
s:='STRING';
lasttypesym:=nil;
end;
else single_type:=id_type(s);
end;
end;
{ liest die Feldliste eines Records in }
{ symtablestack ein }
{ wenn record=false, dann können auch }
{ Klassenfelder eingelesen werden, da }
{ variante Recordkonstruktionen igno- }
{ riert werden }
{ do_absolute, gibt an, ob ABSOLUTE, }
{ sowie Dateitypen erlaubt sind }
procedure feldliste(is_record : boolean;do_absolute : boolean);
var
sc : pstringcontainer;
s : stringid;
p,casedef : pdef;
hs : string;
{ maxsize enthält maximale Größe eines varianten Astes }
{ startvarrec die Startaddresse des varianten Teiles }
maxsize,startvarrec : longint;
pt : ptree;
old_parse_types : boolean;
begin
old_parse_types:=parse_types;
parse_types:=true;
while token=ID do
begin
sc:=idlist;
consume(COLON);
p:=typ('');
if do_absolute and (token=_ABSOLUTE) then
begin
consume(_ABSOLUTE);
end
else
begin
insert_syms(symtablestack,sc,p);
end;
if token<>SEMICOLON then
break
else
consume(SEMICOLON);
while token=SEMICOLON do
consume(SEMICOLON);
end;
if (token=_CASE) and is_record then
begin
maxsize:=0;
consume(_CASE);
s:=pattern;
getsym(s,false);
{ may be only a type: }
if assigned(srsym) and ((srsym^.typ=typesym) or
{ and with unit qualifier: }
(srsym^.typ=unitsym)) then
begin
casedef:=single_type(hs);
end
else
begin
consume(ID);
consume(COLON);
casedef:=single_type(hs);
symtablestack^.insert(new(pvarsym,init(s,casedef)));
end;
if not is_ordinal(casedef) then
error(ordinal_expect);
consume(_OF);
startvarrec:=symtablestack^.datasize;
repeat
repeat
pt:=expr;
do_firstpass(pt);
if not(pt^.treetype=ordconstn) then
error(error_in_expression);
if token=COMMA then consume(COMMA)
else break;
until false;
consume(COLON);
consume(LKLAMMER);
if token<>RKLAMMER then
feldliste(true,false);
{ calc max variant size }
maxsize:=max(maxsize,symtablestack^.datasize);
symtablestack^.datasize:=startvarrec;
consume(RKLAMMER);
if token<>SEMICOLON then
break
else
consume(SEMICOLON);
while token=SEMICOLON do
consume(SEMICOLON);
until (token=_END) or (token=RKLAMMER);
symtablestack^.datasize:=maxsize;
end;
parse_types:=old_parse_types;
end;
procedure _proc_head(options : word);forward;
procedure constructor_head;
begin
consume(_CONSTRUCTOR);
_proc_head(poconstructor);
if cs_checkconsname in aktswitches then
if aktprocsym^.name<>'INIT' then
error(konstrucname_init);
consume(SEMICOLON);
{ der Rückgabetyp von Konstruktoren ist Boolean }
aktprocsym^.definition^.retdef:=
new(pgrunddef,init(bool8bit,0,1));
end;
procedure destructor_head;
begin
consume(_DESTRUCTOR);
if cs_checkconsname in aktswitches then
if aktprocsym^.name<>'DONE' then
error(destrucname_done);
_proc_head(podestructor);
consume(SEMICOLON);
if assigned(aktprocsym^.definition^.para1) then
error(no_paras_2_destructor);
{ kein Rückgabetyp }
aktprocsym^.definition^.retdef:=voiddef;
end;
function object_dec(const n : stringid) : pdef;
type
tzugriffsmode = (priv,prot,pub);
var
aktzugriffsmode : tzugriffsmode;
there_are_a_destructor : boolean;
procedure object_komponenten;
var
oldparse_only : boolean;
begin
testaktobject:=1;
aktobjectname:=n;
repeat
case token of
ID : feldliste(false,false);
_PROCEDURE,_FUNCTION : begin
oldparse_only:=parse_only;
parse_only:=true;
proc_head;
parse_only:=oldparse_only;
if token=_VIRTUAL then
begin
if aktzugriffsmode=priv then
error(priv_meth_not_virtual);
consume(_VIRTUAL);
consume(SEMICOLON);
aktprocsym^.definition^.options:=
aktprocsym^.definition^.options or povirtualmethod;
end;
end;
_CONSTRUCTOR : begin
if aktzugriffsmode<>pub then
error(const_cannot_priv);
oldparse_only:=parse_only;
parse_only:=true;
constructor_head;
parse_only:=oldparse_only;
end;
_DESTRUCTOR : begin
if there_are_a_destructor then
warning(only_one_destructor);
there_are_a_destructor:=true;
if aktzugriffsmode<>pub then
error(dest_cannot_priv);
oldparse_only:=parse_only;
parse_only:=true;
destructor_head;
parse_only:=oldparse_only;
if token=_VIRTUAL then
begin
consume(_VIRTUAL);
consume(SEMICOLON);
aktprocsym^.definition^.options:=
aktprocsym^.definition^.options or povirtualmethod;
end;
end;
_END,_PROTECTED,_PRIVATE,_PUBLIC : exit;
else error(syntax_error);
end;
until false;
testaktobject:=0;
end;
var
childof : pclassdef;
_class : pclassdef;
begin
there_are_a_destructor:=false;
aktzugriffsmode:=pub;
if (symtablestack^.symtabletype and $3fff<>globalsymtable) and
(symtablestack^.symtabletype and $3fff<>staticsymtable) then
error(no_local_objects);
if n='' then error(no_anonym_objects);
consume(_OBJECT);
childof:=nil;
if token=LKLAMMER then
begin
consume(LKLAMMER);
if token<>ID then
consume(ID);
getsym(pattern,true);
if (srsym^.typ<>typesym) and
(ptypesym(srsym)^.definition^.deftype<>classdef) then
begin
error(class_type_expect);
childof:=nil;
end
else childof:=pclassdef(ptypesym(srsym)^.definition);
consume(ID);
consume(RKLAMMER);
end;
_class:=new(pclassdef,init(n,childof));
aktobjectdef:=_class;
{ Default: public }
aktzugriffsmode:=pub;
_class^.publicsyms^.next:=symtablestack;
symtablestack:=_class^.publicsyms;
procinfo._class:=_class;
while token<>_END do
begin
if token=_PRIVATE then
begin
consume(_PRIVATE);
{
symtablestack:=symtablestack^.next;
_class^.privatesyms^.next:=symtablestack;
symtablestack:=_class^.privatesyms;
aktzugriffsmode:=priv;
}
end;
if token=_PROTECTED then
begin
consume(_PROTECTED);
{
symtablestack:=symtablestack^.next;
_class^.protectedsyms^.next:=symtablestack;
symtablestack:=_class^.protectedsyms;
aktzugriffsmode:=prot;
}
end;
if token=_PUBLIC then
begin
consume(_PUBLIC);
symtablestack:=symtablestack^.next;
_class^.publicsyms^.next:=symtablestack;
symtablestack:=_class^.publicsyms;
aktzugriffsmode:=pub;
end;
object_komponenten;
end;
consume(_END);
{ VMT erzeugen: }
vmtasmlist.concat(gennasmrec(DIRECT,S_NO,'.globl VMT_'+n));
vmtasmlist.concat(gennasmrec(DIRECT,S_NO,'VMT_'+n+':'));
vmtasmlist.concat(gennasmrec(A_LONG,S_NO,tostr(_class^.size)));
vmtasmlist.concat(gennasmrec(A_LONG,S_NO,tostr(-_class^.size)));
if assigned(_class^.childof) then
vmtasmlist.concat(gennasmrec(A_LONG,S_NO,'VMT_'+_class^.childof^.name^))
else
vmtasmlist.concat(gennasmrec(A_LONG,S_NO,'0'));
genvmt(_class);
symtablestack:=symtablestack^.next;
procinfo._class:=nil;
object_dec:=_class;
end;
{ liest eine Recorddefinition und gibt }
{ einen Pointer darauf zurück }
function record_dec : pdef;
var
symtable : psymtable;
begin
symtable:=new(psymtable,init(recordsymtable));
symtable^.next:=symtablestack;
symtablestack:=symtable;
consume(_RECORD);
feldliste(true,false);
consume(_END);
symtablestack:=symtable^.next;
record_dec:=new(precdef,init(symtable));
end;
{ liest eine Typdefinition und gibt einen }
{ Pointer darauf zurück }
function typ(const name : stringid) : pdef;
var
procvardef : pprocvardef;
procedure handle_procvar;
var
sc : pstringcontainer;
s : string;
p : pdef;
varspez : tvarspez;
begin
procvardef:=new(pprocvardef,init);
if cs_genexceptcode in aktswitches then
procvardef^.options:=procvardef^.options or poexceptions;
if token=LKLAMMER then
begin
consume(LKLAMMER);
inc(testaktobject);
repeat
if token=_VAR then
begin
consume(_VAR);
varspez:=vs_var;
end
else if token=_CONST then
begin
consume(_CONST);
varspez:=vs_const;
end
else varspez:=vs_value;
sc:=idlist;
if token=COLON then
begin
consume(COLON);
p:=single_type(s);
end
else
p:=new(pformaldef,init);
s:=sc^.get;
while s<>'' do
begin
procvardef^.concatdef(p,varspez);
s:=sc^.get;
end;
dispose(sc,done);
if token=SEMICOLON then consume(SEMICOLON)
else break;
until false;
dec(testaktobject);
consume(RKLAMMER);
end;
end;
var
hp1,p : pdef;
pt : ptree;
aufdef : paufzaehldef;
ap : parraydef;
s : stringid;
l : longint;
hs : string;
begin
case token of
ID : p:=id_type(hs);
LKLAMMER :
begin
consume(LKLAMMER);
l:=-1;
aufdef:=new(paufzaehldef,init);
repeat
s:=pattern;
consume(ID);
if token=ASSIGNMENT then
begin
consume(ASSIGNMENT);
pt:=expr;
do_firstpass(pt);
if not is_constintnode(pt) then
error(error_in_expression)
else l:=pt^.value;
if pt^.value<=l then
error(dup_enum);
disposetree(pt);
end
else
inc(l);
constsymtable^.insert(new(paufzaehlsym,init(s,aufdef,l)));
if token=COMMA then consume(COMMA)
else break;
until false;
aufdef^.max:=l;
p:=aufdef;
consume(RKLAMMER);
end;
_STRING : p:=stringtyp;
_ARRAY :
begin
consume(_ARRAY);
consume(LECKKLAMMER);
p:=nil;
repeat
{ Ausdruck lesen und prüfen }
pt:=expr;
if pt^.treetype=typen then
begin
if pt^.resulttype^.deftype<>aufzaehldef then
error(error_in_type);
if p=nil then
begin
ap:=new(parraydef,
init(0,paufzaehldef(pt^.resulttype)^.max,pt^.resulttype));
p:=ap;
end
else
begin
ap^.definition:=new(parraydef,
init(0,paufzaehldef(pt^.resulttype)^.max,pt^.resulttype));
ap:=parraydef(ap^.definition);
end;
end
else
begin
do_firstpass(pt);
if (pt^.treetype<>rangen) or
(pt^.left^.treetype<>ordconstn) then
error(error_in_type);
{ Registrierung der Grenzen erzwingen: }
if pt^.right^.resulttype=pdef(s32bitdef) then
pt^.right^.resulttype:=new(pgrunddef,init(
s32bit,$80000000,$7fffffff));
if p=nil then
begin
ap:=new(parraydef,init(pt^.left^.value,pt^.right^.value,pt^.right^.resulttype));
p:=ap;
end
else
begin
ap^.definition:=new(parraydef,init(pt^.left^.value,pt^.right^.value,pt^.right^.resulttype));
ap:=parraydef(ap^.definition);
end;
end;
if token=COMMA then consume(COMMA)
else break;
until false;
consume(RECKKLAMMER);
consume(_OF);
ap^.definition:=typ('');
end;
_SET : begin
consume(_SET);
consume(_OF);
hp1:=typ('');
case hp1^.deftype of
aufzaehldef : p:=new(psetdef,init(hp1,paufzaehldef(hp1)^.max));
grunddef : begin
case pgrunddef(hp1)^.typ of
uchar : p:=new(psetdef,init(hp1,255));
u8bit,s8bit,u16bit,s16bit,s32bit :
begin
if (pgrunddef(hp1)^.von>=0) then
p:=new(psetdef,init(hp1,pgrunddef(hp1)^.bis))
else error(illsettype);
end;
else error(illsettype);
end;
end;
else error(illsettype);
end;
end;
{ _FILE : begin
consume(_FILE);
if token=_OF then
begin
consume(_OF);
p:=typ('');
end;
end; }
CARET : begin
consume(CARET);
forwardsallowed:=true;
hp1:=single_type(hs);
p:=new(ppointerdef,init(hp1));
if lasttypesym<>nil then
save_forward(ppointerdef(p),lasttypesym);
forwardsallowed:=false;
end;
_RECORD : begin
p:=record_dec;
end;
_OBJECT : begin
p:=object_dec(name);
end;
_PROCEDURE : begin
consume(_PROCEDURE);
handle_procvar;
p:=procvardef;
end;
_FUNCTION : begin
consume(_FUNCTION);
handle_procvar;
if token<>COLON then
begin
consume(COLON);
while token<>SEMICOLON do
consume(token);
end
else
begin
consume(COLON);
procvardef^.retdef:=single_type(hs);
p:=procvardef;
end;
end;
else
begin
{ kann dann nur Bereichstyp sein }
pt:=expr;
do_firstpass(pt);
{ erlaubter Ausdruck ? }
if (pt^.treetype<>rangen) or
(pt^.left^.treetype<>ordconstn) then
error(error_in_type);
p:=new(pgrunddef,init(uauto,pt^.left^.value,pt^.right^.value));
disposetree(pt);
end;
end;
typ:=p;
end;
{ sucht in symtablestack nach zwar daklarierten }
{ aber nicht definierten Typen }
procedure testforward_types(p : psym);far;
begin
if (p^.typ=typesym) and (p^.forwarddef) then
error(type_id_not_defined);
end;
{ liest den type-Abschnitt in symtablestack ein }
procedure type_dec;
var
typename : stringid;
begin
parse_types:=true;
consume(_TYPE);
repeat
typename:=pattern;
consume(ID);
consume(EQUAL);
symtablestack^.insert(new(ptypesym,init(typename,typ(typename))));
consume(SEMICOLON);
until token<>ID;
{$ifdef tp}
symtablestack^.foreach(testforward_types);
{$else}
symtablestack^.foreach(@testforward_types);
{$endif}
resolve_forwards;
parse_types:=false;
end;
{ parst Variablendeklarationen und fügt sie in die }
{ oberste Symboltabelle ein }
procedure var_dec;
var
p : pdef;
sc : pstringcontainer;
begin
consume(_VAR);
feldliste(false,true);
end;
procedure readtypedconst(def : pdef);
var
p : ptree;
i,l : longint;
s : string;
ca : array[0..512] of char;
aktpos : longint;
pd : pprocdef;
hp1,hp2 : pdefcoll;
begin
case def^.deftype of
grunddef : begin
p:=expr;
do_firstpass(p);
case pgrunddef(def)^.typ of
{!!!!!! Rangechecking }
s8bit,
u8bit : begin
if not is_constintnode(p) then
{ Hier einfach Fehler ausgeben, der }
{ falsche Wert macht überhaubt nichts }
error(error_in_expression);
constsegment.concat(gennasmrec(A_BYTE,S_NO,tostr(p^.value)));
end;
s32bit : begin
if not is_constintnode(p) then
error(error_in_expression);
constsegment.concat(gennasmrec(A_LONG,S_NO,tostr(p^.value)));
end;
s64real : begin
if not is_constrealnode(p) then
error(error_in_expression);
constsegment.concat(gennasmrec(A_DOUBLE,S_NO,double2str(p^.value)));
end;
bool8bit : begin
if not is_constboolnode(p) then
error(error_in_expression);
constsegment.concat(gennasmrec(A_BYTE,S_NO,tostr(p^.value)));
end;
uchar : begin
if not is_constcharnode(p) then
error(error_in_expression);
constsegment.concat(gennasmrec(A_BYTE,S_NO,tostr(p^.value)));
end;
u16bit,
s16bit : begin
if not is_constintnode(p) then
error(error_in_expression);
constsegment.concat(gennasmrec(A_WORD,S_NO,tostr(p^.value)));
end;
end;
disposetree(p);
end;
pointerdef : begin
p:=expr;
do_firstpass(p);
if p^.treetype=niln then
constsegment.concat(gennasmrec(A_LONG,S_NO,'0'))
else
{ kann sonst nur noch PCHAR sein }
if (ppointerdef(def)^.definition^.deftype=grunddef) and
(pgrunddef(ppointerdef(def)^.definition)^.typ=uchar) then
begin
l:=getlabel;
{ String am Anfang einfügen }
if p^.treetype=stringconstn then
constsegment.insert(gennasmrec(ASCII,S_NO,'"'+ibm2ascii(p^.values^)+'\0"'))
else if is_constcharnode(p) then
constsegment.insert(gennasmrec(ASCII,S_NO,'"'+ibm2ascii(char(byte(p^.value)))+'\0"'))
else error(error_in_expression);
constsegment.insert(genlasmrec(A_LABEL,l));
{ Label einfügen }
constsegment.concat(gennasmrec(A_LONG,S_NO,tolabel(l)));
end
else error(error_in_expression);
disposetree(p);
end;
aufzaehldef : begin
p:=expr;
do_firstpass(p);
if p^.treetype=ordconstn then
begin
if is_equal(p^.resulttype,def) then
begin
constsegment.concat(gennasmrec(A_LONG,S_NO,tostr(p^.value)));
end
else
error(error_in_expression);
end
else
error(error_in_expression);
disposetree(p);
end;
stringdef : begin
p:=expr;
do_firstpass(p);
if p^.treetype=stringconstn then
begin
s:=p^.values^;
if length(s)+1>def^.size then
s[0]:=chr(def^.size-1);
constsegment.concat(gennasmrec(ASCII,S_NO,'"'+ibm2ascii(
char(length(s))+s)+'"'));
end
else if is_constcharnode(p) then
begin
constsegment.concat(gennasmrec(ASCII,S_NO,'"\001'+ibm2ascii(
char(byte(p^.value)))+'"'));
s:=char(byte(p^.value));
end
else error(error_in_expression);
ca[0]:='"';
fillchar(ca[1],def^.size-length(s)-1,' ');
ca[def^.size-length(s)]:='"';
ca[def^.size-length(s)+1]:=#0;
constsegment.concat(genpasmrec(ASCII,S_NO,ca));
disposetree(p);
end;
arraydef : begin
consume(LKLAMMER);
for l:=parraydef(def)^.lowrange to parraydef(def)^.highrange-1 do
begin
readtypedconst(parraydef(def)^.definition);
consume(COMMA);
end;
readtypedconst(parraydef(def)^.definition);
consume(RKLAMMER);
end;
procvardef : begin
if token=KLAMMERAFFE then
consume(KLAMMERAFFE);
getsym(pattern,true);
consume(ID);
if srsym^.typ=unitsym then
begin
consume(POINT);
getsymonlyin(punitsym(srsym)^.unitsymtable,pattern);
consume(ID);
end;
if srsym^.typ<>procsym then
error(error_in_expression)
else
begin
pd:=pprocsym(srsym)^.definition;
if assigned(pd^.nextoverloaded) then
error(no_overloaded_procvars);
if not((pprocvardef(def)^.options=pd^.options)) or
not(is_equal(pprocvardef(def)^.retdef,pd^.retdef)) then
error(type_mismatch)
else
begin
hp1:=pprocvardef(def)^.para1;
hp2:=pd^.para1;
while assigned(hp1) and assigned(hp2) do
begin
if not(is_equal(hp1^.data,hp2^.data)) or
not(hp1^.paratyp=hp2^.paratyp) then
begin
error(type_mismatch);
break;
end;
hp1:=hp1^.next;
hp2:=hp2^.next;
end;
if not((hp1=nil) and (hp2=nil)) then
error(type_mismatch);
end;
constsegment.concat(gennasmrec(A_LONG,
S_NO,pd^.mangledname));
end;
end;
recorddef : begin
consume(LKLAMMER);
aktpos:=0;
while token<>RKLAMMER do
begin
s:=pattern;
consume(ID);
consume(COLON);
srsym:=precdef(def)^.symtable^.search(s);
if srsym=nil then
begin
error(id_not_found);
while token<>SEMICOLON do
consume(token);
end
else
begin
{ Position überprüfen }
if pvarsym(srsym)^.adresse<aktpos then
error(invalid_record_const);
{ gegebenenfalls auffüllen }
if pvarsym(srsym)^.adresse>aktpos then
for i:=1 to pvarsym(srsym)^.adresse-aktpos do
constsegment.concat(gennasmrec(A_BYTE,S_NO,'0'));
{ neue Position }
aktpos:=pvarsym(srsym)^.adresse+pvarsym(srsym)^.definition^.size;
{ eigentliche Daten lesen }
readtypedconst(pvarsym(srsym)^.definition);
if token=SEMICOLON then
consume(SEMICOLON)
else break;
end;
end;
for i:=1 to def^.size-aktpos do
constsegment.concat(gennasmrec(A_BYTE,S_NO,'0'));
consume(RKLAMMER);
end;
else error(type_const_not_possible);
end;
end;
procedure const_dec;
var
name : stringid;
p : ptree;
def : pdef;
pd : pdouble;
begin
consume(_CONST);
repeat
name:=pattern;
consume(ID);
case token of
EQUAL : begin
consume(EQUAL);
p:=expr;
do_firstpass(p);
case p^.treetype of
ordconstn : begin
if is_constintnode(p) then
symtablestack^.insert(new(pconstsym,init(name,constint,p^.value,nil)))
else if is_constcharnode(p) then
symtablestack^.insert(new(pconstsym,init(name,constchar,p^.value,nil)))
else if is_constboolnode(p) then
symtablestack^.insert(new(pconstsym,init(name,constbool,p^.value,nil)))
else if p^.resulttype^.deftype=aufzaehldef then
symtablestack^.insert(new(pconstsym,init(name,constord,p^.value,p^.resulttype)))
else internalerror(111);
end;
stringconstn :
symtablestack^.insert(new(pconstsym,init(name,conststring,longint(p^.values),nil)));
realconstn : begin
new(pd);
pd^:=p^.valued;
symtablestack^.insert(new(pconstsym,init(name,constreal,longint(pd),nil)));
end;
else error(error_in_expression);
end;
consume(SEMICOLON);
end;
COLON : begin
consume(COLON);
def:=typ('');
symtablestack^.insert(new(ptypedconstsym,init(name,def)));
consume(EQUAL);
readtypedconst(def);
consume(SEMICOLON);
end;
else consume(EQUAL);
end;
until token<>ID;
end;
function if_anweisung : ptree;
var
ex,if_a,else_a : ptree;
l1,l2,hl : longint;
begin
consume(_IF);
ex:=expr;
consume(_THEN);
if token<>_ELSE then
if_a:=anweisung
else if_a:=nil;
if token=_ELSE then
begin
consume(_ELSE);
else_a:=anweisung;
end
else
else_a:=nil;
if_anweisung:=genloopnode(ifn,ex,if_a,else_a,false);
end;
function case_anweisung : ptree;
var
{ contains the label number of currently parsed case block }
aktcaselabel : longint;
wurzel : pcaserecord;
{ the typ of the case expression }
casedef : pdef;
procedure newcaselabel(l,h : longint);
var
hcaselabel : pcaserecord;
procedure insertlabel(var p : pcaserecord);
begin
if p=nil then p:=hcaselabel
else
if (p^.low>hcaselabel^.low) and
(p^.low>hcaselabel^.high) then
insertlabel(p^.less)
else if (p^.high<hcaselabel^.low) and
(p^.high<hcaselabel^.high) then
insertlabel(p^.greater)
else error(double_caselabel);
end;
begin
new(hcaselabel);
hcaselabel^.less:=nil;
hcaselabel^.greater:=nil;
hcaselabel^.anweisung:=aktcaselabel;
hcaselabel^.at:=getlabel;
hcaselabel^.low:=l;
hcaselabel^.high:=h;
insertlabel(wurzel);
end;
var
code,caseexpr,p,instruc,elseblock : ptree;
hl1,hl2 : longint;
ranges : boolean;
begin
consume(_CASE);
caseexpr:=expr;
{ determines result type }
cleartempgen;
do_firstpass(caseexpr);
casedef:=caseexpr^.resulttype;
if not(is_ordinal(casedef)) then
error(ordinal_expect);
consume(_OF);
wurzel:=nil;
ranges:=false;
instruc:=nil;
repeat
aktcaselabel:=getlabel;
{ an instruction has may be more case labels }
repeat
p:=expr;
cleartempgen;
do_firstpass(p);
if (p^.treetype=rangen) then
begin
hl1:=get_ordinal_value(p^.left);
hl2:=get_ordinal_value(p^.right);
testrange(casedef,hl1);
testrange(casedef,hl2);
newcaselabel(hl1,hl2);
ranges:=true;
end
else
begin
hl1:=get_ordinal_value(p);
testrange(casedef,hl1);
newcaselabel(hl1,hl1);
end;
disposetree(p);
if token=COMMA then consume(COMMA)
else break;
until false;
consume(COLON);
{ handles instruction block }
p:=gensinglenode(labeln,anweisung);
p^.labelnr:=aktcaselabel;
{ concats instruction }
instruc:=gennode(anwein,instruc,p);
if not((token=_ELSE) or (token=_OTHERWISE) or (token=_END)) then
consume(SEMICOLON);
until (token=_ELSE) or (token=_OTHERWISE) or (token=_END);
if (token=_ELSE) or (token=_OTHERWISE) then
begin
if token=_ELSE then consume(_ELSE)
else consume(_OTHERWISE);
elseblock:=anweisung;
if token=SEMICOLON then consume(SEMICOLON);
end
else
elseblock:=nil;
consume(_END);
code:=gencasenode(caseexpr,instruc,wurzel);
code^.elseblock:=elseblock;
{ true, if any case label uses ranges }
code^.ranges:=ranges;
case_anweisung:=code;
end;
function repeat_anweisung : ptree;
var
first,last,p_e : ptree;
begin
consume(_REPEAT);
first:=nil;
while token<>_UNTIL do
begin
if first=nil then
begin
last:=gennode(anwein,nil,anweisung);
first:=last;
end
else
begin
last^.left:=gennode(anwein,nil,anweisung);
last:=last^.left;
end;
if token<>SEMICOLON then
break
else
consume(SEMICOLON);
while token=SEMICOLON do
consume(SEMICOLON);
end;
consume(_UNTIL);
first:=gensinglenode(blockn,first);
p_e:=expr;
repeat_anweisung:=genloopnode(repeatn,p_e,first,nil,false);
end;
function while_anweisung : ptree;
var
p_e,p_a : ptree;
begin
consume(_WHILE);
p_e:=expr;
consume(_DO);
if token<>SEMICOLON then
p_a:=anweisung;
while_anweisung:=genloopnode(whilen,p_e,p_a,nil,false);
end;
function for_anweisung : ptree;
var
p_e,tovalue,p_a : ptree;
backward : boolean;
begin
{ Anweisung parsen }
consume(_FOR);
p_e:=expr;
if token=_DOWNTO then
begin
consume(_DOWNTO);
backward:=true;
end
else
begin
consume(_TO);
backward:=false;
end;
tovalue:=expr;
consume(_DO);
{ ...nun die Anweisungen: }
if token<>SEMICOLON then
p_a:=anweisung
else
p_a:=nil;
for_anweisung:=genloopnode(forn,p_e,tovalue,p_a,backward);
end;
function _with_anweisung : ptree;
var
hp,p : ptree;
ref : treferenz;
withsymtable,symtab : psymtable;
oldaddr : longint;
begin
p:=expr;
do_firstpass(p);
case p^.resulttype^.deftype of
classdef : begin
symtab:=pclassdef(p^.resulttype)^.publicsyms;
end;
recorddef : begin
symtab:=precdef(p^.resulttype)^.symtable;
end;
else begin
error(false_with_expr);
if token=COMMA then
begin
consume(COMMA);
{$ifdef tp}
hp:=_with_anweisung;
{$else}
hp:=_with_anweisung();
{$endif}
end
else
begin
consume(_DO);
if token<>SEMICOLON then
anweisung;
end;
exit;
end;
end;
do_secondpass(p);
aktproccode.concatlist(@exprasmlist);
{ Adresse sichern }
gettempofsizereferenz(4,ref);
aktproccode.concat(gennasmrec(LEA,S_L,
getreferenzstring(p^.location.referenz)+',%edi'));
aktproccode.concat(gennasmrec(MOV,S_L,
'%edi,'+getreferenzstring(ref)));
withsymtable:=new(psymtable,init(symtable.withsymtable));
withsymtable^.wurzel:=symtab^.wurzel;
withsymtable^.next:=symtablestack;
{ datasize hat eine geänderte Bedeutung }
withsymtable^.datasize:=ref.offset;
symtablestack:=withsymtable;
if token=COMMA then
begin
consume(COMMA);
{$ifdef tp}
hp:=_with_anweisung;
{$else}
hp:=_with_anweisung();
{$endif}
end
else
begin
consume(_DO);
if token<>SEMICOLON then
anweisung;
end;
symtablestack:=symtablestack^.next;
withsymtable^.wurzel:=nil;
dispose(withsymtable,done);
end;
procedure with_anweisung;
begin
consume(_WITH);
_with_anweisung;
end;
procedure throw_anweisung;
begin
{
if not(procinfo.exceptions) then
fatalerror(exceptions_not_allowed);
consume(_THROW);
consume(ID);
}
end;
procedure try_anweisung;
begin
if not(procinfo.exceptions) then
fatalerror(exceptions_not_allowed);
consume(_TRY);
anweisung;
repeat
consume(_ON);
consume(ID);
consume(_DO);
anweisung;
until token<>_ON;
end;
function exit_anweisung : ptree;
var
p : ptree;
begin
consume(_EXIT);
if token=LKLAMMER then
begin
consume(LKLAMMER);
p:=expr;
consume(RKLAMMER);
if procinfo.retdef=pdef(voiddef) then
error(void_function);
end
else
p:=nil;
exit_anweisung:=gensinglenode(exitn,p);
end;
function _asm_anweisung : ptree;
begin
_asm_anweisung:=assemble;
{ Erst am Ende _ASM konsumieren, da der Scanner sonst die }
{ erste Assembleranweisung zu lesen versucht! }
consume(_ASM);
{ (END ist gelesen) }
if token=LECKKLAMMER then
begin
{ explizite Angabe der modifizierten Register moeglich }
consume(LECKKLAMMER);
if token<>RECKKLAMMER then
repeat
pattern:=upper(pattern);
if pattern='EAX' then
usedinproc:=usedinproc or ($80 shr byte(R_EAX))
else if pattern='EBX' then
usedinproc:=usedinproc or ($80 shr byte(R_EBX))
else if pattern='ECX' then
usedinproc:=usedinproc or ($80 shr byte(R_ECX))
else if pattern='EDX' then
usedinproc:=usedinproc or ($80 shr byte(R_EDX))
else if pattern='ESI' then
usedinproc:=usedinproc or ($80 shr byte(R_ESI))
else if pattern='EDI' then
usedinproc:=usedinproc or ($80 shr byte(R_EDI))
else consume(RECKKLAMMER);
consume(CSTRING);
if token=COMMA then consume(COMMA)
else break;
until false;
consume(RECKKLAMMER);
end
else usedinproc:=$ff;
end;
function parse_paras(_colon : boolean) : ptree;
var
p1,p2 : ptree;
begin
if token=RKLAMMER then
begin
parse_paras:=nil;
exit;
end;
p2:=nil;
while true do
begin
p1:=expr;
p2:=gencallparanode(p1,p2);
{ blöde Krückensyntax: str(l:5,s); }
if _colon and (token=COLON) then
begin
consume(COLON);
p1:=expr;
p2:=gencallparanode(p1,p2);
p2^.is_colon_para:=true;
if token=COLON then
begin
consume(COLON);
p1:=expr;
p2:=gencallparanode(p1,p2);
p2^.is_colon_para:=true;
end
end;
if token=COMMA then
consume(COMMA)
else
break;
end;
parse_paras:=p2;
end;
function anweisung_syssym(l : longint;var pd : pdef) : ptree;
var
p1,p2 : ptree;
paras : ptree;
begin
case l of
in_typeof_x : begin
consume(LKLAMMER);
p1:=expr;
consume(RKLAMMER);
pd:=voidpointerdef;
if p1^.treetype=typen then
begin
{!!!!!}
internalerror(100)
end
else
begin
do_firstpass(p1);
if p1^.resulttype^.deftype=classdef then
anweisung_syssym:=geninlinenode(in_typeof_x,p1)
else
error(type_mismatch);
end;
end;
in_sizeof_x : begin
consume(LKLAMMER);
p1:=expr;
consume(RKLAMMER);
pd:=s32bitdef;
if p1^.treetype=typen then
anweisung_syssym:=genordinalconstnode(
p1^.resulttype^.size,pd)
else
begin
do_firstpass(p1);
if p1^.resulttype^.deftype<>classdef then
begin
anweisung_syssym:=genordinalconstnode(
p1^.resulttype^.size,pd)
end
else
begin
anweisung_syssym:=geninlinenode(in_sizeof_x,p1);
end;
end;
end;
in_assigned_x : begin
consume(LKLAMMER);
p1:=expr;
do_firstpass(p1);
case p1^.resulttype^.deftype of
pointerdef,procvardef : ;
else error(no_para_match);
end;
p2:=gencallparanode(p1,nil);
p2:=geninlinenode(in_assigned_x,p2);
consume(RKLAMMER);
pd:=booldef;
anweisung_syssym:=p2;
end;
in_ofs_x : begin
consume(RKLAMMER);
p1:=expr;
p1:=gensinglenode(addrn,p1);
do_firstpass(p1);
pd:=p1^.resulttype;
consume(LKLAMMER);
anweisung_syssym:=p1;
end;
in_concat_x : begin
consume(LKLAMMER);
p2:=nil;
while true do
begin
p1:=expr;
do_firstpass(p1);
if not((p1^.resulttype^.deftype=stringdef) or
((p1^.resulttype^.deftype=grunddef) and
(pgrunddef(p1^.resulttype)^.typ=uchar)
)
) then error(no_para_match);
if p2<>nil then
p2:=gennode(addn,p2,p1)
else p2:=p1;
if token=COMMA then
consume(COMMA)
else break;
end;
consume(RKLAMMER);
pd:=cstringdef;
anweisung_syssym:=p2;
end;
in_read_x,
in_readln_x : begin
if token=LKLAMMER then
begin
consume(LKLAMMER);
paras:=parse_paras(false);
consume(RKLAMMER);
end
else
paras:=nil;
pd:=voiddef;
anweisung_syssym:=geninlinenode(l,paras);
end;
in_write_x,
in_writeln_x : begin
if token=LKLAMMER then
begin
consume(LKLAMMER);
paras:=parse_paras(true);
consume(RKLAMMER);
end
else
paras:=nil;
pd:=voiddef;
anweisung_syssym:=geninlinenode(l,paras);
end;
in_str_x_string : begin
consume(LKLAMMER);
paras:=parse_paras(true);
consume(RKLAMMER);
anweisung_syssym:=geninlinenode(l,paras);
pd:=voiddef;
end;
else internalerror(15);
end;
end;
function factor(getaddr : boolean) : ptree;forward;
function new_dispose_anweisung : ptree;
var
p,p2 : ptree;
ht : ttoken;
asmrec : pasmrec;
destrukname : stringid;
sym : psym;
classh : pclassdef;
pd : pdef;
begin
ht:=token;
if token=_NEW then consume(_NEW)
else consume(_DISPOSE);
consume(LKLAMMER);
p:=expr;
{ calc return type }
cleartempgen;
do_firstpass(p);
if (token=COMMA) and (ht=_DISPOSE) then
begin
{ extended syntax of dispose }
{ new is handled in factor }
consume(COMMA);
{ destructors have no parameters }
destrukname:=pattern;
consume(ID);
pd:=p^.resulttype;
if pd^.deftype<>pointerdef then
begin
error(pointer_expect);
p:=factor(false);
consume(RKLAMMER);
exit;
end;
if ppointerdef(pd)^.definition^.deftype<>classdef then
begin
error(pointer_to_class_expect);
new_dispose_anweisung:=factor(false);
while token<>RKLAMMER do
consume(token);
consume(RKLAMMER);
exit;
end;
classh:=pclassdef(ppointerdef(pd)^.definition);
sym:=nil;
while assigned(classh) do
begin
sym:=classh^.publicsyms^.search(pattern);
srsymtable:=classh^.publicsyms;
if assigned(sym) then
break;
classh:=classh^.childof;
end;
if (sym^.typ<>procsym) then
begin
error(expr_have_to_be_destructor_call);
new_dispose_anweisung:=genzeronode(errorn);
end
else
begin
p2:=gensinglenode(hdisposen,p);
p2:=genmethodcallnode(pprocsym(sym),srsymtable,p2);
{ we need the real called method }
cleartempgen;
do_firstpass(p2);
if (p2^.procdefinition^.options and podestructor)=0 then
error(expr_have_to_be_destructor_call);
new_dispose_anweisung:=p2;
end;
end
else
begin
if ppointerdef(p^.resulttype)^.definition^.deftype=classdef then
warning(take_extended_syntax);
case ht of
_NEW : new_dispose_anweisung:=gensinglenode(simplenewn,p);
_DISPOSE : new_dispose_anweisung:=gensinglenode(
simpledisposen,p);
end;
end;
consume(RKLAMMER);
end;
function anweisung : ptree;
var
p : ptree;
code : ptree;
labelnr : longint;
label
ready;
begin
case token of
_GOTO : begin
if not(cs_support_goto in aktswitches )
then error(goto_label_not_support);
consume(_GOTO);
if (token<>INTCONST) and (token<>ID) then
begin
error(label_not_found);
code:=genzeronode(errorn);
end
else
begin
getsym(pattern,true);
consume(token);
if srsym^.typ<>labelsym then
begin
error(id_is_no_label_id);
code:=genzeronode(errorn);
end
else
code:=genlabelnode(goton,
plabelsym(srsym)^.number);
end;
end;
_BEGIN : code:=befehlsblock;
_IF : code:=if_anweisung;
_CASE : code:=case_anweisung;
_REPEAT : code:=repeat_anweisung;
_WHILE : code:=while_anweisung;
_FOR : code:=for_anweisung;
_NEW,_DISPOSE : code:=new_dispose_anweisung;
{!!!!!
_WITH : with_anweisung;
}
{!!!!!
_TRY : try_anweisung;
}
{!!!!!
_THROW : throw_anweisung;
}
SEMICOLON : code:=genzeronode(niln);
_CONTINUE : begin
consume(_CONTINUE);
code:=genzeronode(continuen);
end;
{!!!!!
_FAIL : begin
internalerror(100);
if (aktprocsym^.definition^.options and poconstructor)=0 then
error(fail_only_in_constructor);
consume(_FAIL);
if procinfo.exceptions then
aktproccode.concat(gennasmrec(CALL,S_NO,'HELP_DESTRUCTOR_E'))
else
aktproccode.concat(gennasmrec(CALL,S_NO,'HELP_DESTRUCTOR_NE'));
aktproccode.concat(genlasmrec(JMP,aktexitlabel));
end;
}
_BREAK : begin
consume(_BREAK);
code:=genzeronode(breakn);
end;
_EXIT : code:=exit_anweisung;
_ASM : code:=_asm_anweisung;
else
begin
if (token=INTCONST) or (token=ID) then
begin
getsym(pattern,true);
if srsym^.typ=labelsym then
begin
consume(token);
consume(COLON);
if plabelsym(srsym)^.defined then
error(label_already_defined);
plabelsym(srsym)^.defined:=true;
{ anweisung modifies srsym }
labelnr:=plabelsym(srsym)^.number;
{ the pointer to the following instruction }
{ isn't a very clean way }
{$ifdef tp}
code:=gensinglenode(labeln,anweisung);
{$else}
{ else FPKPascal thinks this is the return value }
{ | }
{ v }
code:=gensinglenode(labeln,anweisung());
{$endif}
code^.labelnr:=labelnr;
{ sorry, but there is a jump the easiest way }
goto ready;
end;
end;
p:=expr;
if (aktexprlevel<9) and (p^.treetype<>calln)
and (p^.treetype<>assignn) and (p^.treetype<>inlinen) then
error(error_in_expression);
code:=p;
end;
end;
ready:
anweisung:=code;
end;
function befehlsblock : ptree;
var
first,last : ptree;
begin
first:=nil;
consume(_BEGIN);
while token<>_END do
begin
if first=nil then
begin
last:=gennode(anwein,nil,anweisung);
first:=last;
end
else
begin
last^.left:=gennode(anwein,nil,anweisung);
last:=last^.left;
end;
if token=_END then
break
else
begin
{ falls kein Semicolon, dann Fehler und überlesen }
if token<>SEMICOLON then
begin
consume(SEMICOLON);
while token<>SEMICOLON do
consume(token);
end;
consume(SEMICOLON);
end;
while token=SEMICOLON do
consume(SEMICOLON);
end;
consume(_END);
first:=gensinglenode(blockn,first);
befehlsblock:=first;
end;
procedure formal_parameter_list;
{ hier durchgeführte Änderungen müssen meist auch in }
{ handle_procvar druchgeführt werden }
var
sc : pstringcontainer;
s : string;
p : pdef;
ref : boolean;
vs : pvarsym;
hs1,hs2 : string;
varspez : tvarspez;
begin
consume(LKLAMMER);
inc(testaktobject);
repeat
if token=_VAR then
begin
consume(_VAR);
varspez:=vs_var;
end
else if token=_CONST then
begin
consume(_CONST);
varspez:=vs_const;
end
else varspez:=vs_value;
sc:=idlist;
if token=COLON then
begin
consume(COLON);
p:=single_type(hs1);
end
else
begin
hs1:='$$$';
p:=new(pformaldef,init);
end;
s:=sc^.get;
hs2:=aktprocsym^.definition^.mangledname;
while s<>'' do
begin
aktprocsym^.definition^.concatdef(p,varspez);
hs2:=hs2+'$'+hs1;
vs:=new(pvarsym,init(s,p));
vs^.varspez:=varspez;
aktprocsym^.definition^.parast^.insert(vs);
s:=sc^.get;
end;
dispose(sc,done);
aktprocsym^.definition^.setmangledname(hs2);
if token=SEMICOLON then consume(SEMICOLON)
else break;
until false;
dec(testaktobject);
consume(RKLAMMER);
end;
{ enthält den richtigen Namen der Prozedur, der nicht }
{ ge"upcased" wurde }
var
realname : stringid;
procedure _proc_head(options : word);
var
sp : stringid;
pd : pprocdef;
paramoffset : longint;
hsymtab : psymtable;
sym : psym;
hs : string;
begin
sp:=pattern;
realname:=orgpattern;
consume(ID);
if (token=POINT) and not(parse_only) then
begin
consume(POINT);
getsym(sp,true);
sym:=srsym;
if (sym^.typ<>typesym) or
(ptypesym(sym)^.definition^.deftype<>classdef) then
fatalerror(object_type_expect);
sp:=pattern;
realname:=orgpattern;
consume(ID);
procinfo._class:=pclassdef(ptypesym(sym)^.definition);
aktprocsym:=pprocsym(procinfo._class^.publicsyms^.search(sp));
{ wird unten provisorisch behoben }
if aktprocsym=nil then
error(method_id_expect);
end
else
begin
if not(parse_only) and
((options and (poconstructor or podestructor))<>0) then
error(cons_always_obj);
aktprocsym:=pprocsym(symtablestack^.search(sp));
hs:=procprefix+'_'+sp;
if not(parse_only) then
begin
{ hier haben wir nicht nur einen Header }
procinfo._class:=nil;
hsymtab:=symtablestack;
if (aktprocsym=nil) then
begin
while (assigned(hsymtab)) and (hsymtab^.symtabletype<>globalsymtable) do
hsymtab:=hsymtab^.next;
if assigned(hsymtab) and (hsymtab^.symtabletype=globalsymtable) then
begin
aktprocsym:=pprocsym(hsymtab^.search(sp));
{ if symbol found => is global }
if assigned(aktprocsym) then
procinfo.globalsymbol:=true;
end;
end;
end;
end;
if procinfo._class<>nil then
hs:=procprefix+'_$$_'+procinfo._class^.name^+'_'+sp;
if aktprocsym=nil then
begin
aktprocsym:=new(pprocsym,init(sp));
symtablestack^.insert(aktprocsym);
end;
if aktprocsym^.typ<>procsym then fatalerror(overloaded_no_proc);
pd:=new(pprocdef,init);
{ Übergebene Optionen setzen }
pd^.options:=pd^.options or options;
{ Offset der Parameter berechnen }
paramoffset:=8;
{ Sollten Exceptions eingeschaltet sein, dann Exceptionflag setzen }
if cs_genexceptcode in aktswitches then
begin
pd^.options:=pd^.options or poexceptions;
inc(paramoffset,4);
end;
procinfo.exceptions:=cs_genexceptcode in aktswitches ;
{ Framepointeroffset berechnen }
if lexlevel>0 then
begin
procinfo.framepointer:=paramoffset;
inc(paramoffset,4);
end;
if ((pd^.options and poconstructor)<>0) or
((pd^.options and podestructor)<>0) then
begin
procinfo.VMT_table:=paramoffset;
inc(paramoffset,4);
end;
{ Selfpointeroffset }
if assigned(procinfo._class) then
begin
procinfo.ESI_offset:=paramoffset;
inc(paramoffset,4);
end;
procinfo.call_offset:=paramoffset;
pd^.parast^.datasize:=0;
pd^.nextoverloaded:=aktprocsym^.definition;
aktprocsym^.definition:=pd;
aktprocsym^.definition^.setmangledname(hs);
if not(parse_only) then
procprefix:=hs;
if token=LKLAMMER then formal_parameter_list;
end;
procedure proc_head;
var
{ Nur ein Hilfsstring, der den Namen des Rückgabetypes einer }
{ Funktion aufnimmt }
hs : string;
begin
if token=_FUNCTION then
begin
consume(_FUNCTION);
_proc_head(0);
if token<>COLON then
begin
consume(COLON);
while token<>SEMICOLON do
consume(token);
end
else
begin
consume(COLON);
aktprocsym^.definition^.retdef:=single_type(hs);
end;
end
else if token=_PROCEDURE then
begin
consume(_PROCEDURE);
_proc_head(0);
aktprocsym^.definition^.retdef:=voiddef;
end
else if token=_CONSTRUCTOR then
begin
consume(_CONSTRUCTOR);
_proc_head(poconstructor);
{ kann auch als bool'sche Funktion betrachtet werden }
aktprocsym^.definition^.retdef:=
new(pgrunddef,init(bool8bit,0,1));
end
else if token=_DESTRUCTOR then
begin
consume(_DESTRUCTOR);
_proc_head(podestructor);
aktprocsym^.definition^.retdef:=voiddef;
end
else if token=_OPERATOR then
begin
internalerror(110);
consume(_OPERATOR);
if not(token in [PLUS]) then
begin
error(operator_not_overloaded);
{!!!!!!!}
end;
consume(token);
if token<>COLON then
begin
consume(COLON);
while token<>SEMICOLON do
consume(token);
end
else
begin
consume(COLON);
{!!!!!!!}
aktprocsym^.definition^.retdef:=single_type(hs);
end;
end;
consume(SEMICOLON);
end;
procedure unter_dec;
var
oldprocsym : pprocsym;
oldexceptlabel,oldexitlabel,oldexit2label : longint;
_class : pclassdef;
oldprocinfo : tprocinfo;
oldconstsymtable : psymtable;
{ für geschachtelte Unterprogramme eindeutige Namen erzeugen }
oldprefix,hs : string;
{ Größe des lokalen Stackframes }
stackframe : longint;
{ Anzahl der Bytes die mit RET entfernt werden müssen }
parasize : longint;
{ true wenn kein Stackframe erforderlich ist }
nostackframe : boolean;
hd,pd : pprocdef;
names : tstringcontainer;
{ wird auf true gesetzt, wenn Symbole exportiert werden sollen }
make_global : boolean;
{ wird auf true gesetzt, wenn ein Unterprogramm schon }
{ "forward" deklariert wurde }
was_forward : boolean;
{ wird nur in Konstruktoren angesprungen, wenn eine Speicheran- }
{ forderung für die Instanz fehlschlägt }
quickexitlabel : longint;
hl : longint;
p : ptree;
{ Code für das Unterprogramm in Treeform }
code : ptree;
label
restore;
begin
oldprocsym:=aktprocsym;
oldprefix:=procprefix;
oldconstsymtable:=constsymtable;
oldprocinfo:=procinfo;
{ symbol isn't global }
procinfo.globalsymbol:=false;
proc_head;
{ uses no asm }
procinfo.uses_asm:=false;
{ Returntyp setzen }
procinfo.retdef:=aktprocsym^.definition^.retdef;
{ Vielleicht ein Zeiger für einen Returntyp }
if (procinfo.retdef^.deftype=arraydef) or
(procinfo.retdef^.deftype=stringdef) or
(procinfo.retdef^.deftype=classdef) or
(procinfo.retdef^.deftype=recorddef) or
(procinfo.retdef^.deftype=setdef) then
begin
procinfo.retoffset:=procinfo.call_offset;
inc(procinfo.call_offset,4);
end;
{ spart Speicherplatz: }
{ param_offset muß gespeichert werden, da geschachtelte Unterprogramme }
{ procinfo ändern }
aktprocsym^.definition^.parast^.name:=pstring(procinfo.call_offset);
{ Header ist geparst }
if parse_only then
goto restore;
{ wird nur wegen EXPORT hier schon durchgeführt: }
names.init;
make_global:=false;
procinfo.exported:=false;
case token of
_FAR : begin
consume(_FAR);
warning(far_ignored);
consume(SEMICOLON);
end;
_NEAR : begin
consume(_NEAR);
warning(near_ignored);
consume(SEMICOLON);
end;
_INTERRUPT : begin
consume(_INTERRUPT);
warning(interrupt_ignored);
consume(SEMICOLON);
end;
_EXPORT : begin
consume(_EXPORT);
names.insert(realname);
make_global:=true;
procinfo.exported:=true;
consume(SEMICOLON);
if gendeffile then
writeln(defdatei,#9+aktprocsym^.definition^.mangledname);
aktprocsym^.definition^.options:=
aktprocsym^.definition^.options or poexports;
if procinfo._class<>nil then
error(methods_dont_be_export);
if lexlevel<>0 then
error(dont_nest_export);
{ zwar dürfen Exceptions in exportierten Unterprogrammen }
{ eingeschaltet sein, jedoch darf natürlich keine }
{ Exceptionhandlingadresse auf dem Stack erwartet werden }
if procinfo.exceptions then
begin
{ also call_offset erniedrigen: }
dec(procinfo.call_offset,4);
{ call_offset neu zuweisen (s.o.): }
aktprocsym^.definition^.parast^.name:=pstring(procinfo.call_offset);
{ auch retoffset, nur falls exportierte Funktionen }
{ jemals strukturierte Typen zurückgeben, unwahrscheinlich }
dec(procinfo.retoffset,4);
end;
end;
_INLINE : error(inline_not_supported);
end;
case token of
_FORWARD : begin
consume(_FORWARD);
consume(SEMICOLON);
end;
else
begin
{ searchs idendical definitions }
{ if there is a forward, then kill this }
was_forward:=false;
pd:=aktprocsym^.definition;
while (assigned(pd)) and (assigned(pd^.nextoverloaded)) do
begin
if equal_paras(aktprocsym^.definition^.para1,pd^.nextoverloaded^.para1) then
begin
if pd^.nextoverloaded^.forwarddef then
{ sollte das eine "forward"-Definition sein, }
{ dann eine halbe Leiche daraus machen }
{ da die Definition noch in einer Symbol- }
{ tabelle zum Loeschen eingetragen ist, }
{ kein dispose! }
begin
{ and not(virtual), weil virtual nicht angegeben werden muß }
if ((pd^.nextoverloaded^.options and not(povirtualmethod))
<>aktprocsym^.definition^.options) or
not(is_equal(pd^.nextoverloaded^.retdef,aktprocsym^.definition^.retdef)) then
error(header_dont_match);
hd:=pd^.nextoverloaded;
{ erst Name ändern: }
hd^.setmangledname(aktprocsym^.definition^.mangledname);
{ Test! }
hd^.parast^.name:=aktprocsym^.definition^.parast^.name;
{ pd^.nextoverloaded aus der Liste an den Anfang }
{ und aktprocsym^.definition aushaengen }
pd^.nextoverloaded:=pd^.nextoverloaded^.nextoverloaded;
hd^.nextoverloaded:=aktprocsym^.definition^.nextoverloaded;
aktprocsym^.definition:=hd;
was_forward:=true;
end
else error(same_parameters);
end;
pd:=pd^.nextoverloaded;
end;
if assigned(procinfo._class) and not(was_forward) then
error(header_dont_match_any_member);
if not(was_forward) and procinfo.globalsymbol then
error(overloaded_must_be_all_global);
{$ifdef EXTDEBUG}
writeln('Unterprogramm: ',aktprocsym^.name,' (',
aktprocsym^.definition^.mangledname,')');
{$endif}
{ Funktionsattribute lesen }
if token=LECKKLAMMER then
begin
consume(LECKKLAMMER);
repeat
if token=_PUBLIC then
begin
consume(_PUBLIC);
make_global:=true;
end
else if token=ID then
begin
if pattern='ALIAS' then
begin
consume(ID);
consume(COLON);
names.insert(pattern);
if token=CCHAR then consume(CCHAR)
else consume(CSTRING);
end
else if pattern='INTERNPROC' then
begin
consume(ID);
consume(COLON);
p:=expr;
do_firstpass(p);
if p^.treetype<>ordconstn then
fatalerror(error_in_expression);
aktprocsym^.definition^.extnumber:=p^.value;
aktprocsym^.definition^.options:=
aktprocsym^.definition^.options or pointernproc;
disposetree(p);
consume(RECKKLAMMER);
consume(SEMICOLON);
{ definiert }
aktprocsym^.definition^.forwarddef:=false;
goto restore;
end
else if pattern='SYSTEM' then
begin
consume(ID);
aktprocsym^.definition^.options:=
aktprocsym^.definition^.options or poclearstack;
{ Vermutlich keine Register retten }
{ aktprocsym^.definition^.usedregisters:=$ff; }
aktprocsym^.definition^.forwarddef:=false;
aktprocsym^.definition^.setmangledname(realname);
consume(RECKKLAMMER);
consume(SEMICOLON);
goto restore;
end
{ it does currently the same as 'SYSTEM' }
else if pattern='C' then
begin
consume(ID);
aktprocsym^.definition^.options:=
aktprocsym^.definition^.options or poclearstack;
aktprocsym^.definition^.forwarddef:=false;
aktprocsym^.definition^.setmangledname(realname);
consume(RECKKLAMMER);
consume(SEMICOLON);
goto restore;
end
else if pattern='IOCHECK' then
begin
consume(ID);
aktprocsym^.definition^.options:=
aktprocsym^.definition^.options or poiocheck;
end
end;
if token=COMMA then consume(COMMA)
else break;
until false;
consume(RECKKLAMMER);
consume(SEMICOLON);
end
else if token=_EXTERNAL then
begin
consume(_EXTERNAL);
aktprocsym^.definition^.forwarddef:=false;
if token=SEMICOLON then
consume(SEMICOLON)
else
begin
{ Funktion aus DLL }
{!!!!!!!!!!!}
end;
goto restore;
end
{ else if token=_ASSEMBLER then
begin
consume(_ASSEMBLER);
consume(SEMICOLON);
end} ;
if procinfo.exported then
aktprocsym^.definition^.options:=aktprocsym^.definition^.options or
poclearstack;
oldexitlabel:=aktexitlabel;
oldexit2label:=aktexit2label;
oldexceptlabel:=aktexceptlabel;
aktexitlabel:=getlabel;
aktexit2label:=getlabel;
aktexceptlabel:=getlabel;
{ lex. Level berechnen }
inc(lexlevel);
if lexlevel>31 then
error(too_much_lexlevel);
{ break-und continuelabel zurücksetzen, }
{ müssen aber nicht gerettet werden! }
aktbreaklabel:=0;
aktcontinuelabel:=0;
{ falls Objekt, Membersymboltabelle eintragen }
if assigned(procinfo._class) then
begin
_class:=procinfo._class;
while assigned(_class) do
begin
_class^.publicsyms^.next:=symtablestack;
symtablestack:=_class^.publicsyms;
_class:=_class^.childof;
end;
end;
{ Symboltabellen einfügen }
{ und die lex. Level eintragen }
aktprocsym^.definition^.parast^.next:=symtablestack;
symtablestack:=aktprocsym^.definition^.parast;
inc(symtablestack^.symtabletype,lexlevel);
aktprocsym^.definition^.localst^.next:=symtablestack;
symtablestack:=aktprocsym^.definition^.localst;
inc(symtablestack^.symtabletype,lexlevel);
{ hier werden die Aufzähltypen eingefügt }
constsymtable:=symtablestack;
{ temporäre Variablen zurücksetzen }
cleartempgen;
pushgened:=false;
{ keine Register bisher benutzt }
usedinproc:=0;
{ entscheidender Moment... }
code:=block;
generatecode(code);
{ the code isn't needed }
disposetree(code);
dec(lexlevel);
{ jetzt definiert }
aktprocsym^.definition^.forwarddef:=false;
aktprocsym^.definition^.usedregisters:=usedinproc;
stackframe:=gettempsize;
quickexitlabel:=0;
{ Aufruf der Konstruktorhilfsprozedur }
if (aktprocsym^.definition^.options and poconstructor)<>0 then
{ verschiedene Hilfsunterprogramme (mit und ohne Exceptions) }
if procinfo.exceptions then
begin
aktentrycode.insert(gennasmrec(CALL,S_NO,'HELP_CONSTRUCTOR_E'));
aktentrycode.insert(gennasmrec(PUSH,S_L,'$'+tolabel(aktexceptlabel)));
end
else
begin
quickexitlabel:=getlabel;
aktentrycode.insert(genlasmrec(JZ,quickexitlabel));
aktentrycode.insert(gennasmrec(CALL,S_NO,'HELP_CONSTRUCTOR_NE'));
end;
{ ESI wird immer schon vom Hauptprogramm geladen }
{ also unnötig:
if procinfo._class<>nil then
aktentrycode.insert(gennasmrec(MOV,S_L,tostr(procinfo.ESI_offset)+'(%ebp),%esi'));
}
if stackframe<>0 then
begin
if cs_littlesize in aktswitches then
aktentrycode.insert(gennasmrec(ENTER,S_L,'$'+tostr(stackframe)+',$0'))
else
begin
aktentrycode.insert(gennasmrec(SUB,S_L,'$'+tostr(stackframe)+',%esp'));
aktentrycode.insert(gennasmrec(MOV,S_L,'%esp,%ebp'));
aktentrycode.insert(gennasmrec(PUSH,S_L,'%ebp'));
end;
end
else
begin
aktentrycode.insert(gennasmrec(MOV,S_L,'%esp,%ebp'));
aktentrycode.insert(gennasmrec(PUSH,S_L,'%ebp'));
end;
names.insert(aktprocsym^.definition^.mangledname);
if (aktprocsym^.definition^.owner^.symtabletype=globalsymtable) or
((procinfo._class<>nil) and
(procinfo._class^.owner^.symtabletype=globalsymtable)) then
make_global:=true;
hs:=names.get;
while hs<>'' do
begin
aktentrycode.insert(gennasmrec(DIRECT,S_NO,hs+':'));
if make_global then
aktentrycode.insert(gennasmrec(DIRECT,S_NO,'.globl '+hs));
hs:=names.get;
end;
if not(cs_littlesize in aktswitches ) then
aktentrycode.insert(gennasmrec(A_ALIGN,S_NO,'4,0x90'));
parasize:=aktprocsym^.definition^.parast^.datasize+procinfo.call_offset-8;
if procinfo.exceptions then
begin
aktexceptcode.insert(genlasmrec(A_LABEL,aktexceptlabel));
{ Aufruf der Destruktorhilfsprozedur }
if (aktprocsym^.definition^.options and podestructor)<>0 then
aktexceptcode.concat(gennasmrec(CALL,S_NO,'HELP_DESTRUCTOR_E'));
if not(nostackframe) then
aktexceptcode.concat(gennasmrec(LEAVE,S_NO,''));
{ exportierte Routinen enden immer nur mit RET }
if procinfo.exported then
aktexceptcode.concat(gennasmrec(RET,S_NO,''))
else
begin
aktexceptcode.concat(gennasmrec(ADD,S_L,'$4,%esp'));
aktexceptcode.concat(gennasmrec(RET,S_NO,'$'+tostr(parasize-4)));
end;
end;
{ !!!! hier automatische Destruktoren einfügen }
aktexitcode.insert(genlasmrec(A_LABEL,aktexitlabel));
{ Aufruf der Desstruktorhilfsprozedur }
if (aktprocsym^.definition^.options and podestructor)<>0 then
{ verschiedene Hilfsunterprogramme }
if procinfo.exceptions then
aktexitcode.concat(gennasmrec(CALL,S_NO,'HELP_DESTRUCTOR_E'))
else aktexitcode.insert(gennasmrec(CALL,S_NO,'HELP_DESTRUCTOR_NE'));
if (aktprocsym^.definition^.options and poconstructor)=0 then
begin
if procinfo.retdef<>pdef(voiddef) then
begin
if (procinfo.retdef^.deftype=grunddef) then
begin
case pgrunddef(procinfo.retdef)^.typ of
s32bit : aktexitcode.concat(gennasmrec(MOV,S_L,tostr(procinfo.retoffset)+'(%ebp),%eax'));
u8bit,s8bit,uchar,bool8bit :
aktexitcode.concat(gennasmrec(MOV,S_B,tostr(procinfo.retoffset)+'(%ebp),%al'));
s16bit,u16bit :
aktexitcode.concat(gennasmrec(MOV,S_W,tostr(procinfo.retoffset)+'(%ebp),%ax'));
s64real :
aktexitcode.concat(gennasmrec(FLD,S_L,tostr(procinfo.retoffset)+'(%ebp)'));
end;
end
else
if (procinfo.retdef^.deftype=pointerdef) or
(procinfo.retdef^.deftype=aufzaehldef) or
(procinfo.retdef^.deftype=procvardef) then
aktexitcode.concat(gennasmrec(MOV,S_L,tostr(procinfo.retoffset)+'(%ebp),%eax'));
end
end
else
begin
{ erfolgreicher Konstruktor löscht das Zeroflag }
{ und gibt SELF in EAX zurück }
aktexitcode.concat(gennasmrec(MOV,S_L,'%esi,%eax'));
aktexitcode.concat(gennasmrec(A_OR,S_L,'%eax,%eax'));
if not(procinfo.exceptions) then
aktexitcode.concat(genlasmrec(A_LABEL,quickexitlabel));
end;
aktexitcode.concat(genlasmrec(A_LABEL,aktexit2label));
aktexitcode.concat(gennasmrec(LEAVE,S_NO,''));
{ max. 65535 Bytes Parameter wegen RET imm16 }
if parasize>65535 then
error(para_too_big);
{ jetzt noch das RET erzeugen, mit Entfernen der }
{ möglichen Catchadresse und der Parameter }
{ exportierte Routinen enden immer nur mit RET }
if (parasize=0) or procinfo.exported then
aktexitcode.concat(gennasmrec(RET,S_NO,''))
else aktexitcode.concat(gennasmrec(
RET,S_NO,'$'+tostr(parasize)));
if cs_debuginfo in aktswitches then
aktexitcode.concat(gennasmrec(STABS,S_NO,'"'+
aktprocsym^.name+'"'+',36,0,0,'+
aktprocsym^.definition^.mangledname));
aktproccode.insertlist(@aktentrycode);
aktproccode.concatlist(@aktexitcode);
aktproccode.concatlist(@aktexceptcode);
mainasmlist.concatlist(@aktproccode);
{ ... Symboltabellen entfernen }
symtablestack:=symtablestack^.next^.next;
{ ...auf unbenutzte Symbole testen }
if not(procinfo.uses_asm) then
begin
aktprocsym^.definition^.localst^.allsymbolsused;
aktprocsym^.definition^.parast^.allsymbolsused;
end;
{ die lokalen Symboltabellen dürfen gelöscht werden, }
{ nur auf die Parametersymboltablellen und insbesonders }
{ auf die Definitionen wird noch zugegriffen }
dispose(aktprocsym^.definition^.localst,done);
aktprocsym^.definition^.localst:=nil;
{ Klassenmember entfernen }
while symtablestack^.symtabletype=objectsymtable do
symtablestack:=symtablestack^.next;
aktexitlabel:=oldexit2label;
aktexit2label:=oldexitlabel;
aktexceptlabel:=oldexceptlabel;
names.done;
consume(SEMICOLON);
end;
end;
restore:
constsymtable:=oldconstsymtable;
aktprocsym:=oldprocsym;
procprefix:=oldprefix;
procinfo:=oldprocinfo;
end;
function block : ptree;
begin
repeat
case token of
_LABEL : label_dec;
_CONST : const_dec;
_TYPE : type_dec;
_VAR : var_dec;
_CONSTRUCTOR,_DESTRUCTOR,
_FUNCTION,_PROCEDURE,_OPERATOR : unter_dec;
else break;
end;
until false;
{ bei BEGIN der temporäre Variablen setzen }
if (symtablestack^.symtabletype and $8000)=localsymtable then
firsttemp:=-symtablestack^.datasize
else firsttemp:=0;
{ Platz fuer den Returnwert schaffen }
if procinfo.retdef<>pdef(voiddef) then
begin
if (procinfo.retdef^.deftype=grunddef) or
(procinfo.retdef^.deftype=pointerdef) or
(procinfo.retdef^.deftype=aufzaehldef) or
(procinfo.retdef^.deftype=procvardef) then
begin
procinfo.retoffset:=gettempofsize(procinfo.retdef^.size);
{ EAX wird auch verändert: }
usedinproc:=usedinproc or ($80 shr byte(R_EAX))
end;
end;
block:=befehlsblock;
end;
procedure loadunits;
var
st : psymtable;
s : stringid;
begin
consume(_USES);
repeat
s:=pattern;
consume(ID);
st:=readunit(s);
refsymtable^.insert(new(punitsym,init(s,st)));
if token=COMMA then consume(COMMA)
else break;
until false;
consume(SEMICOLON);
end;
procedure insertinternsyms;
begin
symtablestack^.insert(new(psyssym,init('CONCAT',in_concat_x)));
symtablestack^.insert(new(psyssym,init('WRITE',in_write_x)));
symtablestack^.insert(new(psyssym,init('WRITELN',in_writeln_x)));
symtablestack^.insert(new(psyssym,init('ASSIGNED',in_assigned_x)));
symtablestack^.insert(new(psyssym,init('READ',in_read_x)));
symtablestack^.insert(new(psyssym,init('READLN',in_readln_x)));
symtablestack^.insert(new(psyssym,init('OFS',in_ofs_x)));
symtablestack^.insert(new(psyssym,init('SIZEOF',in_sizeof_x)));
symtablestack^.insert(new(psyssym,init('TYPEOF',in_typeof_x)));
{ symtablestack^.insert(new(psyssym,init('STR',in_str_x_string))); }
end;
procedure proc_unit;
var
unitname : stringid;
p : psymtable;
code : ptree;
begin
if gendeffile then
error(def_only_in_program);
consume(_UNIT);
if (cs_compilesystem in aktswitches) and
(
not(pattern=target_info.system_unit) or
(length(pattern)>8) or
(pattern<>inputfile)
)
and (cs_check_unit_name in aktswitches) then
error(ill_unit_name);
unitname:=pattern;
consume(ID);
consume(SEMICOLON);
consume(_INTERFACE);
procprefix:='_'+unitname+'$$';
parse_only:=true;
{ jetzt die globale Symboltabelle erzeugen }
p:=new(psymtable,init(globalsymtable));
p^.name:=stringdup(unitname);
refsymtable:=p;
{ SYSTEM-Qualifier einfügen }
if not(cs_compilesystem in aktswitches) then
refsymtable^.insert(new(punitsym,init('SYSTEM',symtablestack)));
if token=_USES then loadunits;
{ ... aber hier erst einfügen }
p^.next:=symtablestack;
symtablestack:=p;
constsymtable:=symtablestack;
{ beim Uebersetzen von System einige Typen direkt einfuegen: }
if cs_compilesystem in aktswitches then
begin
voiddef:=new(pgrunddef,init(uvoid,0,0));
symtablestack^.insert(new(ptypesym,init('REAL',new(pgrunddef,init(s64real,0,0)))));
symtablestack^.insert(new(ptypesym,init('POINTER',new(ppointerdef,init(voiddef)))));
symtablestack^.insert(new(ptypesym,init('BOOLEAN',new(pgrunddef,init(bool8bit,0,1)))));
symtablestack^.insert(new(ptypesym,init('CHAR',new(pgrunddef,init(uchar,0,255)))));
symtablestack^.insert(new(ptypesym,init('TEXT',new(pfiledef,init(ft_text,nil)))));
symtablestack^.insert(new(ptypesym,init('FILE',new(pfiledef,init(ft_untyped,nil)))));
{ jetzt wurde voiddef ja geaendert }
procinfo.retdef:=voiddef;
insertinternsyms;
end;
{ ... und die Deklarationen parsen }
repeat
case token of
_CONST : const_dec;
_TYPE : type_dec;
_VAR : var_dec;
_FUNCTION,_PROCEDURE : unter_dec;
else
begin
consume(_IMPLEMENTATION);
break;
end;
end;
until false;
parse_only:=false;
{ statische Symboltabelle erzeugen }
p:=new(psymtable,init(staticsymtable));
p^.name:=stringdup(unitname);
refsymtable:=p;
{
if token=_USES then loadunits;
}
{ ... hier erst Einfügen }
p^.next:=symtablestack;
symtablestack:=p;
constsymtable:=symtablestack;
repeat
case token of
_CONST : const_dec;
_TYPE : type_dec;
_VAR : var_dec;
_FUNCTION,_PROCEDURE,
_CONSTRUCTOR,_DESTRUCTOR : unter_dec;
else break;
end;
until false;
{ temporäre Variablen zurücksetzen }
cleartempgen;
{ sonstige Einstellungen: }
aktexitlabel:=getlabel;
aktexit2label:=getlabel;
aktexceptlabel:=getlabel;
aktbreaklabel:=0;
aktcontinuelabel:=0;
pushgened:=false;
{ set some informations }
procinfo.retdef:=voiddef;
procinfo.exceptions:=true;
procinfo._class:=nil;
procinfo.uses_asm:=false;
if token=_BEGIN then
begin
{$ifdef EXTDEBUG}
writeln('Unitinitialisierungsteil');
{$endif}
usedunits.insert(unitname);
mainasmlist.concat(gennasmrec(DIRECT,S_NO,'.globl INIT$$'+unitname));
mainasmlist.concat(gennasmrec(DIRECT,S_NO,'INIT$$'+unitname+':'));
code:=befehlsblock;
generatecode(code);
if gettempsize<>0 then
aktentrycode.insert(gennasmrec(SUB,S_L,'$'+tostr(gettempsize)+',%esp'));
aktentrycode.insert(gennasmrec(MOV,S_L,'%esp,%ebp'));
aktentrycode.insert(gennasmrec(PUSH,S_L,'%ebp'));
aktexitcode.concat(genlasmrec(A_LABEL,aktexitlabel));
aktexitcode.concat(genlasmrec(A_LABEL,aktexit2label));
aktexitcode.concat(gennasmrec(LEAVE,S_NO,''));
aktexitcode.concat(gennasmrec(RET,S_NO,''));
aktexitcode.concat(genlasmrec(A_LABEL,aktexceptlabel));
aktexitcode.concat(gennasmrec(PUSH,S_L,'$LINITEXPT'));
aktexitcode.concat(gennasmrec(CALL,S_NO,'INITEXCEPTION'));
aktexitcode.concat(gennasmrec(DIRECT,S_NO,'LINITEXPT:'));
aktexitcode.concat(gennasmrec(LEAVE,S_NO,''));
aktexitcode.concat(gennasmrec(RET,S_NO,''));
aktproccode.insertlist(@aktentrycode);
aktproccode.concatlist(@aktexitcode);
aktproccode.concatlist(@aktexceptcode);
mainasmlist.concatlist(@aktproccode);
end
else
begin
consume(_END);
{ Units mit vorangestellter Tilde werden nicht initialisiert }
usedunits.insert('~'+unitname);
end;
consume(POINT);
{ Größe der statischen Daten: }
datasize:=symtablestack^.datasize;
{ unsed static symbols ? }
symtablestack^.allsymbolsused;
{ dels static symbols }
dellexlevel;
{ alle im Implementationsteil aufgeführten Units entfernen }
while symtablestack^.symtabletype<>globalsymtable do
dellexlevel;
if codegeneration then
writeunitas(inputdir+unitname+'.PPU',symtablestack);
inc(datasize,symtablestack^.datasize);
dellexlevel;
end;
function findfile(const s : string) : string;
var
found : boolean;
dirinfo : searchrec;
envstring : string;
f : file;
begin
findfirst(s+target_info.objext,anyfile,dirinfo);
if doserror=0 then
begin
findfile:='';
exit;
end;
findfirst(unitpath+s+target_info.objext,anyfile,dirinfo);
if doserror=0 then
begin
findfile:=unitpath;
exit;
end;
findfile:=search(s+target_info.objext,getenv(target_info.unit_env),found);
if found then
exit;
findfile:=search(s+target_info.objext,getenv(target_info.lib_env),found);
if found then
exit;
findfile:='';
end;
procedure proc_program;
var
st : psymtable;
programname : stringid;
s : stringid;
unitinits : tasmlist;
code : ptree;
begin
{ bei -Us Fehler erzeugen }
if cs_compilesystem in aktswitches then
consume(_UNIT);
parse_only:=false;
programname:='';
if token=_PROGRAM then
begin
consume(_PROGRAM);
programname:=pattern;
consume(ID);
if token=LKLAMMER then
begin
consume(LKLAMMER);
idlist;
consume(RKLAMMER);
end;
consume(SEMICOLON);
end;
{ Nach den Units Hauptsymboltabelle einfügen }
st:=new(psymtable,init(staticsymtable));
refsymtable:=st;
refsymtable^.insert(new(punitsym,init('SYSTEM',symtablestack)));
if token=_USES then loadunits;
st^.next:=symtablestack;
symtablestack:=st;
if programname<>'' then
symtablestack^.insert(new(pprogramsym,init(programname)));
{ ...und als constsymtable setzen }
constsymtable:=st;
{ set some informations about the main program }
procinfo.retdef:=voiddef;
procinfo.exceptions:=true;
procinfo._class:=nil;
procinfo.uses_asm:=false;
procprefix:='';
aktbreaklabel:=0;
aktcontinuelabel:=0;
aktexitlabel:=getlabel;
aktexit2label:=getlabel;
aktexceptlabel:=getlabel;
{ temporäre Variablen zurücksetzten }
cleartempgen;
pushgened:=false;
if target_info.target=target_DOS then
begin
assign(linkresponse,inputdir+'LINK.RES');
rewrite(linkresponse);
writeln(linkresponse,'-o '+inputdir+inputfile);
writeln(linkresponse,findfile('PRT0')+'PRT0.o');
writeln(linkresponse,inputdir+inputfile+'.o');
end;
if target_info.target=target_OS2 then
begin
assign(linkresponse,inputdir+'LINK.RES');
rewrite(linkresponse);
writeln(linkresponse,'-o '+inputdir+inputfile);
writeln(linkresponse,inputdir+inputfile+'.obj');
if gendeffile then
writeln(linkresponse,inputdir+inputfile+'.def');
end;
unitinits.init;
s:=usedunits.get;
while s<>'' do
begin
if s[1]<>'~' then
unitinits.concat(gennasmrec(CALL,S_NO,'INIT$$'+s))
else
delete(s,1,1);
if (target_info.target=target_DOS) or (target_info.target=target_OS2) then
writeln(linkresponse,findfile(s)+s+target_info.objext);
s:=usedunits.get;
end;
code:=block;
{$ifdef EXTDEBUG}
writeln('Hauptprogramm');
{$endif}
generatecode(code);
aktentrycode.insertlist(@unitinits);
if gettempsize<>0 then
aktentrycode.insert(gennasmrec(SUB,S_L,'$'+tostr(gettempsize)+',%esp'));
aktentrycode.insert(gennasmrec(MOV,S_L,'%esp,%ebp'));
aktentrycode.insert(gennasmrec(PUSH,S_L,'%ebp'));
if target_info.target=target_DOS then
begin
aktentrycode.insert(gennasmrec(DIRECT,S_NO,'PASCALMAIN:'));
aktentrycode.insert(gennasmrec(DIRECT,S_NO,'.globl'#9'PASCALMAIN'));
end;
{ the main function for Linux is in PRT0L.O }
if (target_info.target<>target_LINUX) then
begin
aktentrycode.insert(gennasmrec(DIRECT,S_NO,'_main:'));
aktentrycode.insert(gennasmrec(DIRECT,S_NO,'.globl'#9'_main'));
end;
aktexceptcode.concat(genlasmrec(A_LABEL,aktexceptlabel));
aktexceptcode.concat(gennasmrec(CALL,S_NO,'__EXIT'));
aktexceptcode.concat(gennasmrec(LEAVE,S_NO,''));
if target_info.target=target_DOS then
begin
aktexceptcode.concat(gennasmrec(ADD,S_L,'$4,%esp'));
aktexceptcode.concat(gennasmrec(RET,S_NO,''));
end
else if target_info.target=target_OS2 then
begin
{!!!!!! Hier Exceptions für OS/2 abfangen }
aktexceptcode.concat(gennasmrec(RET,S_NO,''));
end
else if target_info.target=target_LINUX then
begin
{!!!!!! Hier Exceptions für Linux abfangen }
aktexceptcode.concat(gennasmrec(RET,S_NO,''));
end
else if target_info.target=target_WIN32 then
begin
{!!!!!! Hier Exceptions für Win32 abfangen }
aktexceptcode.concat(gennasmrec(RET,S_NO,''));
end;
aktexitcode.concat(genlasmrec(A_LABEL,aktexitlabel));
aktexitcode.concat(genlasmrec(A_LABEL,aktexit2label));
aktexitcode.concat(gennasmrec(CALL,S_NO,'__EXIT'));
aktexitcode.concat(gennasmrec(LEAVE,S_NO,''));
if target_info.target=target_DOS then
aktexitcode.concat(gennasmrec(RET,S_NO,'$4'))
else if target_info.target=target_OS2 then
aktexitcode.concat(gennasmrec(RET,S_NO,''))
{ !!!!!!!!!!!! Abändern: }
else if target_info.target=target_LINUX then
aktexitcode.concat(gennasmrec(RET,S_NO,''))
else if target_info.target=target_WIN32 then
aktexitcode.concat(gennasmrec(RET,S_NO,''));
aktproccode.insertlist(@aktentrycode);
aktproccode.concatlist(@aktexitcode);
aktproccode.concatlist(@aktexceptcode);
mainasmlist.concatlist(@aktproccode);
if (target_info.target=target_DOS) or
(target_info.target=target_LINUX) then
begin
{ heap of DOS and LINUX are in the data segment }
datasegment.concat(gennasmrec(
A_GLOBAL,S_NO,'HEAP,'+tostr(heapsize)));
end;
constsegment.concat(gennasmrec(
DIRECT,S_NO,'.globl HEAPSIZE'));
constsegment.concat(gennasmrec(
DIRECT,S_NO,'HEAPSIZE:'));
constsegment.concat(gennasmrec(
A_LONG,S_NO,tostr(heapsize)));
datasize:=symtablestack^.datasize;
symtablestack^.allsymbolsused;
while assigned(symtablestack) do
dellexlevel;
consume(POINT);
end;
function factor(getaddr : boolean) : ptree;
var
l : longint;
p1,p2,p3 : ptree;
code : word;
pd,pd2 : pdef;
nochmal : boolean;
sym : pvarsym;
classh : pclassdef;
d : double;
constset : pconstset;
{ liest die Parameter für einen Unterprogrammaufruf }
{ eigentlich ein Makro }
procedure do_proc_call;
begin
{ soll nur die Adresse eines }
{ Unterprogramms festgestellt werden ? }
if not(getaddr) then
begin
if token=LKLAMMER then
begin
consume(LKLAMMER);
p1^.left:=parse_paras(false);
consume(RKLAMMER);
end
else p1^.left:=nil;
{ Schon den einen ersten Durchlauf }
{ durchführen, da wir den Returntyp }
{ brauchen }
do_firstpass(p1);
pd:=p1^.resulttype;
end
else
begin
p1^.left:=nil;
{ vergessen wir pd }
pd:=nil;
{ keine Postfixoperatoren }
nochmal:=false;
end;
end;
{ erzeugt den Knoten für ein Klassenelement, }
{ wobei sym auf das Symbol und srsymtable }
{ auf die entsprechende Symboltabelle zeigen }
{ müssen und p1 muß ein Knoten auf die Klasse }
{ sein }
{ eigentlich ein Makro }
procedure do_member_read;
begin
consume(ID);
if sym=nil then
begin
error(id_no_member);
disposetree(p1);
p1:=genzeronode(errorn);
end
else
begin
{ nimmt an, das nur procsym's und varsym's in }
{ Symboltabellen von Klassen vorkommen }
case sym^.typ of
procsym : begin
p1:=genmethodcallnode(pprocsym(sym),
srsymtable,p1);
do_proc_call;
end;
varsym : begin
p1:=gensubscriptnode(sym,p1);
pd:=sym^.definition;
end;
else internalerror(16);
end;
end;
end;
{ bearbeitet die Postfixoperatoren }
{ pd und p1 müssen gesetzt sein }
procedure postfixoperators;
begin
while nochmal do
begin
case token of
CARET : begin
consume(CARET);
if pd^.deftype<>pointerdef then
begin
error(invalid_qualifizier);
disposetree(p1);
p1:=genzeronode(errorn);
end
else
begin
p1:=gensinglenode(derefn,p1);
pd:=ppointerdef(pd)^.definition;
end;
end;
LECKKLAMMER : begin
consume(LECKKLAMMER);
repeat
if (pd^.deftype<>arraydef) and
(pd^.deftype<>stringdef) and
(pd^.deftype<>pointerdef) then
begin
error(invalid_qualifizier);
disposetree(p1);
p1:=genzeronode(errorn);
end
else if (pd^.deftype=pointerdef) then
begin
p2:=expr;
p1:=gennode(vecn,p1,p2);
pd:=ppointerdef(pd)^.definition;
end
else
begin
p2:=expr;
p1:=gennode(vecn,p1,p2);
if pd^.deftype=stringdef then
pd:=cchardef
else pd:=parraydef(pd)^.definition;
end;
if token=COMMA then consume(COMMA)
else break;
until false;
consume(RECKKLAMMER);
end;
POINT : begin
consume(POINT);
case pd^.deftype of
recorddef :
begin
sym:=pvarsym(precdef(pd)^.symtable^.search(pattern));
consume(ID);
if sym=nil then
begin
error(ill_field);
disposetree(p1);
p1:=genzeronode(errorn);
end
else
begin
p1:=gensubscriptnode(sym,p1);
pd:=sym^.definition;
end;
end;
classdef :
begin
classh:=pclassdef(pd);
sym:=nil;
while assigned(classh) do
begin
sym:=pvarsym(classh^.publicsyms^.search(pattern));
srsymtable:=classh^.publicsyms;
if assigned(sym) then
break;
classh:=classh^.childof;
end;
do_member_read;
end
else
begin
error(invalid_qualifizier);
disposetree(p1);
p1:=genzeronode(errorn);
end;
end;
end;
else
begin
{ Prozedurvariablen }
if pd^.deftype=procvardef then
begin
if token=LKLAMMER then
begin
{ alles etwas ungewohnt benutzen }
p2:=p1;
p1:=gencallnode(nil,
nil);
p1^.right:=p2;
consume(LKLAMMER);
p1^.left:=parse_paras(false);
consume(RKLAMMER);
pd:=pprocvardef(pd)^.retdef;
p1^.resulttype:=pd;
end
else nochmal:=false;
end
else nochmal:=false;
end;
end;
end;
end;
procedure do_set(p : pconstset;pos : longint);
var
l : longint;
begin
if (pos>255) or
(pos<0) then
error(illsetexpr);
l:=pos div 8;
p^[l]:=p^[l] or (1 shl (pos mod 8));
end;
begin
case token of
ID : begin
{ Postfixoperatoren sind erlaubt }
nochmal:=true;
getsym(pattern,true);
consume(ID);
{ Zugriff auf das Funktionsresultat ? }
if (aktprocsym<>nil) and
(srsym^.name=aktprocsym^.name) and
(procinfo.retdef<>pdef(voiddef)) and
(token<>LKLAMMER) then
begin
p1:=genzeronode(funcretn);
pd:=procinfo.retdef;
end
else
begin
if srsym^.typ=unitsym then
begin
consume(POINT);
getsymonlyin(punitsym(srsym)^.unitsymtable,pattern);
consume(ID);
end;
case srsym^.typ of
varsym : begin
p1:=genloadnode(pvarsym(srsym),srsymtable);
pd:=pvarsym(srsym)^.definition;
end;
typedconstsym :
begin
p1:=gentypedconstloadnode(ptypedconstsym(srsym),srsymtable);
pd:=ptypedconstsym(srsym)^.definition;
end;
syssym : begin
p1:=anweisung_syssym(psyssym(srsym)^.number,pd);
end;
typesym : begin
pd:=ptypesym(srsym)^.definition;
if token=LKLAMMER then
begin
consume(LKLAMMER);
p1:=expr;
consume(RKLAMMER);
p1:=gentypeconvnode(p1,pd);
p1^.explizit:=true;
end
else if token=POINT then
begin
consume(POINT);
if pd^.deftype=classdef then
begin
if assigned(procinfo._class) then
begin
if procinfo._class^.isrelated(pclassdef(pd)) then
begin
p1:=genzeronode(typen);
p1^.resulttype:=pd;
srsymtable:=pclassdef(pd)^.publicsyms;
sym:=pvarsym(srsymtable^.search(pattern));
do_member_read;
end
else
error(no_super_class);
end
else
error(generic_methods_only_in_methods);
end
else
error(class_expected);
end
else
begin
{ Typknoten erzeugen }
p1:=genzeronode(typen);
p1^.resulttype:=pd;
pd:=voiddef;
end;
end;
aufzaehlsym : begin
p1:=genaufzaehlnode(paufzaehlsym(srsym));
pd:=p1^.resulttype;
end;
constsym : begin
case pconstsym(srsym)^.consttype of
constint : p1:=genordinalconstnode(pconstsym(srsym)^.value,s32bitdef);
conststring : p1:=genstringconstnode(pstring(pconstsym(srsym)^.value)^);
constchar : p1:=genordinalconstnode(pconstsym(srsym)^.value,cchardef);
constreal : p1:=genrealconstnode(pdouble(pconstsym(srsym)^.value)^);
constbool : p1:=genordinalconstnode(pconstsym(srsym)^.value,booldef);
constord : p1:=genordinalconstnode(pconstsym(srsym)^.value,
pconstsym(srsym)^.definition);
end;
pd:=p1^.resulttype;
end;
procsym : begin
p1:=gencallnode(pprocsym(srsym),srsymtable);
do_proc_call;
end;
errorsym : begin
p1:=genzeronode(errorn);
pd:=generrordef;
if token=LKLAMMER then
begin
consume(LKLAMMER);
parse_paras(false);
consume(RKLAMMER);
end;
end;
else
begin
p1:=genzeronode(errorn);
pd:=generrordef;
error(error_in_expression);
end;
end;
end;
{ Postfixoperatoren bearbeiten }
postfixoperators;
end;
_NEW : begin
consume(_NEW);
consume(LKLAMMER);
p1:=factor(false);
if p1^.treetype<>typen then
error(type_id_expect);
pd:=p1^.resulttype;
pd2:=pd;
if (pd^.deftype<>pointerdef) or
(ppointerdef(pd)^.definition^.deftype<>classdef) then
begin
error(pointer_to_class_expect);
{ bei Fehler bis Ende von new alles ignorieren }
p1:=genzeronode(errorn);
l:=1;
while true do
begin
case token of
LKLAMMER : inc(l);
RKLAMMER : dec(l);
end;
consume(token);
if l=0 then
break;
end;
end
else
begin
disposetree(p1);
p1:=genzeronode(hnewn);
p1^.resulttype:=ppointerdef(pd)^.definition;
consume(COMMA);
{ Konstruktor auch in den Symboltabellen der }
{ Elternklassen suchen }
classh:=pclassdef(ppointerdef(pd)^.definition);
sym:=nil;
while assigned(classh) do
begin
sym:=pvarsym(classh^.publicsyms^.search(pattern));
srsymtable:=classh^.publicsyms;
if assigned(sym) then
break;
classh:=classh^.childof;
end;
do_member_read;
if (p1^.treetype<>calln) or
((p1^.procdefinition^.options and poconstructor)=0) then
error(expr_have_to_be_constructor_call);
p1:=gensinglenode(newn,p1);
{ hier schon Resultattyp setzen }
p1^.resulttype:=pd2;
consume(RKLAMMER);
end;
end;
_SELF : begin
nochmal:=true;
consume(_SELF);
if not assigned(procinfo._class) then
begin
p1:=genzeronode(errorn);
error(self_not_in_method);
end
else
begin
p1:=genselfnode(procinfo._class);
p1^.resulttype:=procinfo._class;
pd:=p1^.resulttype;
end;
postfixoperators;
end;
_INHERITED : begin
nochmal:=true;
consume(_INHERITED);
if assigned(procinfo._class) then
begin
classh:=procinfo._class^.childof;
while assigned(classh) do
begin
srsymtable:=pclassdef(classh)^.publicsyms;
sym:=pvarsym(srsymtable^.search(pattern));
if assigned(sym) then
begin
p1:=genzeronode(typen);
p1^.resulttype:=classh;
pd:=p1^.resulttype;
do_member_read;
break;
end;
classh:=classh^.childof;
end;
if classh=nil then
error(id_no_member);
end
else
error(generic_methods_only_in_methods);
postfixoperators;
end;
INTCONST : begin
val(pattern,l,code);
if code<>0 then
begin
error(error_in_integer);
l:=1;
end;
consume(INTCONST);
p1:=genordinalconstnode(l,s32bitdef);
end;
REALNUMBER : begin
val(pattern,d,code);
if code<>0 then
begin
error(error_in_real);
d:=1.0;
end;
consume(REALNUMBER);
p1:=genrealconstnode(d);
end;
{ string kann auch ein Typkonvertierungsoperator sein }
_STRING : begin
pd:=stringtyp;
consume(LKLAMMER);
p1:=expr;
consume(RKLAMMER);
p1:=gentypeconvnode(p1,pd);
p1^.explizit:=true;
nochmal:=true;
end;
CSTRING : begin
p1:=genstringconstnode(pattern);
consume(CSTRING);
end;
CCHAR : begin
p1:=genordinalconstnode(ord(pattern[1]),cchardef);
consume(CCHAR);
end;
KLAMMERAFFE : begin
consume(KLAMMERAFFE);
p1:=factor(true);
p1:=gensinglenode(addrn,p1);
end;
LKLAMMER : begin
consume(LKLAMMER);
p1:=expr;
consume(RKLAMMER);
{ keine tolle Konstruktion }
{ aber sonst ist z.B. ([pointer]+[integer])^ }
{ ein kleines Problemchen }
case token of
CARET,POINT,LECKKLAMMER : begin
{ wir brauchen pd }
do_firstpass(p1);
pd:=p1^.resulttype;
nochmal:=true;
postfixoperators;
end;
end;
end;
LECKKLAMMER : begin
consume(LECKKLAMMER);
new(constset);
for l:=0 to 31 do
constset^[l]:=0;
p2:=nil;
pd:=nil;
if token<>RECKKLAMMER then
while true do
begin
p1:=expr;
do_firstpass(p1);
case p1^.treetype of
ordconstn : begin
if pd=nil then
pd:=p1^.resulttype;
if not(is_equal(pd,p1^.resulttype)) then
error(typeconflict_in_set)
else
do_set(constset,p1^.value);
disposetree(p1);
end;
rangen : begin
if pd=nil then
pd:=p1^.left^.resulttype;
if not(is_equal(pd,p1^.left^.resulttype)) then
error(typeconflict_in_set)
else
for l:=p1^.left^.value to p1^.right^.value do
do_set(constset,l);
disposetree(p1);
end;
else
begin
if pd=nil then
pd:=p1^.resulttype;
if not(is_equal(pd,p1^.resulttype)) then
error(typeconflict_in_set);
p2:=gennode(setelen,p1,p2);
end;
end;
if token=COMMA then
consume(COMMA)
else break;
end;
consume(RECKKLAMMER);
p1:=gensinglenode(setconstrn,p2);
p1^.resulttype:=new(psetdef,init(pd,255));
p1^.constset:=constset;
end;
PLUS : begin
consume(PLUS);
p1:=factor(false);
end;
MINUS : begin
consume(MINUS);
p1:=factor(false);
p1:=gensinglenode(umminusn,p1);
end;
_NOT : begin
consume(_NOT);
p1:=factor(false);
p1:=gensinglenode(notn,p1);
end;
_TRUE : begin
consume(_TRUE);
p1:=genordinalconstnode(1,booldef);
end;
_FALSE : begin
consume(_FALSE);
p1:=genordinalconstnode(0,booldef);
end;
_NIL : begin
consume(_NIL);
p1:=genzeronode(niln);
end;
else
begin
p1:=genzeronode(errorn);
consume(token);
error(error_in_expression);
end;
end;
factor:=p1;
end;
function term : ptree;
var
p1,p2 : ptree;
begin
p1:=factor(false);
repeat
case token of
STAR : begin
consume(STAR);
p2:=factor(false);
p1:=gennode(muln,p1,p2);
end;
SLASH : begin
consume(SLASH);
p2:=factor(false);
p1:=gennode(slashn,p1,p2);
end;
_DIV : begin
consume(_DIV);
p2:=factor(false);
p1:=gennode(divn,p1,p2);
end;
_MOD : begin
consume(_MOD);
p2:=factor(false);
p1:=gennode(modn,p1,p2);
end;
_AND : begin
consume(_AND);
p2:=factor(false);
p1:=gennode(andn,p1,p2);
end;
_SHL : begin
consume(_SHL);
p2:=factor(false);
p1:=gennode(shln,p1,p2);
end;
_SHR : begin
consume(_SHR);
p2:=factor(false);
p1:=gennode(shrn,p1,p2);
end;
else break;
end;
until false;
term:=p1;
end;
function simpl_expr : ptree;
var
p1,p2 : ptree;
begin
p1:=term;
repeat
case token of
PLUS : begin
consume(PLUS);
p2:=term;
p1:=gennode(addn,p1,p2);
end;
MINUS : begin
consume(MINUS);
p2:=term;
p1:=gennode(subn,p1,p2);
end;
_OR : begin
consume(_OR);
p2:=term;
p1:=gennode(orn,p1,p2);
end;
_XOR : begin
consume(_XOR);
p2:=term;
p1:=gennode(xorn,p1,p2);
end;
else break;
end;
until false;
simpl_expr:=p1;
end;
function simpl2_expr : ptree;
var
p1,p2 : ptree;
begin
p1:=simpl_expr;
repeat
case token of
LT : begin
consume(LT);
p2:=simpl_expr;
p1:=gennode(ltn,p1,p2);
end;
LTE : begin
consume(LTE);
p2:=simpl_expr;
p1:=gennode(lten,p1,p2);
end;
GT : begin
consume(GT);
p2:=simpl_expr;
p1:=gennode(gtn,p1,p2);
end;
GTE : begin
consume(GTE);
p2:=simpl_expr;
p1:=gennode(gten,p1,p2);
end;
EQUAL : begin
consume(EQUAL);
p2:=simpl_expr;
p1:=gennode(equaln,p1,p2);
end;
UNEQUAL : begin
consume(UNEQUAL);
p2:=simpl_expr;
p1:=gennode(unequaln,p1,p2);
end;
_IN : begin
consume(_IN);
p2:=simpl_expr;
p1:=gennode(inn,p1,p2);
end;
else break;
end;
until false;
simpl2_expr:=p1;
end;
function expr : ptree;
var
p1,p2 : ptree;
begin
p1:=simpl2_expr;
case token of
POINTPOINT : begin
consume(POINTPOINT);
p2:=simpl2_expr;
p1:=gennode(rangen,p1,p2);
end;
ASSIGNMENT : begin
consume(ASSIGNMENT);
{$ifdef tp}
p2:=expr;
{$else}
{ FPKPascal erkennt sonst den Aufruf nicht }
p2:=expr();
{$endif}
p1:=gennode(assignn,p1,p2);
end
end;
expr:=p1;
end;
procedure compile(const path,filename : string);
var
p : pgrunddef;
st : psymtable;
pd : pdef;
hs : string;
mac : pmacrosym;
i : ttoken;
comp_unit : boolean;
begin
{ !!!!!! save old state }
{ Zielbetriebssystem als Symbol für bedingte Compilierung }
{ festlegen }
mac:=new(pmacrosym,init(target_info.short_name));
mac^.defined:=true;
macros^.insert(mac);
{ copy command line options }
aktswitches:=initswitches;
aktexprlevel:=initexprlevel;
aktpackrecords:=initpackrecords;
{ Codegenerator initialisieren }
codegeninit;
{ Scanner initilisieren }
token:=yylex;
forwardsallowed:=false;
{ Definitionen jetzt nicht registrieren }
registerdef:=false;
{ Scanner ^M als String annehmen lassen }
parse_types:=false;
{ es wird keine Objectdeklaration geparst }
{ und kein Funktionskopf }
testaktobject:=0;
{ Fehlerdefinition erzeugen: }
generrordef:=new(perrordef,init);
{ Definitionen fuer Konstanten erzeugen: }
s32bitdef:=new(pgrunddef,init(s32bit,$80000000,$7fffffff));
cstringdef:=new(pstringdef,init(255));
cchardef:=new(pgrunddef,init(uchar,0,255));
cs64realdef:=new(pgrunddef,init(s64real,0,0));
{ sonstige verwendete Definitionen: }
voiddef:=new(pgrunddef,init(uvoid,0,0));
u8bitdef:=new(pgrunddef,init(u8bit,0,255));
u16bitdef:=new(pgrunddef,init(u16bit,0,65535));
booldef:=new(pgrunddef,init(bool8bit,0,1));
voidpointerdef:=new(ppointerdef,init(voiddef));
{ erst jetzt Definitionen registrieren, da vorher symtabletack }
{ auf jeden Fall ungueltig war, was mir einige Zeit Kopfzer- }
{ brechen verursacht hat }
registerdef:=true;
symtablestack:=nil;
{ no operator is overloaded }
{!!!!!!
for i:=PLUS to last_overloaded do
overloaded_operators[i]:=nil;
}
{ falls nicht SYSTEM compiliert wird, SYSTEM laden }
if not(cs_compilesystem in aktswitches) then
begin
readunit(target_info.system_unit);
insertinternsyms;
end;
{ aktueller Rückgabetyp: void }
procinfo.retdef:=voiddef;
{ lexikalisches Level zurücksetzen }
lexlevel:=0;
{ Quelltext parsen }
if token=_UNIT then
begin
proc_unit;
comp_unit:=true;
end
else
begin
proc_program;
comp_unit:=false;
end;
consume(_EOF);
if codegeneration then
begin
if cs_optimize in aktswitches then simpljumpopt(mainasmlist);
if cs_debuginfo in aktswitches then
begin
debuginfos.insert(gennasmrec(DIRECT,S_NO,'Ltext0:'));
mainasmlist.insertlist(@debuginfos);
end;
mainasmlist.insertlist(@startupasmlist);
{ nun Datensegment anhängen }
mainasmlist.concatlist(@datasegment);
constsegment.insert(gennasmrec(DIRECT,S_NO,'.align 4'));
constsegment.insert(gennasmrec(DIRECT,S_NO,'.data'));
{ nun Constsegment anhängen }
mainasmlist.concatlist(@constsegment);
{ und VMT's: }
mainasmlist.concatlist(@vmtasmlist);
{ Codegenerator beenden }
codegendone;
{ Inputpuffer entfernen }
donescanner;
if writeasmfile then
begin
{ use extern assembler }
writemainasmlist(inputdir+inputfile+'.s');
if not(quiet) then
writeln('Calling assembler...');
swapvectors;
exec(env_ppbin+'AS.EXE','-o '+inputdir+inputfile+target_info.objext+' '+inputdir+inputfile+'.S');
swapvectors;
if dosexitcode<>0 then
halt(100);
end
else
begin
writeofile(inputdir+inputfile+'.o');
end;
{ del all instructions }
mainasmlist.done;
end
else
begin
case language of
'D' : write(errorcount,' Fehler');
'E' : write(errorcount,' errors');
end;
writeln;
halt(1);
end;
{ Linkresponsedatei erst hier schließen, da auch }
{ die per $L aufgenommenen Units in Linkresponse }
{ eingetragen werden }
if not(comp_unit) then
begin
hs:=linkofiles.get;
while hs<>'' do
begin
writeln(linkresponse,hs);
hs:=linkofiles.get;
end;
close(linkresponse);
if not(quiet) then
writeln('Calling linker...');
swapvectors;
exec(env_ppbin+'LD.EXE','@LINK.RES');
swapvectors;
if dosexitcode<>0 then
halt(100);
erase(linkresponse);
end;
end;
end.