summaryrefslogtreecommitdiff
path: root/compiler/pdecl.pas
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/pdecl.pas')
-rw-r--r--compiler/pdecl.pas659
1 files changed, 659 insertions, 0 deletions
diff --git a/compiler/pdecl.pas b/compiler/pdecl.pas
new file mode 100644
index 0000000000..476d25d257
--- /dev/null
+++ b/compiler/pdecl.pas
@@ -0,0 +1,659 @@
+{
+ Copyright (c) 1998-2002 by Florian Klaempfl
+
+ Does declaration (but not type) parsing for Free Pascal
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit pdecl;
+
+{$i fpcdefs.inc}
+
+interface
+
+ uses
+ { global }
+ globals,
+ { symtable }
+ symsym,
+ { pass_1 }
+ node;
+
+ function readconstant(const orgname:string;const filepos:tfileposinfo):tconstsym;
+
+ procedure const_dec;
+ procedure label_dec;
+ procedure type_dec;
+ procedure var_dec;
+ procedure threadvar_dec;
+ procedure property_dec;
+ procedure resourcestring_dec;
+
+implementation
+
+ uses
+ { common }
+ cutils,cclasses,
+ { global }
+ globtype,tokens,verbose,widestr,
+ systems,
+ { aasm }
+ aasmbase,aasmtai,fmodule,
+ { symtable }
+ symconst,symbase,symtype,symdef,symtable,paramgr,defutil,
+ { pass 1 }
+ nmat,nadd,ncal,nset,ncnv,ninl,ncon,nld,nflw,nobj,
+ { codegen }
+ ncgutil,
+ { parser }
+ scanner,
+ pbase,pexpr,ptype,ptconst,pdecsub,pdecvar,pdecobj,
+ { cpu-information }
+ cpuinfo
+ ;
+
+
+ function readconstant(const orgname:string;const filepos:tfileposinfo):tconstsym;
+ var
+ hp : tconstsym;
+ p : tnode;
+ ps : pconstset;
+ pd : pbestreal;
+ pg : pguid;
+ sp : pchar;
+ pw : pcompilerwidestring;
+ storetokenpos : tfileposinfo;
+ begin
+ readconstant:=nil;
+ if orgname='' then
+ internalerror(9584582);
+ hp:=nil;
+ p:=comp_expr(true);
+ storetokenpos:=akttokenpos;
+ akttokenpos:=filepos;
+ case p.nodetype of
+ ordconstn:
+ begin
+ if p.resulttype.def.deftype=pointerdef then
+ hp:=tconstsym.create_ordptr(orgname,constpointer,tordconstnode(p).value,p.resulttype)
+ else
+ hp:=tconstsym.create_ord(orgname,constord,tordconstnode(p).value,p.resulttype);
+ end;
+ stringconstn:
+ begin
+ if is_widestring(p.resulttype.def) then
+ begin
+ initwidestring(pw);
+ copywidestring(pcompilerwidestring(tstringconstnode(p).value_str),pw);
+ hp:=tconstsym.create_wstring(orgname,constwstring,pw);
+ end
+ else
+ begin
+ getmem(sp,tstringconstnode(p).len+1);
+ move(tstringconstnode(p).value_str^,sp^,tstringconstnode(p).len+1);
+ hp:=tconstsym.create_string(orgname,conststring,sp,tstringconstnode(p).len);
+ end;
+ end;
+ realconstn :
+ begin
+ new(pd);
+ pd^:=trealconstnode(p).value_real;
+ hp:=tconstsym.create_ptr(orgname,constreal,pd,p.resulttype);
+ end;
+ setconstn :
+ begin
+ new(ps);
+ ps^:=tsetconstnode(p).value_set^;
+ hp:=tconstsym.create_ptr(orgname,constset,ps,p.resulttype);
+ end;
+ pointerconstn :
+ begin
+ hp:=tconstsym.create_ordptr(orgname,constpointer,tpointerconstnode(p).value,p.resulttype);
+ end;
+ niln :
+ begin
+ hp:=tconstsym.create_ord(orgname,constnil,0,p.resulttype);
+ end;
+ typen :
+ begin
+ if is_interface(p.resulttype.def) then
+ begin
+ if assigned(tobjectdef(p.resulttype.def).iidguid) then
+ begin
+ new(pg);
+ pg^:=tobjectdef(p.resulttype.def).iidguid^;
+ hp:=tconstsym.create_ptr(orgname,constguid,pg,p.resulttype);
+ end
+ else
+ Message1(parser_e_interface_has_no_guid,tobjectdef(p.resulttype.def).objrealname^);
+ end
+ else
+ Message(parser_e_illegal_expression);
+ end;
+ else
+ Message(parser_e_illegal_expression);
+ end;
+ akttokenpos:=storetokenpos;
+ p.free;
+ readconstant:=hp;
+ end;
+
+
+ procedure const_dec;
+ var
+ orgname : stringid;
+ tt : ttype;
+ sym : tsym;
+ dummysymoptions : tsymoptions;
+ storetokenpos,filepos : tfileposinfo;
+ old_block_type : tblock_type;
+ skipequal : boolean;
+ begin
+ consume(_CONST);
+ old_block_type:=block_type;
+ block_type:=bt_const;
+ repeat
+ orgname:=orgpattern;
+ filepos:=akttokenpos;
+ consume(_ID);
+ case token of
+
+ _EQUAL:
+ begin
+ consume(_EQUAL);
+ sym:=readconstant(orgname,filepos);
+ { Support hint directives }
+ dummysymoptions:=[];
+ try_consume_hintdirective(dummysymoptions);
+ if assigned(sym) then
+ begin
+ sym.symoptions:=sym.symoptions+dummysymoptions;
+ symtablestack.insert(sym);
+ end;
+ consume(_SEMICOLON);
+ end;
+
+ _COLON:
+ begin
+ { set the blocktype first so a consume also supports a
+ caret, to support const s : ^string = nil }
+ block_type:=bt_type;
+ consume(_COLON);
+ ignore_equal:=true;
+ read_type(tt,'',false);
+ ignore_equal:=false;
+ block_type:=bt_const;
+ skipequal:=false;
+ { create symbol }
+ storetokenpos:=akttokenpos;
+ akttokenpos:=filepos;
+ sym:=ttypedconstsym.createtype(orgname,tt,(cs_typed_const_writable in aktlocalswitches));
+ akttokenpos:=storetokenpos;
+ symtablestack.insert(sym);
+ { procvar can have proc directives, but not type references }
+ if (tt.def.deftype=procvardef) and
+ (tt.sym=nil) then
+ begin
+ { support p : procedure;stdcall=nil; }
+ if try_to_consume(_SEMICOLON) then
+ begin
+ if check_proc_directive(true) then
+ parse_var_proc_directives(sym)
+ else
+ begin
+ Message(parser_e_proc_directive_expected);
+ skipequal:=true;
+ end;
+ end
+ else
+ { support p : procedure stdcall=nil; }
+ begin
+ if check_proc_directive(true) then
+ parse_var_proc_directives(sym);
+ end;
+ { add default calling convention }
+ handle_calling_convention(tabstractprocdef(tt.def));
+ end;
+ if not skipequal then
+ begin
+ { get init value }
+ consume(_EQUAL);
+ readtypedconst(tt,ttypedconstsym(sym),(cs_typed_const_writable in aktlocalswitches));
+ try_consume_hintdirective(sym.symoptions);
+ consume(_SEMICOLON);
+ end;
+ end;
+
+ else
+ { generate an error }
+ consume(_EQUAL);
+ end;
+ until token<>_ID;
+ block_type:=old_block_type;
+ end;
+
+
+ procedure label_dec;
+ var
+ hl : tasmlabel;
+ begin
+ consume(_LABEL);
+ if not(cs_support_goto in aktmoduleswitches) then
+ Message(sym_e_goto_and_label_not_supported);
+ repeat
+ if not(token in [_ID,_INTCONST]) then
+ consume(_ID)
+ else
+ begin
+ if token=_ID then
+ symtablestack.insert(tlabelsym.create(orgpattern))
+ else
+ symtablestack.insert(tlabelsym.create(pattern));
+ consume(token);
+ end;
+ if token<>_SEMICOLON then consume(_COMMA);
+ until not(token in [_ID,_INTCONST]);
+ consume(_SEMICOLON);
+ end;
+
+
+ { search in symtablestack used, but not defined type }
+ procedure resolve_type_forward(p : tnamedindexitem;arg:pointer);
+ var
+ hpd,pd : tdef;
+ stpos : tfileposinfo;
+ again : boolean;
+ srsym : tsym;
+ srsymtable : tsymtable;
+
+ begin
+ { Check only typesyms or record/object fields }
+ case tsym(p).typ of
+ typesym :
+ pd:=ttypesym(p).restype.def;
+ fieldvarsym :
+ pd:=tfieldvarsym(p).vartype.def
+ else
+ exit;
+ end;
+ repeat
+ again:=false;
+ case pd.deftype of
+ arraydef :
+ begin
+ { elementtype could also be defined using a forwarddef }
+ pd:=tarraydef(pd).elementtype.def;
+ again:=true;
+ end;
+ pointerdef,
+ classrefdef :
+ begin
+ { classrefdef inherits from pointerdef }
+ hpd:=tpointerdef(pd).pointertype.def;
+ { still a forward def ? }
+ if hpd.deftype=forwarddef then
+ begin
+ { try to resolve the forward }
+ { get the correct position for it }
+ stpos:=akttokenpos;
+ akttokenpos:=tforwarddef(hpd).forwardpos;
+ resolving_forward:=true;
+ make_ref:=false;
+ if not assigned(tforwarddef(hpd).tosymname) then
+ internalerror(20021120);
+ searchsym(tforwarddef(hpd).tosymname^,srsym,srsymtable);
+ make_ref:=true;
+ resolving_forward:=false;
+ akttokenpos:=stpos;
+ { we don't need the forwarddef anymore, dispose it }
+ hpd.free;
+ tpointerdef(pd).pointertype.def:=nil; { if error occurs }
+ { was a type sym found ? }
+ if assigned(srsym) and
+ (srsym.typ=typesym) then
+ begin
+ tpointerdef(pd).pointertype.setsym(srsym);
+ { avoid wrong unused warnings web bug 801 PM }
+ inc(ttypesym(srsym).refs);
+ { we need a class type for classrefdef }
+ if (pd.deftype=classrefdef) and
+ not(is_class(ttypesym(srsym).restype.def)) then
+ Message1(type_e_class_type_expected,ttypesym(srsym).restype.def.typename);
+ end
+ else
+ begin
+ MessagePos1(tsym(p).fileinfo,sym_e_forward_type_not_resolved,tsym(p).realname);
+ { try to recover }
+ tpointerdef(pd).pointertype:=generrortype;
+ end;
+ end;
+ end;
+ recorddef :
+ trecorddef(pd).symtable.foreach_static(@resolve_type_forward,nil);
+ objectdef :
+ begin
+ if not(m_fpc in aktmodeswitches) and
+ (oo_is_forward in tobjectdef(pd).objectoptions) then
+ begin
+ { only give an error as the implementation may follow in an
+ other type block which is allowed by FPC modes }
+ MessagePos1(tsym(p).fileinfo,sym_e_forward_type_not_resolved,tsym(p).realname);
+ end
+ else
+ begin
+ { Check all fields of the object declaration, but don't
+ check objectdefs in objects/records, because these
+ can't exist (anonymous objects aren't allowed) }
+ if not(tsym(p).owner.symtabletype in [objectsymtable,recordsymtable]) then
+ tobjectdef(pd).symtable.foreach_static(@resolve_type_forward,nil);
+ end;
+ end;
+ end;
+ until not again;
+ end;
+
+
+ { reads a type declaration to the symbol table }
+ procedure type_dec;
+ var
+ typename,orgtypename : stringid;
+ newtype : ttypesym;
+ sym : tsym;
+ srsymtable : tsymtable;
+ tt : ttype;
+ oldfilepos,
+ defpos,storetokenpos : tfileposinfo;
+ old_block_type : tblock_type;
+ ch : tclassheader;
+ unique,istyperenaming : boolean;
+
+ begin
+ old_block_type:=block_type;
+ block_type:=bt_type;
+ consume(_TYPE);
+ typecanbeforward:=true;
+ repeat
+ typename:=pattern;
+ orgtypename:=orgpattern;
+ defpos:=akttokenpos;
+ istyperenaming:=false;
+ consume(_ID);
+ consume(_EQUAL);
+ { support 'ttype=type word' syntax }
+ unique:=try_to_consume(_TYPE);
+
+ { MacPas object model is more like Delphi's than like TP's, but }
+ { uses the object keyword instead of class }
+ if (m_mac in aktmodeswitches) and
+ (token = _OBJECT) then
+ token := _CLASS;
+
+ { is the type already defined? }
+ searchsym(typename,sym,srsymtable);
+ newtype:=nil;
+ { found a symbol with this name? }
+ if assigned(sym) then
+ begin
+ if (sym.typ=typesym) then
+ begin
+ if ((token=_CLASS) or
+ (token=_INTERFACE)) and
+ (assigned(ttypesym(sym).restype.def)) and
+ is_class_or_interface(ttypesym(sym).restype.def) and
+ (oo_is_forward in tobjectdef(ttypesym(sym).restype.def).objectoptions) then
+ begin
+ { we can ignore the result }
+ { the definition is modified }
+ object_dec(orgtypename,tobjectdef(ttypesym(sym).restype.def));
+ newtype:=ttypesym(sym);
+ tt:=newtype.restype;
+ end
+ else
+ message1(parser_h_type_redef,orgtypename);
+ end;
+ end;
+ { no old type reused ? Then insert this new type }
+ if not assigned(newtype) then
+ begin
+ { insert the new type first with an errordef, so that
+ referencing the type before it's really set it
+ will give an error (PFV) }
+ tt:=generrortype;
+ storetokenpos:=akttokenpos;
+ newtype:=ttypesym.create(orgtypename,tt);
+ symtablestack.insert(newtype);
+ akttokenpos:=defpos;
+ akttokenpos:=storetokenpos;
+ { read the type definition }
+ read_type(tt,orgtypename,false);
+ { update the definition of the type }
+ newtype.restype:=tt;
+ if assigned(tt.sym) then
+ istyperenaming:=true
+ else
+ tt.sym:=newtype;
+ if unique and assigned(tt.def) then
+ begin
+ tt.setdef(tstoreddef(tt.def).getcopy);
+ include(tt.def.defoptions,df_unique);
+ newtype.restype:=tt;
+ end;
+ if assigned(tt.def) and not assigned(tt.def.typesym) then
+ tt.def.typesym:=newtype;
+ { KAZ: handle TGUID declaration in system unit }
+ if (cs_compilesystem in aktmoduleswitches) and not assigned(rec_tguid) and
+ (typename='TGUID') and { name: TGUID and size=16 bytes that is 128 bits }
+ assigned(tt.def) and (tt.def.deftype=recorddef) and (tt.def.size=16) then
+ rec_tguid:=trecorddef(tt.def);
+ end;
+ if assigned(tt.def) then
+ begin
+ case tt.def.deftype of
+ pointerdef :
+ begin
+ consume(_SEMICOLON);
+ if try_to_consume(_FAR) then
+ begin
+ tpointerdef(tt.def).is_far:=true;
+ consume(_SEMICOLON);
+ end;
+ end;
+ procvardef :
+ begin
+ { in case of type renaming, don't parse proc directives }
+ if istyperenaming then
+ consume(_SEMICOLON)
+ else
+ begin
+ if not check_proc_directive(true) then
+ consume(_SEMICOLON);
+ parse_var_proc_directives(tsym(newtype));
+ handle_calling_convention(tprocvardef(tt.def));
+ end;
+ end;
+ objectdef,
+ recorddef :
+ begin
+ try_consume_hintdirective(newtype.symoptions);
+ consume(_SEMICOLON);
+ end;
+ else
+ consume(_SEMICOLON);
+ end;
+ end;
+
+ { Write tables if we are the typesym that defines
+ this type. This will not be done for simple type renamings }
+ if (tt.def.typesym=newtype) then
+ begin
+ { file position }
+ oldfilepos:=aktfilepos;
+ aktfilepos:=newtype.fileinfo;
+
+ { generate persistent init/final tables when it's declared in the interface so it can
+ be reused in other used }
+ if current_module.in_interface and
+ ((is_class(tt.def) and
+ tobjectdef(tt.def).members_need_inittable) or
+ tt.def.needs_inittable) then
+ generate_inittable(newtype);
+
+ { for objects we should write the vmt and interfaces.
+ This need to be done after the rtti has been written, because
+ it can contain a reference to that data (PFV)
+ This is not for forward classes }
+ if (tt.def.deftype=objectdef) and
+ (tt.def.owner.symtabletype in [staticsymtable,globalsymtable]) then
+ with Tobjectdef(tt.def) do
+ begin
+ if not(oo_is_forward in objectoptions) then
+ begin
+ ch:=tclassheader.create(tobjectdef(tt.def));
+ { generate and check virtual methods, must be done
+ before RTTI is written }
+ ch.genvmt;
+ { Generate RTTI for class }
+ generate_rtti(newtype);
+ if is_interface(tobjectdef(tt.def)) then
+ ch.writeinterfaceids;
+ if (oo_has_vmt in objectoptions) then
+ ch.writevmt;
+ ch.free;
+ end;
+ end
+ else
+ begin
+ { Always generate RTTI info for all types. This is to have typeinfo() return
+ the same pointer }
+ generate_rtti(newtype);
+ end;
+
+ aktfilepos:=oldfilepos;
+ end;
+ until token<>_ID;
+ typecanbeforward:=false;
+ symtablestack.foreach_static(@resolve_type_forward,nil);
+ block_type:=old_block_type;
+ end;
+
+
+ procedure var_dec;
+ { parses variable declarations and inserts them in }
+ { the top symbol table of symtablestack }
+ begin
+ consume(_VAR);
+ read_var_decs([]);
+ end;
+
+
+ procedure property_dec;
+ var
+ old_block_type : tblock_type;
+ begin
+ consume(_PROPERTY);
+ if not(symtablestack.symtabletype in [staticsymtable,globalsymtable]) then
+ message(parser_e_resourcestring_only_sg);
+ old_block_type:=block_type;
+ block_type:=bt_const;
+ repeat
+ read_property_dec(nil);
+ consume(_SEMICOLON);
+ until token<>_ID;
+ block_type:=old_block_type;
+ end;
+
+
+ procedure threadvar_dec;
+ { parses thread variable declarations and inserts them in }
+ { the top symbol table of symtablestack }
+ begin
+ consume(_THREADVAR);
+ if not(symtablestack.symtabletype in [staticsymtable,globalsymtable]) then
+ message(parser_e_threadvars_only_sg);
+ read_var_decs([vd_threadvar]);
+ end;
+
+
+ procedure resourcestring_dec;
+ var
+ orgname : stringid;
+ p : tnode;
+ dummysymoptions : tsymoptions;
+ storetokenpos,filepos : tfileposinfo;
+ old_block_type : tblock_type;
+ sp : pchar;
+ sym : tsym;
+ begin
+ consume(_RESOURCESTRING);
+ if not(symtablestack.symtabletype in [staticsymtable,globalsymtable]) then
+ message(parser_e_resourcestring_only_sg);
+ old_block_type:=block_type;
+ block_type:=bt_const;
+ repeat
+ orgname:=orgpattern;
+ filepos:=akttokenpos;
+ consume(_ID);
+ case token of
+ _EQUAL:
+ begin
+ consume(_EQUAL);
+ p:=comp_expr(true);
+ storetokenpos:=akttokenpos;
+ akttokenpos:=filepos;
+ sym:=nil;
+ case p.nodetype of
+ ordconstn:
+ begin
+ if is_constcharnode(p) then
+ begin
+ getmem(sp,2);
+ sp[0]:=chr(tordconstnode(p).value);
+ sp[1]:=#0;
+ sym:=tconstsym.create_string(orgname,constresourcestring,sp,1);
+ end
+ else
+ Message(parser_e_illegal_expression);
+ end;
+ stringconstn:
+ with Tstringconstnode(p) do
+ begin
+ getmem(sp,len+1);
+ move(value_str^,sp^,len+1);
+ sym:=tconstsym.create_string(orgname,constresourcestring,sp,len);
+ end;
+ else
+ Message(parser_e_illegal_expression);
+ end;
+ akttokenpos:=storetokenpos;
+ { Support hint directives }
+ dummysymoptions:=[];
+ try_consume_hintdirective(dummysymoptions);
+ if assigned(sym) then
+ begin
+ sym.symoptions:=sym.symoptions+dummysymoptions;
+ symtablestack.insert(sym);
+ end;
+ consume(_SEMICOLON);
+ p.free;
+ end;
+ else consume(_EQUAL);
+ end;
+ until token<>_ID;
+ block_type:=old_block_type;
+ end;
+
+end.