2
0
Эх сурвалжийг харах

* split type reading from pdecl to ptype unit
* parameter_dec routine is now used for procedure and procvars

peter 26 жил өмнө
parent
commit
89b677a0ee

+ 6 - 2
compiler/globtype.pas

@@ -137,7 +137,7 @@ interface
 
        { currently parsed block type }
        tblock_type = (bt_none,
-         bt_general,bt_type,bt_const
+         bt_general,bt_type,bt_const,bt_except
        );
 
        { packrecords types }
@@ -179,7 +179,11 @@ begin
 end.
 {
   $Log$
-  Revision 1.19  1999-09-20 16:38:54  peter
+  Revision 1.20  1999-10-22 10:39:34  peter
+    * split type reading from pdecl to ptype unit
+    * parameter_dec routine is now used for procedure and procvars
+
+  Revision 1.19  1999/09/20 16:38:54  peter
     * cs_create_smart instead of cs_smartlink
     * -CX is create smartlink
     * -CD is create dynamic, but does nothing atm.

+ 6 - 2
compiler/parser.pas

@@ -67,7 +67,7 @@ unit parser;
       { cgbase must be after hcodegen to use the correct procinfo !!! }
       cgbase,
 {$endif newcg}
-      comphook,tree,scanner,pbase,pdecl,psystem,pmodules,cresstr;
+      comphook,tree,scanner,pbase,ptype,psystem,pmodules,cresstr;
 
 
     procedure initparser;
@@ -487,7 +487,11 @@ unit parser;
 end.
 {
   $Log$
-  Revision 1.88  1999-10-12 21:20:45  florian
+  Revision 1.89  1999-10-22 10:39:34  peter
+    * split type reading from pdecl to ptype unit
+    * parameter_dec routine is now used for procedure and procvars
+
+  Revision 1.88  1999/10/12 21:20:45  florian
     * new codegenerator compiles again
 
   Revision 1.87  1999/10/03 19:44:41  peter

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 493 - 1906
compiler/pdecl.pas


+ 7 - 3
compiler/pexpr.pas

@@ -60,7 +60,7 @@ unit pexpr;
 {$endif newcg}
        pass_1,
        { parser specific stuff }
-       pbase,pdecl,
+       pbase,ptype,
        { processor specific stuff }
        cpubase,cpuinfo;
 
@@ -1757,7 +1757,7 @@ unit pexpr;
                  p1:=genrealconstnode(d,bestrealdef^);
                end;
      _STRING : begin
-                 pd:=stringtype;
+                 pd:=string_dec;
                  { STRING can be also a type cast }
                  if token=_LKLAMMER then
                   begin
@@ -2113,7 +2113,11 @@ _LECKKLAMMER : begin
 end.
 {
   $Log$
-  Revision 1.148  1999-10-14 14:57:52  florian
+  Revision 1.149  1999-10-22 10:39:34  peter
+    * split type reading from pdecl to ptype unit
+    * parameter_dec routine is now used for procedure and procvars
+
+  Revision 1.148  1999/10/14 14:57:52  florian
     - removed the hcodegen use in the new cg, use cgbase instead
 
   Revision 1.147  1999/09/28 11:03:54  peter

+ 11 - 11
compiler/pstatmnt.pas

@@ -26,10 +26,6 @@ unit pstatmnt;
 
     uses tree;
 
-    var
-       { true, if we are in a except block }
-       in_except_block : boolean;
-
     { reads a block }
     function block(islibrary : boolean) : ptree;
 
@@ -506,7 +502,7 @@ unit pstatmnt;
            end
          else
            begin
-              if not(in_except_block) then
+              if (block_type<>bt_except) then
                Message(parser_e_no_reraise_possible);
            end;
          raise_statement:=gennode(raisen,p1,p2);
@@ -520,7 +516,7 @@ unit pstatmnt;
          p_default,p_specific,hp : ptree;
          ot : pobjectdef;
          sym : pvarsym;
-         old_in_except_block : boolean;
+         old_block_type : tblock_type;
          exceptsymtable : psymtable;
          objname : stringid;
 
@@ -564,8 +560,8 @@ unit pstatmnt;
          else
            begin
               consume(_EXCEPT);
-              old_in_except_block:=in_except_block;
-              in_except_block:=true;
+              old_block_type:=block_type;
+              block_type:=bt_except;
               p_specific:=nil;
               if token=_ON then
                 { catch specific exceptions }
@@ -677,7 +673,7 @@ unit pstatmnt;
                 end;
               dec(statement_level);
 
-              in_except_block:=old_in_except_block;
+              block_type:=old_block_type;
               try_statement:=genloopnode(tryexceptn,p_try_block,p_specific,p_default,false);
            end;
       end;
@@ -694,7 +690,7 @@ unit pstatmnt;
            begin
               p:=comp_expr(true);
               consume(_RKLAMMER);
-              if in_except_block then
+              if (block_type=bt_except) then
                 Message(parser_e_exit_with_argument_not__possible);
               if procinfo^.retdef=pdef(voiddef) then
                 Message(parser_e_void_function);
@@ -1324,7 +1320,11 @@ unit pstatmnt;
 end.
 {
   $Log$
-  Revision 1.104  1999-10-14 14:57:54  florian
+  Revision 1.105  1999-10-22 10:39:35  peter
+    * split type reading from pdecl to ptype unit
+    * parameter_dec routine is now used for procedure and procvars
+
+  Revision 1.104  1999/10/14 14:57:54  florian
     - removed the hcodegen use in the new cg, use cgbase instead
 
   Revision 1.103  1999/09/27 23:44:56  peter

+ 9 - 202
compiler/psub.pas

@@ -78,7 +78,7 @@ uses
   ,tgen68k,cga68k
 {$endif}
   { parser specific stuff }
-  ,pbase,pdecl,pexpr,pstatmnt
+  ,pbase,ptype,pdecl,pexpr,pstatmnt
 {$ifdef newcg}
   ,tgcpu,convtree,cgobj,tgeni386  { for the new code generator tgeni386 is only a dummy }
 {$endif newcg}
@@ -88,204 +88,6 @@ var
   realname:string;  { contains the real name of a procedure as it's typed }
 
 
-procedure formal_parameter_list;
-{
-  handle_procvar needs the same changes
-}
-var
-  sc      : Pstringcontainer;
-  s       : string;
-  storetokenpos : tfileposinfo;
-  p       : Pdef;
-  hsym    : psym;
-  hvs,
-  vs      : Pvarsym;
-  hs1,hs2 : string;
-  varspez : Tvarspez;
-  inserthigh : boolean;
-begin
-  consume(_LKLAMMER);
-  inc(testcurobject);
-  repeat
-    if try_to_consume(_VAR) then
-      varspez:=vs_var
-    else
-      if try_to_consume(_CONST) then
-        varspez:=vs_const
-      else
-        varspez:=vs_value;
-    inserthigh:=false;
-    readtypesym:=nil;
-    if idtoken=_SELF then
-      begin
-         { we parse the defintion in the class definition }
-         if assigned(procinfo^._class) and procinfo^._class^.is_class then
-           begin
-{$ifndef UseNiceNames}
-            hs2:=hs2+'$'+'self';
-{$else UseNiceNames}
-            hs2:=hs2+tostr(length('self'))+'self';
-{$endif UseNiceNames}
-            vs:=new(Pvarsym,init('@',procinfo^._class));
-            vs^.varspez:=vs_var;
-          { insert the sym in the parasymtable }
-            aktprocsym^.definition^.parast^.insert(vs);
-{$ifdef INCLUDEOK}
-            include(aktprocsym^.definition^.procoptions,po_containsself);
-{$else}
-            aktprocsym^.definition^.procoptions:=aktprocsym^.definition^.procoptions+[po_containsself];
-{$endif}
-{$ifdef newcg}
-            inc(procinfo^.selfpointer_offset,vs^.address);
-{$else newcg}
-            inc(procinfo^.ESI_offset,vs^.address);
-{$endif newcg}
-            consume(idtoken);
-            consume(_COLON);
-            p:=single_type(hs1,false);
-            if assigned(readtypesym) then
-             aktprocsym^.definition^.concattypesym(readtypesym,vs_value)
-            else
-             aktprocsym^.definition^.concatdef(p,vs_value);
-            CheckTypes(p,procinfo^._class);
-           end
-         else
-           consume(_ID);
-      end
-    else
-      begin
-       { read identifiers }
-         sc:=idlist;
-       { read type declaration, force reading for value and const paras }
-         if (token=_COLON) or (varspez=vs_value) then
-          begin
-            consume(_COLON);
-          { check for an open array }
-            if token=_ARRAY then
-             begin
-               consume(_ARRAY);
-               consume(_OF);
-             { define range and type of range }
-               p:=new(Parraydef,init(0,-1,s32bitdef));
-             { array of const ? }
-               if (token=_CONST) and (m_objpas in aktmodeswitches) then
-                begin
-                  consume(_CONST);
-                  srsym:=nil;
-                  getsymonlyin(systemunit,'TVARREC');
-                  if not assigned(srsym) then
-                   InternalError(1234124);
-                  Parraydef(p)^.definition:=ptypesym(srsym)^.definition;
-                  Parraydef(p)^.IsArrayOfConst:=true;
-                  hs1:='array_of_const';
-                end
-               else
-                begin
-                { define field type }
-                  Parraydef(p)^.definition:=single_type(hs1,false);
-                  hs1:='array_of_'+hs1;
-                  { we don't need the typesym anymore }
-                  readtypesym:=nil;
-                end;
-               inserthigh:=true;
-             end
-            { open string ? }
-            else if (varspez=vs_var) and
-                    (
-                      (
-                        ((token=_STRING) or (idtoken=_SHORTSTRING)) and
-                        (cs_openstring in aktmoduleswitches) and
-                        not(cs_ansistrings in aktlocalswitches)
-                      ) or
-                    (idtoken=_OPENSTRING)) then
-             begin
-               consume(token);
-               p:=openshortstringdef;
-               hs1:='openstring';
-               inserthigh:=true;
-             end
-            { everything else }
-            else
-             p:=single_type(hs1,false);
-          end
-         else
-          begin
-     {$ifndef UseNiceNames}
-            hs1:='$$$';
-     {$else UseNiceNames}
-            hs1:='var';
-     {$endif UseNiceNames}
-            p:=cformaldef;
-            { }
-          end;
-         hs2:=aktprocsym^.definition^.mangledname;
-         storetokenpos:=tokenpos;
-         while not sc^.empty do
-          begin
-{$ifndef UseNiceNames}
-            hs2:=hs2+'$'+hs1;
-{$else UseNiceNames}
-            hs2:=hs2+tostr(length(hs1))+hs1;
-{$endif UseNiceNames}
-            s:=sc^.get_with_tokeninfo(tokenpos);
-            if assigned(readtypesym) then
-             begin
-               aktprocsym^.definition^.concattypesym(readtypesym,varspez);
-               vs:=new(Pvarsym,initsym(s,readtypesym))
-             end
-            else
-             begin
-               aktprocsym^.definition^.concatdef(p,varspez);
-               vs:=new(Pvarsym,init(s,p));
-             end;
-            vs^.varspez:=varspez;
-          { we have to add this to avoid var param to be in registers !!!}
-            if (varspez in [vs_var,vs_const]) and push_addr_param(p) then
-{$ifdef INCLUDEOK}
-              include(vs^.varoptions,vo_regable);
-{$else}
-              vs^.varoptions:=vs^.varoptions+[vo_regable];
-{$endif}
-
-            { search for duplicate ids in object members/methods    }
-            { but only the current class, I don't know why ...      }
-            { at least TP and Delphi do it in that way   (FK) }
-            if assigned(procinfo^._class) and
-               (lexlevel=normal_function_level) then
-             begin
-               hsym:=procinfo^._class^.symtable^.search(vs^.name);
-               if assigned(hsym) then
-                DuplicateSym(hsym);
-             end;
-
-          { do we need a local copy }
-            if (varspez=vs_value) and push_addr_param(p) and
-               not(is_open_array(p) or is_array_of_const(p)) then
-              vs^.setname('val'+vs^.name);
-
-          { insert the sym in the parasymtable }
-            aktprocsym^.definition^.parast^.insert(vs);
-
-          { also need to push a high value? }
-            if inserthigh then
-             begin
-               hvs:=new(Pvarsym,init('high'+s,s32bitdef));
-               hvs^.varspez:=vs_const;
-               aktprocsym^.definition^.parast^.insert(hvs);
-             end;
-
-          end;
-         dispose(sc,done);
-         tokenpos:=storetokenpos;
-      end;
-    aktprocsym^.definition^.setmangledname(hs2);
-  until not try_to_consume(_SEMICOLON);
-  dec(testcurobject);
-  consume(_RKLAMMER);
-end;
-
-
-
 procedure parse_proc_head(options:tproctypeoption);
 var sp:stringid;
     pd:Pprocdef;
@@ -543,7 +345,8 @@ begin
     definitions of args defs in staticsymtable for
     implementation of a global method }
   if token=_LKLAMMER then
-    formal_parameter_list;
+    parameter_dec(aktprocsym^.definition);
+
   { so we only restore the symtable now }
   symtablestack:=st;
   if (options=potype_operator) then
@@ -1577,7 +1380,7 @@ begin
        getlabel(quickexitlabel);
      end;
    { reset break and continue labels }
-   in_except_block:=false;
+   block_type:=bt_general;
    aktbreaklabel:=nil;
    aktcontinuelabel:=nil;
 
@@ -2099,7 +1902,11 @@ end.
 
 {
   $Log$
-  Revision 1.28  1999-10-13 10:37:36  peter
+  Revision 1.29  1999-10-22 10:39:35  peter
+    * split type reading from pdecl to ptype unit
+    * parameter_dec routine is now used for procedure and procvars
+
+  Revision 1.28  1999/10/13 10:37:36  peter
     * moved mangledname creation of normal proc so it also handles a wrong
       method proc
 

+ 1616 - 0
compiler/ptype.pas

@@ -0,0 +1,1616 @@
+{
+    $Id$
+    Copyright (c) 1999 by Florian Klaempfl
+
+    Does parsing types 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 ptype;
+interface
+
+uses
+  globtype,symtable;
+
+
+    const
+       { forward types should only be possible inside a TYPE statement }
+       typecanbeforward : boolean = false;
+
+    var
+       { ttypesym read by read_type, this is needed to be
+         stored in the ppu for resolving purposes }
+       readtypesym : ptypesym;
+
+       { hack, which allows to use the current parsed }
+       { object type as function argument type  }
+       testcurobject : byte;
+       curobjectname : stringid;
+
+    { parses a string declaration }
+    function string_dec : pdef;
+
+    { parses a object declaration }
+    function object_dec(const n : stringid;fd : pobjectdef) : pdef;
+
+
+    { reads a string, file type or a type id and returns a name and }
+    { pdef                                                        }
+    function single_type(var s : string;isforwarddef:boolean) : pdef;
+
+    function read_type(const name : stringid) : pdef;
+
+
+implementation
+
+uses
+  cobjects,globals,verbose,systems,tokens,
+  aasm,symconst,types,
+{$ifdef GDB}
+  gdb,
+{$endif}
+  tree,hcodegen,hcgdata,
+  scanner,pbase,pexpr,pdecl,psub,
+  tccnv,pass_1;
+
+
+    function string_dec : pdef;
+    { reads a string type with optional length }
+    { and returns a pointer to the string      }
+    { definition                               }
+      var
+         p : ptree;
+         d : pdef;
+      begin
+         consume(_STRING);
+         if token=_LECKKLAMMER then
+           begin
+              consume(_LECKKLAMMER);
+              p:=comp_expr(true);
+              do_firstpass(p);
+              if not is_constintnode(p) then
+                Message(cg_e_illegal_expression);
+              if (p^.value<=0) then
+                begin
+                   Message(parser_e_invalid_string_size);
+                   p^.value:=255;
+                end;
+              consume(_RECKKLAMMER);
+              if p^.value>255 then
+                d:=new(pstringdef,longinit(p^.value))
+              else
+                if p^.value<>255 then
+                  d:=new(pstringdef,shortinit(p^.value))
+              else
+                d:=cshortstringdef;
+              disposetree(p);
+           end
+          else
+            begin
+               if cs_ansistrings in aktlocalswitches then
+                 d:=cansistringdef
+               else
+                 d:=cshortstringdef;
+            end;
+          string_dec:=d;
+       end;
+
+
+    function id_type(var s : string;isforwarddef:boolean) : pdef;
+    { reads a type definition and returns a pointer }
+    { to a appropriating pdef, s gets the name of   }
+    { the type to allow name mangling          }
+      var
+        is_unit_specific : boolean;
+      begin
+         s:=pattern;
+         consume(_ID);
+         { classes can be used also in classes }
+         if (curobjectname=pattern) and aktobjectdef^.is_class then
+           begin
+              id_type:=aktobjectdef;
+              exit;
+           end;
+         { objects can be parameters }
+         if (testcurobject=2) and (curobjectname=pattern) then
+           begin
+              id_type:=aktobjectdef;
+              exit;
+           end;
+         { try to load the symbol to see if it's a unitsym }
+         is_unit_specific:=false;
+         getsym(s,false);
+         if assigned(srsym) and
+            (srsym^.typ=unitsym) then
+           begin
+              consume(_POINT);
+              getsymonlyin(punitsym(srsym)^.unitsymtable,pattern);
+              s:=pattern;
+              consume(_ID);
+              is_unit_specific:=true;
+           end;
+         { are we parsing a possible forward def ? }
+         if isforwarddef and
+            not(is_unit_specific) then
+          begin
+            id_type:=new(pforwarddef,init(s));
+            exit;
+          end;
+         { unknown sym ? }
+         if not assigned(srsym) then
+          begin
+            Message1(sym_e_id_not_found,s);
+            id_type:=generrordef;
+            exit;
+          end;
+         if (srsym^.typ<>typesym) then
+          begin
+            Message(type_e_type_id_expected);
+            id_type:=generrordef;
+            exit;
+          end;
+         { can't use in [] here, becuase unitid can be > 255 }
+         if (ptypesym(srsym)^.owner^.unitid=0) or
+            (ptypesym(srsym)^.owner^.unitid=1) then
+          readtypesym:=nil
+         else
+          readtypesym:=ptypesym(srsym);
+         { return the definition of the type }
+         id_type:=ptypesym(srsym)^.definition;
+      end;
+
+
+    function single_type(var s : string;isforwarddef:boolean) : pdef;
+    { reads a string, file type or a type id and returns a name and }
+    { pdef                                                        }
+       var
+          hs : string;
+       begin
+          readtypesym:=nil;
+          case token of
+            _STRING:
+                begin
+                   single_type:=string_dec;
+                   s:='STRING';
+                   readtypesym:=nil;
+                end;
+            _FILE:
+                begin
+                   consume(_FILE);
+                   if token=_OF then
+                     begin
+                        consume(_OF);
+                        single_type:=new(pfiledef,init(ft_typed,single_type(hs,false)));
+                        s:='FILE$OF$'+hs;
+                     end
+                   else
+                     begin
+                        single_type:=cfiledef;
+                        s:='FILE';
+                     end;
+                   readtypesym:=nil;
+                end;
+            else
+              begin
+                single_type:=id_type(s,isforwarddef);
+              end;
+         end;
+      end;
+
+
+    function object_dec(const n : stringid;fd : pobjectdef) : pdef;
+    { this function parses an object or class declaration }
+      var
+         actmembertype : tsymoptions;
+         there_is_a_destructor : boolean;
+         is_a_class : boolean;
+         childof : pobjectdef;
+         aktclass : pobjectdef;
+
+      procedure constructor_head;
+
+        begin
+           consume(_CONSTRUCTOR);
+           { must be at same level as in implementation }
+           inc(lexlevel);
+           parse_proc_head(potype_constructor);
+           dec(lexlevel);
+
+           if (cs_constructor_name in aktglobalswitches) and (aktprocsym^.name<>'INIT') then
+            Message(parser_e_constructorname_must_be_init);
+
+{$ifdef INCLUDEOK}
+           include(aktclass^.objectoptions,oo_has_constructor);
+{$else}
+           aktclass^.objectoptions:=aktclass^.objectoptions+[oo_has_constructor];
+{$endif}
+           consume(_SEMICOLON);
+             begin
+                if (aktclass^.is_class) then
+                  begin
+                     { CLASS constructors return the created instance }
+                     aktprocsym^.definition^.retdef:=aktclass;
+                  end
+                else
+                  begin
+                     { OBJECT constructors return a boolean }
+{$IfDef GDB}
+                     {GDB doesn't like unnamed types !}
+                     aktprocsym^.definition^.retdef:=
+                       globaldef('boolean');
+{$Else GDB}
+                     aktprocsym^.definition^.retdef:=
+                        new(porddef,init(bool8bit,0,1));
+
+{$Endif GDB}
+                  end;
+             end;
+        end;
+
+
+      procedure property_dec;
+
+        var
+           sym : psym;
+           propertyparas : pdefcoll;
+
+        { returns the matching procedure to access a property }
+        function get_procdef : pprocdef;
+
+          var
+             p : pprocdef;
+
+          begin
+             p:=pprocsym(sym)^.definition;
+             get_procdef:=nil;
+             while assigned(p) do
+               begin
+                  if equal_paras(p^.para1,propertyparas,true) then
+                    break;
+                  p:=p^.nextoverloaded;
+               end;
+             get_procdef:=p;
+          end;
+
+          procedure deletepropsymlist(p : ppropsymlist);
+
+            var
+               hp : ppropsymlist;
+
+            begin
+               while assigned(p) do
+                 begin
+                    hp:=p;
+                    p:=p^.next;
+                    dispose(hp);
+                 end;
+            end;
+
+          procedure addpropsymlist(var root:ppropsymlist;s:psym);
+          var
+            last,hp : ppropsymlist;
+          begin
+            if not assigned(s) then
+             exit;
+            last:=root;
+            new(hp);
+            hp^.sym:=s;
+            hp^.next:=nil;
+            if assigned(last) then
+             begin
+               while assigned(last^.next) do
+                last:=last^.next;
+               last^.next:=hp;
+             end
+            else
+             root:=hp;
+          end;
+
+          function copypropsymlist(s:ppropsymlist):ppropsymlist;
+          var
+            root,last,hp : ppropsymlist;
+          begin
+            copypropsymlist:=nil;
+            if not assigned(s) then
+             exit;
+            last:=nil;
+            root:=nil;
+            while assigned(s) do
+             begin
+               new(hp);
+               hp^.sym:=s^.sym;
+               hp^.next:=nil;
+               if assigned(last) then
+                last^.next:=hp;
+               last:=hp;
+               if not assigned(root) then
+                root:=hp;
+               s:=s^.next;
+             end;
+            copypropsymlist:=root;
+          end;
+
+        var
+           hp2,datacoll : pdefcoll;
+           p,p2 : ppropertysym;
+           overriden : psym;
+           hs : string;
+           code : integer;
+           varspez : tvarspez;
+           sc : pstringcontainer;
+           hp : pdef;
+           s : string;
+           declarepos : tfileposinfo;
+           pp : pprocdef;
+           pt : ptree;
+           propname : stringid;
+
+        begin
+           { check for a class }
+           if not(aktclass^.is_class) then
+            Message(parser_e_syntax_error);
+           consume(_PROPERTY);
+           propertyparas:=nil;
+           datacoll:=nil;
+           if token=_ID then
+             begin
+                p:=new(ppropertysym,init(pattern));
+                propname:=pattern;
+                consume(_ID);
+                { property parameters ? }
+                if token=_LECKKLAMMER then
+                  begin
+                     if (sp_published in current_object_option) then
+                       Message(parser_e_cant_publish_that_property);
+
+                     { create a list of the parameters in propertyparas }
+                     consume(_LECKKLAMMER);
+                     inc(testcurobject);
+                     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);
+                            if token=_ARRAY then
+                              begin
+                                 {
+                                 if (varspez<>vs_const) and
+                                   (varspez<>vs_var) then
+                                   begin
+                                      varspez:=vs_const;
+                                      Message(parser_e_illegal_open_parameter);
+                                   end;
+                                 }
+                                 consume(_ARRAY);
+                                 consume(_OF);
+                                 { define range and type of range }
+                                 hp:=new(parraydef,init(0,-1,s32bitdef));
+                                 { define field type }
+                                 parraydef(hp)^.definition:=single_type(s,false);
+                              end
+                            else
+                              hp:=single_type(s,false);
+                         end
+                       else
+                         hp:=cformaldef;
+                       s:=sc^.get_with_tokeninfo(declarepos);
+                       while s<>'' do
+                         begin
+                            new(hp2);
+                            hp2^.paratyp:=varspez;
+                            hp2^.data:=hp;
+                            hp2^.next:=propertyparas;
+                            propertyparas:=hp2;
+                            s:=sc^.get_with_tokeninfo(declarepos);
+                         end;
+                       dispose(sc,done);
+                       if token=_SEMICOLON then consume(_SEMICOLON)
+                     else break;
+                     until false;
+                     dec(testcurobject);
+                     consume(_RECKKLAMMER);
+                  end;
+                { overriden property ?                                 }
+                { force property interface, if there is a property parameter }
+                if (token=_COLON) or assigned(propertyparas) then
+                  begin
+                     consume(_COLON);
+                     p^.proptype:=single_type(hs,false);
+                     if (idtoken=_INDEX) then
+                       begin
+                          consume(_INDEX);
+                          pt:=comp_expr(true);
+                          do_firstpass(pt);
+                          if not(is_ordinal(pt^.resulttype)) or
+                             is_64bitint(pt^.resulttype) then
+                            Message(parser_e_invalid_property_index_value);
+                          p^.index:=pt^.value;
+{$ifdef INCLUDEOK}
+                          include(p^.propoptions,ppo_indexed);
+{$else}
+                          p^.propoptions:=p^.propoptions+[ppo_indexed];
+{$endif}
+                          { concat a longint to the para template }
+                          new(hp2);
+                          hp2^.paratyp:=vs_value;
+                          hp2^.data:=pt^.resulttype;
+                          hp2^.next:=propertyparas;
+                          propertyparas:=hp2;
+                          disposetree(pt);
+                       end;
+                  end
+                else
+                  begin
+                     { do an property override }
+                     overriden:=search_class_member(aktclass,propname);
+                     if assigned(overriden) and (overriden^.typ=propertysym) then
+                       begin
+                          { take the whole info: }
+                          p^.propoptions:=ppropertysym(overriden)^.propoptions;
+                          p^.index:=ppropertysym(overriden)^.index;
+                          p^.proptype:=ppropertysym(overriden)^.proptype;
+                          p^.writeaccesssym:=copypropsymlist(ppropertysym(overriden)^.writeaccesssym);
+                          p^.readaccesssym:=copypropsymlist(ppropertysym(overriden)^.readaccesssym);
+                          p^.storedsym:=copypropsymlist(ppropertysym(overriden)^.storedsym);
+                          p^.writeaccessdef:=ppropertysym(overriden)^.writeaccessdef;
+                          p^.readaccessdef:=ppropertysym(overriden)^.readaccessdef;
+                          p^.storeddef:=ppropertysym(overriden)^.storeddef;
+                          p^.default:=ppropertysym(overriden)^.default;
+                       end
+                     else
+                       begin
+                          p^.proptype:=generrordef;
+                          message(parser_e_no_property_found_to_override);
+                       end;
+                  end;
+
+                if (sp_published in current_object_option) and
+                   not(p^.proptype^.is_publishable) then
+                  Message(parser_e_cant_publish_that_property);
+
+                { create data defcoll to allow correct parameter checks }
+                new(datacoll);
+                datacoll^.paratyp:=vs_value;
+                datacoll^.data:=p^.proptype;
+                datacoll^.next:=nil;
+
+                if (idtoken=_READ) then
+                  begin
+                     if assigned(p^.readaccesssym) then
+                       deletepropsymlist(p^.readaccesssym);
+                     p^.readaccesssym:=nil;
+                     consume(_READ);
+                     sym:=search_class_member(aktclass,pattern);
+                     if not(assigned(sym)) then
+                       begin
+                         Message1(sym_e_unknown_id,pattern);
+                         consume(_ID);
+                       end
+                     else
+                       begin
+                          consume(_ID);
+                          while (token=_POINT) and
+                                ((sym^.typ=varsym) and
+                                 (pvarsym(sym)^.definition^.deftype=recorddef)) do
+                           begin
+                             addpropsymlist(p^.readaccesssym,sym);
+                             consume(_POINT);
+                             getsymonlyin(precorddef(pvarsym(sym)^.definition)^.symtable,pattern);
+                             if not assigned(srsym) then
+                               Message1(sym_e_illegal_field,pattern);
+                             sym:=srsym;
+                             consume(_ID);
+                           end;
+                       end;
+
+                     if assigned(sym) then
+                       begin
+                          { varsym aren't allowed for an indexed property
+                            or an property with parameters }
+                          if ((sym^.typ=varsym) and
+                             { not necessary, an index forces propertyparas
+                               to be assigned
+                             }
+                             { (((p^.options and ppo_indexed)<>0) or }
+                             assigned(propertyparas)) or
+                             not(sym^.typ in [varsym,procsym]) then
+                            Message(parser_e_ill_property_access_sym);
+                          { search the matching definition }
+                          case sym^.typ of
+                            procsym :
+                              begin
+                                 pp:=get_procdef;
+                                 if not(assigned(pp)) or
+                                    not(is_equal(pp^.retdef,p^.proptype)) then
+                                   Message(parser_e_ill_property_access_sym);
+                                 p^.readaccessdef:=pp;
+                              end;
+                            varsym :
+                              begin
+                                if not(is_equal(pvarsym(sym)^.definition,p^.proptype)) then
+                                  Message(parser_e_ill_property_access_sym);
+                              end;
+                          end;
+                          addpropsymlist(p^.readaccesssym,sym);
+                       end;
+                  end;
+                if (idtoken=_WRITE) then
+                  begin
+                     if assigned(p^.writeaccesssym) then
+                       deletepropsymlist(p^.writeaccesssym);
+                     p^.writeaccesssym:=nil;
+                     consume(_WRITE);
+                     sym:=search_class_member(aktclass,pattern);
+                     if not(assigned(sym)) then
+                       begin
+                         Message1(sym_e_unknown_id,pattern);
+                         consume(_ID);
+                       end
+                     else
+                       begin
+                          consume(_ID);
+                          while (token=_POINT) and
+                                ((sym^.typ=varsym) and
+                                 (pvarsym(sym)^.definition^.deftype=recorddef)) do
+                           begin
+                             addpropsymlist(p^.writeaccesssym,sym);
+                             consume(_POINT);
+                             getsymonlyin(precorddef(pvarsym(sym)^.definition)^.symtable,pattern);
+                             if not assigned(srsym) then
+                               Message1(sym_e_illegal_field,pattern);
+                             sym:=srsym;
+                             consume(_ID);
+                           end;
+                       end;
+
+                     if assigned(sym) then
+                       begin
+                          if ((sym^.typ=varsym) and
+                             assigned(propertyparas)) or
+                             not(sym^.typ in [varsym,procsym]) then
+                            Message(parser_e_ill_property_access_sym);
+                          { search the matching definition }
+                          if sym^.typ=procsym then
+                            begin
+                               { insert data entry to check access method }
+                               datacoll^.next:=propertyparas;
+                               propertyparas:=datacoll;
+                               pp:=get_procdef;
+                               { ... and remove it }
+                               propertyparas:=propertyparas^.next;
+                               datacoll^.next:=nil;
+                               if not(assigned(pp)) then
+                                 Message(parser_e_ill_property_access_sym);
+                               p^.writeaccessdef:=pp;
+                            end
+                          else if sym^.typ=varsym then
+                            begin
+                               if not(is_equal(pvarsym(sym)^.definition,
+                                 p^.proptype)) then
+                                 Message(parser_e_ill_property_access_sym);
+                            end;
+                          addpropsymlist(p^.writeaccesssym,sym);
+                       end;
+                  end;
+                include(p^.propoptions,ppo_stored);
+                if (idtoken=_STORED) then
+                  begin
+                     consume(_STORED);
+                     if assigned(p^.storedsym) then
+                       deletepropsymlist(p^.storedsym);
+                     p^.storedsym:=nil;
+                     p^.storeddef:=nil;
+                     case token of
+                        _ID:
+                           { in the case that idtoken=_DEFAULT }
+                           { we have to do nothing except      }
+                           { setting ppo_stored, it's the same }
+                           { as stored true                    }
+                           if idtoken<>_DEFAULT then
+                             begin
+                                sym:=search_class_member(aktclass,pattern);
+                                if not(assigned(sym)) then
+                                  begin
+                                    Message1(sym_e_unknown_id,pattern);
+                                    consume(_ID);
+                                  end
+                                else
+                                  begin
+                                     consume(_ID);
+                                     while (token=_POINT) and
+                                           ((sym^.typ=varsym) and
+                                            (pvarsym(sym)^.definition^.deftype=recorddef)) do
+                                      begin
+                                        addpropsymlist(p^.storedsym,sym);
+                                        consume(_POINT);
+                                        getsymonlyin(precorddef(pvarsym(sym)^.definition)^.symtable,pattern);
+                                        if not assigned(srsym) then
+                                          Message1(sym_e_illegal_field,pattern);
+                                        sym:=srsym;
+                                        consume(_ID);
+                                      end;
+                                  end;
+
+                                if assigned(sym) then
+                                  begin
+                                     { only non array properties can be stored }
+                                     if assigned(propertyparas) or
+                                        not(sym^.typ in [varsym,procsym]) then
+                                       Message(parser_e_ill_property_storage_sym);
+                                     { search the matching definition }
+                                     if sym^.typ=procsym then
+                                       begin
+                                          pp:=pprocsym(sym)^.definition;
+                                          while assigned(pp) do
+                                            begin
+                                               { the stored function shouldn't have any parameters }
+                                               if not(assigned(pp^.para1)) then
+                                                 break;
+                                                pp:=pp^.nextoverloaded;
+                                            end;
+                                          { found we a procedure and does it really return a bool? }
+                                          if not(assigned(pp)) or
+                                             not(is_equal(pp^.retdef,booldef)) then
+                                            Message(parser_e_ill_property_storage_sym);
+                                          p^.storeddef:=pp;
+                                       end
+                                     else if sym^.typ=varsym then
+                                       begin
+                                          if not(is_equal(pvarsym(sym)^.definition,
+                                            booldef)) then
+                                            Message(parser_e_stored_property_must_be_boolean);
+                                       end;
+                                     addpropsymlist(p^.storedsym,sym);
+                                  end;
+                             end;
+                        _FALSE:
+                          begin
+                             consume(_FALSE);
+                             exclude(p^.propoptions,ppo_stored);
+                          end;
+                        _TRUE:
+                          consume(_TRUE);
+                     end;
+                  end;
+                if (idtoken=_DEFAULT) then
+                  begin
+                     consume(_DEFAULT);
+                     if not(is_ordinal(p^.proptype) or
+                         is_64bitint(p^.proptype) or
+                       ((p^.proptype^.deftype=setdef) and
+                        (psetdef(p^.proptype)^.settype=smallset)
+                       ) or
+                       assigned(propertyparas)
+                       ) then
+                       Message(parser_e_property_cant_have_a_default_value);
+                     { Get the result of the default, the firstpass is
+                       needed to support values like -1 }
+                     pt:=comp_expr(true);
+                     do_firstpass(pt);
+                     if p^.proptype^.deftype=setdef then
+                       begin
+{$ifndef newcg}
+                         {!!!!!!!!!!}
+                         arrayconstructor_to_set(pt);
+{$endif newcg}
+                         do_firstpass(pt);
+                       end;
+                     pt:=gentypeconvnode(pt,p^.proptype);
+                     do_firstpass(pt);
+                     if not(is_constnode(pt)) then
+                       Message(parser_e_property_default_value_must_const);
+
+                     if pt^.treetype=setconstn then
+                       p^.default:=plongint(pt^.value_set)^
+                     else
+                       p^.default:=pt^.value;
+                     disposetree(pt);
+                  end
+                else if (idtoken=_NODEFAULT) then
+                  begin
+                     consume(_NODEFAULT);
+                     p^.default:=0;
+                  end;
+                symtablestack^.insert(p);
+                { default property ? }
+                consume(_SEMICOLON);
+                if (idtoken=_DEFAULT) then
+                  begin
+                     consume(_DEFAULT);
+                     p2:=search_default_property(aktclass);
+                     if assigned(p2) then
+                       message1(parser_e_only_one_default_property,
+                         pobjectdef(p2^.owner^.defowner)^.objname^)
+                     else
+                       begin
+{$ifdef INCLUDEOK}
+                          include(p^.propoptions,ppo_defaultproperty);
+{$else}
+                          p^.propoptions:=p^.propoptions+[ppo_defaultproperty];
+{$endif}
+                          if not(assigned(propertyparas)) then
+                            message(parser_e_property_need_paras);
+                       end;
+                     consume(_SEMICOLON);
+                  end;
+                { clean up }
+                if assigned(datacoll) then
+                  disposepdefcoll(datacoll);
+             end
+           else
+             begin
+                consume(_ID);
+                consume(_SEMICOLON);
+             end;
+           if assigned(propertyparas) then
+             disposepdefcoll(propertyparas);
+        end;
+
+
+      procedure destructor_head;
+        begin
+           consume(_DESTRUCTOR);
+           inc(lexlevel);
+           parse_proc_head(potype_destructor);
+           dec(lexlevel);
+           if (cs_constructor_name in aktglobalswitches) and (aktprocsym^.name<>'DONE') then
+            Message(parser_e_destructorname_must_be_done);
+{$ifdef INCLUDEOK}
+           include(aktclass^.objectoptions,oo_has_destructor);
+{$else}
+           aktclass^.objectoptions:=aktclass^.objectoptions+[oo_has_destructor];
+{$endif}
+           consume(_SEMICOLON);
+           if assigned(aktprocsym^.definition^.para1) then
+            Message(parser_e_no_paras_for_destructor);
+           { no return value }
+           aktprocsym^.definition^.retdef:=voiddef;
+        end;
+
+      var
+         hs      : string;
+         pcrd       : pclassrefdef;
+         hp1    : pdef;
+         oldprocinfo : pprocinfo;
+         oldprocsym : pprocsym;
+         oldparse_only : boolean;
+         methodnametable,intmessagetable,
+         strmessagetable,classnamelabel : pasmlabel;
+         storetypecanbeforward : boolean;
+         vmtlist : taasmoutput;
+
+      begin
+         {Nowadays aktprocsym may already have a value, so we need to save
+          it.}
+         oldprocsym:=aktprocsym;
+         { forward is resolved }
+         if assigned(fd) then
+{$ifdef INCLUDEOK}
+           exclude(fd^.objectoptions,oo_is_forward);
+{$else}
+           fd^.objectoptions:=fd^.objectoptions-[oo_is_forward];
+{$endif}
+         there_is_a_destructor:=false;
+         actmembertype:=[sp_public];
+
+         { objects and class types can't be declared local }
+         if (symtablestack^.symtabletype<>globalsymtable) and
+           (symtablestack^.symtabletype<>staticsymtable) then
+           Message(parser_e_no_local_objects);
+
+         storetypecanbeforward:=typecanbeforward;
+         { for tp mode don't allow forward types }
+         if m_tp in aktmodeswitches then
+           typecanbeforward:=false;
+
+         { distinguish classes and objects }
+         if token=_OBJECT then
+           begin
+              is_a_class:=false;
+              consume(_OBJECT)
+           end
+         else
+           begin
+              is_a_class:=true;
+              consume(_CLASS);
+              if not(assigned(fd)) and (token=_OF) then
+                begin
+                   { a hack, but it's easy to handle }
+                   { class reference type }
+                   consume(_OF);
+                   hp1:=single_type(hs,typecanbeforward);
+
+                   { accept hp1, if is a forward def or a class }
+                   if (hp1^.deftype=forwarddef) or
+                      ((hp1^.deftype=objectdef) and pobjectdef(hp1)^.is_class) then
+                     begin
+                        pcrd:=new(pclassrefdef,init(hp1));
+                        object_dec:=pcrd;
+                     end
+                   else
+                     begin
+                        object_dec:=generrordef;
+                        Message1(type_e_class_type_expected,generrordef^.typename);
+                     end;
+                   typecanbeforward:=storetypecanbeforward;
+                   exit;
+                end
+              { forward class }
+              else if not(assigned(fd)) and (token=_SEMICOLON) then
+                begin
+                   { also anonym objects aren't allow (o : object a : longint; end;) }
+                   if n='' then
+                    begin
+                       Message(parser_f_no_anonym_objects)
+                    end;
+                   if n='TOBJECT' then
+                     begin
+                        aktclass:=new(pobjectdef,init(n,nil));
+                        class_tobject:=aktclass;
+                     end
+                   else
+                     aktclass:=new(pobjectdef,init(n,nil));
+                   aktclass^.objectoptions:=aktclass^.objectoptions+[oo_is_class,oo_is_forward];
+                   { all classes must have a vmt !!  at offset zero }
+                   if not(oo_has_vmt in aktclass^.objectoptions) then
+                     aktclass^.insertvmt;
+
+                   object_dec:=aktclass;
+                   typecanbeforward:=storetypecanbeforward;
+                   exit;
+                end;
+           end;
+
+         { also anonym objects aren't allow (o : object a : longint; end;) }
+         if n='' then
+           Message(parser_f_no_anonym_objects);
+
+         { read the parent class }
+         if token=_LKLAMMER then
+           begin
+              consume(_LKLAMMER);
+              childof:=pobjectdef(id_type(pattern,false));
+              if (childof^.deftype<>objectdef) then
+               begin
+                 Message1(type_e_class_type_expected,childof^.typename);
+                 childof:=nil;
+                 aktclass:=new(pobjectdef,init(n,nil));
+               end
+              else
+               begin
+                 { a mix of class and object isn't allowed }
+                 if (childof^.is_class and not is_a_class) or
+                    (not childof^.is_class and is_a_class) then
+                  Message(parser_e_mix_of_classes_and_objects);
+                 { the forward of the child must be resolved to get
+                   correct field addresses }
+                 if assigned(fd) then
+                  begin
+                    if (oo_is_forward in childof^.objectoptions) then
+                     Message1(parser_e_forward_declaration_must_be_resolved,childof^.objname^);
+                    aktclass:=fd;
+                    { we must inherit several options !!
+                      this was missing !!
+                      all is now done in set_parent
+                      including symtable datasize setting PM }
+                    fd^.set_parent(childof);
+                  end
+                 else
+                  aktclass:=new(pobjectdef,init(n,childof));
+               end;
+              consume(_RKLAMMER);
+           end
+         { if no parent class, then a class get tobject as parent }
+         else if is_a_class then
+           begin
+              { is the current class tobject?   }
+              { so you could define your own tobject }
+              if n='TOBJECT' then
+                begin
+                   if assigned(fd) then
+                     aktclass:=fd
+                   else
+                     aktclass:=new(pobjectdef,init(n,nil));
+                   class_tobject:=aktclass;
+                end
+              else
+                begin
+                   childof:=class_tobject;
+                   if assigned(fd) then
+                     begin
+                        { the forward of the child must be resolved to get
+                          correct field addresses
+                        }
+                        if (oo_is_forward in childof^.objectoptions) then
+                          Message1(parser_e_forward_declaration_must_be_resolved,childof^.objname^);
+                        aktclass:=fd;
+                        aktclass^.set_parent(childof);
+                     end
+                   else
+                     begin
+                        aktclass:=new(pobjectdef,init(n,childof));
+                        aktclass^.set_parent(childof);
+                     end;
+                end;
+           end
+         else
+           aktclass:=new(pobjectdef,init(n,nil));
+
+         { default access is public }
+         actmembertype:=[sp_public];
+
+         { set the class attribute }
+         if is_a_class then
+           begin
+{$ifdef INCLUDEOK}
+              include(aktclass^.objectoptions,oo_is_class);
+{$else}
+              aktclass^.objectoptions:=aktclass^.objectoptions+[oo_is_class];
+{$endif}
+              if (cs_generate_rtti in aktlocalswitches) or
+                  (assigned(aktclass^.childof) and
+                   (oo_can_have_published in aktclass^.childof^.objectoptions)) then
+                begin
+                   include(aktclass^.objectoptions,oo_can_have_published);
+                   { in "publishable" classes the default access type is published }
+                   actmembertype:=[sp_published];
+                   { don't know if this is necessary (FK) }
+                   current_object_option:=[sp_published];
+                end;
+           end;
+
+         aktobjectdef:=aktclass;
+         aktclass^.symtable^.next:=symtablestack;
+         symtablestack:=aktclass^.symtable;
+         testcurobject:=1;
+         curobjectname:=n;
+
+         { new procinfo }
+         oldprocinfo:=procinfo;
+         new(procinfo);
+         fillchar(procinfo^,sizeof(tprocinfo),0);
+         procinfo^._class:=aktclass;
+
+
+       { short class declaration ? }
+         if (not is_a_class) or (token<>_SEMICOLON) then
+          begin
+          { Parse componenten }
+            repeat
+              if (sp_private in actmembertype) then
+{$ifdef INCLUDEOK}
+                include(aktclass^.objectoptions,oo_has_private);
+{$else}
+                aktclass^.objectoptions:=aktclass^.objectoptions+[oo_has_private];
+{$endif}
+              if (sp_protected in actmembertype) then
+{$ifdef INCLUDEOK}
+                include(aktclass^.objectoptions,oo_has_protected);
+{$else}
+                aktclass^.objectoptions:=aktclass^.objectoptions+[oo_has_protected];
+{$endif}
+              case token of
+              _ID : begin
+                      case idtoken of
+                       _PRIVATE : begin
+                                    consume(_PRIVATE);
+                                    actmembertype:=[sp_private];
+                                    current_object_option:=[sp_private];
+                                  end;
+                     _PROTECTED : begin
+                                    consume(_PROTECTED);
+                                    current_object_option:=[sp_protected];
+                                    actmembertype:=[sp_protected];
+                                  end;
+                        _PUBLIC : begin
+                                    consume(_PUBLIC);
+                                    current_object_option:=[sp_public];
+                                    actmembertype:=[sp_public];
+                                  end;
+                     _PUBLISHED : begin
+                                    if not(oo_can_have_published in aktclass^.objectoptions) then
+                                     Message(parser_e_cant_have_published);
+                                    consume(_PUBLISHED);
+                                    current_object_option:=[sp_published];
+                                    actmembertype:=[sp_published];
+                                  end;
+                      else
+                        read_var_decs(false,true,false);
+                      end;
+                    end;
+        _PROPERTY : property_dec;
+       _PROCEDURE,
+        _FUNCTION,
+           _CLASS : begin
+                      oldparse_only:=parse_only;
+                      parse_only:=true;
+                      parse_proc_dec;
+{$ifndef newcg}
+                      parse_object_proc_directives(aktprocsym);
+{$endif newcg}
+                      if (po_msgint in aktprocsym^.definition^.procoptions) then
+{$ifdef INCLUDEOK}
+                        include(aktclass^.objectoptions,oo_has_msgint);
+{$else}
+                        aktclass^.objectoptions:=aktclass^.objectoptions+[oo_has_msgint];
+{$endif}
+                      if (po_msgstr in aktprocsym^.definition^.procoptions) then
+{$ifdef INCLUDEOK}
+                        include(aktclass^.objectoptions,oo_has_msgstr);
+{$else}
+                        aktclass^.objectoptions:=aktclass^.objectoptions+[oo_has_msgstr];
+{$endif}
+                      if (po_virtualmethod in aktprocsym^.definition^.procoptions) then
+{$ifdef INCLUDEOK}
+                        include(aktclass^.objectoptions,oo_has_virtual);
+{$else}
+                        aktclass^.objectoptions:=aktclass^.objectoptions+[oo_has_virtual];
+{$endif}
+                      parse_only:=oldparse_only;
+                    end;
+     _CONSTRUCTOR : begin
+                      if not(sp_public in actmembertype) then
+                        Message(parser_w_constructor_should_be_public);
+                      oldparse_only:=parse_only;
+                      parse_only:=true;
+                      constructor_head;
+{$ifndef newcg}
+                      parse_object_proc_directives(aktprocsym);
+{$endif newcg}
+                      if (po_virtualmethod in aktprocsym^.definition^.procoptions) then
+{$ifdef INCLUDEOK}
+                        include(aktclass^.objectoptions,oo_has_virtual);
+{$else}
+                        aktclass^.objectoptions:=aktclass^.objectoptions+[oo_has_virtual];
+{$endif}
+                      parse_only:=oldparse_only;
+                    end;
+      _DESTRUCTOR : begin
+                      if there_is_a_destructor then
+                        Message(parser_n_only_one_destructor);
+                      there_is_a_destructor:=true;
+                      if not(sp_public in actmembertype) then
+                        Message(parser_w_destructor_should_be_public);
+                      oldparse_only:=parse_only;
+                      parse_only:=true;
+                      destructor_head;
+{$ifndef newcg}
+                      parse_object_proc_directives(aktprocsym);
+{$endif newcg}
+                      if (po_virtualmethod in aktprocsym^.definition^.procoptions) then
+{$ifdef INCLUDEOK}
+                        include(aktclass^.objectoptions,oo_has_virtual);
+{$else}
+                        aktclass^.objectoptions:=aktclass^.objectoptions+[oo_has_virtual];
+{$endif}
+                      parse_only:=oldparse_only;
+                    end;
+             _END : begin
+                      consume(_END);
+                      break;
+                    end;
+              else
+               consume(_ID); { Give a ident expected message, like tp7 }
+              end;
+            until false;
+            current_object_option:=[sp_public];
+          end;
+         testcurobject:=0;
+         curobjectname:='';
+         typecanbeforward:=storetypecanbeforward;
+
+         { generate vmt space if needed }
+         if not(oo_has_vmt in aktclass^.objectoptions) and
+            ([oo_has_virtual,oo_has_constructor,oo_has_destructor,oo_is_class]*aktclass^.objectoptions<>[]) then
+           aktclass^.insertvmt;
+         if (cs_create_smart in aktmoduleswitches) then
+           datasegment^.concat(new(pai_cut,init));
+
+         { Write the start of the VMT, wich is equal for classes and objects }
+         if (oo_has_vmt in aktclass^.objectoptions) then
+           begin
+              { this generates the entries }
+              vmtlist.init;
+              genvmt(@vmtlist,aktclass);
+
+              { write tables for classes, this must be done before the actual
+                class is written, because we need the labels defined }
+              if is_a_class then
+               begin
+                 methodnametable:=genpublishedmethodstable(aktclass);
+                 { rtti }
+                 if (oo_can_have_published in aktclass^.objectoptions) then
+                  aktclass^.generate_rtti;
+                 { write class name }
+                 getdatalabel(classnamelabel);
+                 datasegment^.concat(new(pai_label,init(classnamelabel)));
+                 datasegment^.concat(new(pai_const,init_8bit(length(aktclass^.objname^))));
+                 datasegment^.concat(new(pai_string,init(aktclass^.objname^)));
+                 { generate message and dynamic tables }
+                 if (oo_has_msgstr in aktclass^.objectoptions) then
+                   strmessagetable:=genstrmsgtab(aktclass);
+                 if (oo_has_msgint in aktclass^.objectoptions) then
+                   intmessagetable:=genintmsgtab(aktclass)
+                 else
+                   datasegment^.concat(new(pai_const,init_32bit(0)));
+               end;
+
+             { write debug info }
+{$ifdef GDB}
+             if (cs_debuginfo in aktmoduleswitches) then
+              begin
+                do_count_dbx:=true;
+                if assigned(aktclass^.owner) and assigned(aktclass^.owner^.name) then
+                  datasegment^.concat(new(pai_stabs,init(strpnew('"vmt_'+aktclass^.owner^.name^+n+':S'+
+                    typeglobalnumber('__vtbl_ptr_type')+'",'+tostr(N_STSYM)+',0,0,'+aktclass^.vmt_mangledname))));
+              end;
+{$endif GDB}
+              datasegment^.concat(new(pai_symbol,initname_global(aktclass^.vmt_mangledname,0)));
+
+              { determine the size with symtable^.datasize, because }
+              { size gives back 4 for classes                    }
+              datasegment^.concat(new(pai_const,init_32bit(aktclass^.symtable^.datasize)));
+              datasegment^.concat(new(pai_const,init_32bit(-aktclass^.symtable^.datasize)));
+
+              { write pointer to parent VMT, this isn't implemented in TP }
+              { but this is not used in FPC ? (PM) }
+              { it's not used yet, but the delphi-operators as and is need it (FK) }
+              { it is not written for parents that don't have any vmt !! }
+              if assigned(aktclass^.childof) and
+                 (oo_has_vmt in aktclass^.childof^.objectoptions) then
+                datasegment^.concat(new(pai_const_symbol,initname(aktclass^.childof^.vmt_mangledname)))
+              else
+                datasegment^.concat(new(pai_const,init_32bit(0)));
+
+              { write extended info for classes, for the order see rtl/inc/objpash.inc }
+              if is_a_class then
+               begin
+                 { pointer to class name string }
+                 datasegment^.concat(new(pai_const_symbol,init(classnamelabel)));
+                 { pointer to dynamic table }
+                 if (oo_has_msgint in aktclass^.objectoptions) then
+                   datasegment^.concat(new(pai_const_symbol,init(intmessagetable)))
+                 else
+                   datasegment^.concat(new(pai_const,init_32bit(0)));
+                 { pointer to method table }
+                 if assigned(methodnametable) then
+                   datasegment^.concat(new(pai_const_symbol,init(methodnametable)))
+                 else
+                   datasegment^.concat(new(pai_const,init_32bit(0)));
+                 { pointer to field table }
+                 datasegment^.concat(new(pai_const,init_32bit(0)));
+                 { pointer to type info of published section }
+                 if (oo_can_have_published in aktclass^.objectoptions) then
+                   datasegment^.concat(new(pai_const_symbol,initname(aktclass^.rtti_name)))
+                 else
+                   datasegment^.concat(new(pai_const,init_32bit(0)));
+                 { inittable for con-/destruction }
+                 if aktclass^.needs_inittable then
+                   datasegment^.concat(new(pai_const_symbol,init(aktclass^.get_inittable_label)))
+                 else
+                   datasegment^.concat(new(pai_const,init_32bit(0)));
+                 { auto table }
+                 datasegment^.concat(new(pai_const,init_32bit(0)));
+                 { interface table }
+                 datasegment^.concat(new(pai_const,init_32bit(0)));
+                 { table for string messages }
+                 if (oo_has_msgstr in aktclass^.objectoptions) then
+                   datasegment^.concat(new(pai_const_symbol,init(strmessagetable)))
+                 else
+                   datasegment^.concat(new(pai_const,init_32bit(0)));
+               end;
+              datasegment^.concatlist(@vmtlist);
+              vmtlist.done;
+              { write the size of the VMT }
+              datasegment^.concat(new(pai_symbol_end,initname(aktclass^.vmt_mangledname)));
+           end;
+
+         { restore old state }
+         symtablestack:=symtablestack^.next;
+         aktobjectdef:=nil;
+         {Restore procinfo}
+         dispose(procinfo);
+         procinfo:=oldprocinfo;
+         {Restore the aktprocsym.}
+         aktprocsym:=oldprocsym;
+
+         object_dec:=aktclass;
+      end;
+
+
+    { reads a record declaration }
+    function record_dec : pdef;
+
+      var
+         symtable : psymtable;
+         storetypecanbeforward : boolean;
+
+      begin
+         { create recdef }
+         symtable:=new(psymtable,init(recordsymtable));
+         record_dec:=new(precorddef,init(symtable));
+         { update symtable stack }
+         symtable^.next:=symtablestack;
+         symtablestack:=symtable;
+         { parse record }
+         consume(_RECORD);
+         storetypecanbeforward:=typecanbeforward;
+         { for tp mode don't allow forward types }
+         if m_tp in aktmodeswitches then
+           typecanbeforward:=false;
+         read_var_decs(true,false,false);
+         consume(_END);
+         typecanbeforward:=storetypecanbeforward;
+         { may be scale record size to a size of n*4 ? }
+         symtablestack^.datasize:=align(symtablestack^.datasize,symtablestack^.dataalignment);
+         { restore symtable stack }
+         symtablestack:=symtable^.next;
+      end;
+
+
+    { reads a type definition and returns a pointer to it }
+    function read_type(const name : stringid) : pdef;
+      var
+        pt : ptree;
+        hp1,p : pdef;
+        aufdef : penumdef;
+        aufsym : penumsym;
+        ap : parraydef;
+        s : stringid;
+        l,v : longint;
+        oldaktpackrecords : tpackrecords;
+        hs : string;
+
+        procedure expr_type;
+        var
+           pt1,pt2 : ptree;
+        begin
+           { use of current parsed object ? }
+           if (token=_ID) and (testcurobject=2) and (curobjectname=pattern) then
+             begin
+                consume(_ID);
+                p:=aktobjectdef;
+                exit;
+             end;
+           { we can't accept a equal in type }
+           pt1:=comp_expr(not(ignore_equal));
+           do_firstpass(pt1);
+           if (token=_POINTPOINT) then
+             begin
+               consume(_POINTPOINT);
+               { get high value of range }
+               pt2:=comp_expr(not(ignore_equal));
+               do_firstpass(pt2);
+               { both must be evaluated to constants now }
+               if (pt1^.treetype<>ordconstn) or (pt2^.treetype<>ordconstn) then
+                 Message(sym_e_error_in_type_def)
+               else
+                 begin
+                 { check types }
+                   if CheckTypes(pt1^.resulttype,pt2^.resulttype) then
+                     begin
+                     { Check bounds }
+                       if pt2^.value<pt1^.value then
+                         Message(cg_e_upper_lower_than_lower)
+                       else
+                        begin
+                        { All checks passed, create the new def }
+                          case pt1^.resulttype^.deftype of
+                           enumdef : p:=new(penumdef,init_subrange(penumdef(pt1^.resulttype),pt1^.value,pt2^.value));
+                            orddef : begin
+                                       if is_char(pt1^.resulttype) then
+                                         p:=new(porddef,init(uchar,pt1^.value,pt2^.value))
+                                       else
+                                        if is_boolean(pt1^.resulttype) then
+                                         p:=new(porddef,init(bool8bit,pt1^.value,pt2^.value))
+                                       else
+                                        p:=new(porddef,init(uauto,pt1^.value,pt2^.value));
+                                     end;
+                          end;
+                        end;
+                     end;
+                 end;
+               disposetree(pt2);
+             end
+           else
+             begin
+               { a simple type renaming }
+               if (pt1^.treetype=typen) then
+                 begin
+                   p:=pt1^.resulttype;
+                   readtypesym:=pt1^.typenodesym;
+                 end
+               else
+                 Message(sym_e_error_in_type_def);
+             end;
+           disposetree(pt1);
+        end;
+
+        procedure array_dec;
+        var
+          lowval,
+          highval   : longint;
+          arraytype : pdef;
+        begin
+           consume(_ARRAY);
+           consume(_LECKKLAMMER);
+           { defaults }
+           arraytype:=generrordef;
+           lowval:=$80000000;
+           highval:=$7fffffff;
+           p:=nil;
+           repeat
+             { read the expression and check it }
+             pt:=expr;
+             if pt^.treetype=typen then
+               begin
+                 case pt^.resulttype^.deftype of
+                   enumdef :
+                     begin
+                       lowval:=penumdef(pt^.resulttype)^.min;
+                       highval:=penumdef(pt^.resulttype)^.max;
+                       arraytype:=pt^.resulttype;
+                     end;
+                   orddef :
+                     begin
+                       lowval:=porddef(pt^.resulttype)^.low;
+                       highval:=porddef(pt^.resulttype)^.high;
+                       arraytype:=pt^.resulttype;
+                     end;
+                   else
+                     Message(sym_e_error_in_type_def);
+                 end;
+               end
+             else
+               begin
+                  do_firstpass(pt);
+                  if (pt^.treetype=rangen) then
+                   begin
+                     if (pt^.left^.treetype=ordconstn) and
+                        (pt^.right^.treetype=ordconstn) then
+                      begin
+                        lowval:=pt^.left^.value;
+                        highval:=pt^.right^.value;
+                        if highval<lowval then
+                         begin
+                           Message(parser_e_array_lower_less_than_upper_bound);
+                           highval:=lowval;
+                         end;
+                        arraytype:=pt^.right^.resulttype;
+                      end
+                     else
+                      Message(type_e_cant_eval_constant_expr);
+                   end
+                  else
+                   Message(sym_e_error_in_type_def)
+               end;
+             disposetree(pt);
+
+           { create arraydef }
+             if p=nil then
+              begin
+                ap:=new(parraydef,init(lowval,highval,arraytype));
+                p:=ap;
+              end
+             else
+              begin
+                ap^.definition:=new(parraydef,init(lowval,highval,arraytype));
+                ap:=parraydef(ap^.definition);
+              end;
+
+             if token=_COMMA then
+               consume(_COMMA)
+             else
+               break;
+           until false;
+           consume(_RECKKLAMMER);
+           consume(_OF);
+           hp1:=read_type('');
+           { if no error, set element type }
+           if assigned(ap) then
+             ap^.definition:=hp1;
+        end;
+
+      begin
+         readtypesym:=nil;
+         p:=nil;
+         case token of
+            _STRING,_FILE:
+              begin
+                p:=single_type(hs,false);
+                readtypesym:=nil;
+              end;
+           _LKLAMMER:
+              begin
+                 consume(_LKLAMMER);
+                 { allow negativ value_str }
+                 l:=-1;
+                 aufsym := Nil;
+                 aufdef:=new(penumdef,init);
+                 repeat
+                   s:=pattern;
+                   consume(_ID);
+                   if token=_ASSIGNMENT then
+                     begin
+                        consume(_ASSIGNMENT);
+                        v:=get_intconst;
+                        { please leave that a note, allows type save }
+                        { declarations in the win32 units !       }
+                        if v<=l then
+                         Message(parser_n_duplicate_enum);
+                        l:=v;
+                     end
+                   else
+                     inc(l);
+                   constsymtable^.insert(new(penumsym,init(s,aufdef,l)));
+                   if token=_COMMA then
+                     consume(_COMMA)
+                   else
+                     break;
+                 until false;
+                 {aufdef^.max:=l;
+                 if we allow unordered enums
+                 this can be wrong
+                 min and max are now set in tenumsym.init PM }
+                 p:=aufdef;
+                 consume(_RKLAMMER);
+                readtypesym:=nil;
+              end;
+            _ARRAY:
+              begin
+                array_dec;
+                readtypesym:=nil;
+              end;
+            _SET:
+              begin
+                consume(_SET);
+                consume(_OF);
+                hp1:=read_type('');
+                if assigned(hp1) then
+                 begin
+                   case hp1^.deftype of
+                     { don't forget that min can be negativ  PM }
+                     enumdef :
+                       if penumdef(hp1)^.min>=0 then
+                        p:=new(psetdef,init(hp1,penumdef(hp1)^.max))
+                       else
+                        Message(sym_e_ill_type_decl_set);
+                     orddef :
+                       begin
+                         case porddef(hp1)^.typ of
+                           uchar :
+                             p:=new(psetdef,init(hp1,255));
+                           u8bit,u16bit,u32bit,
+                           s8bit,s16bit,s32bit :
+                             begin
+                               if (porddef(hp1)^.low>=0) then
+                                p:=new(psetdef,init(hp1,porddef(hp1)^.high))
+                               else
+                                Message(sym_e_ill_type_decl_set);
+                             end;
+                           else
+                             Message(sym_e_ill_type_decl_set);
+                         end;
+                       end;
+                     else
+                       Message(sym_e_ill_type_decl_set);
+                   end;
+                 end
+                else
+                 p:=generrordef;
+                readtypesym:=nil;
+              end;
+           _CARET:
+              begin
+                consume(_CARET);
+                hp1:=single_type(hs,typecanbeforward);
+                p:=new(ppointerdef,init(hp1));
+                readtypesym:=nil;
+              end;
+            _RECORD:
+              begin
+                p:=record_dec;
+                readtypesym:=nil;
+              end;
+            _PACKED:
+              begin
+                consume(_PACKED);
+                if token=_ARRAY then
+                  array_dec
+                else
+                  begin
+                    oldaktpackrecords:=aktpackrecords;
+                    aktpackrecords:=packrecord_1;
+                    if token in [_CLASS,_OBJECT] then
+                      p:=object_dec(name,nil)
+                    else
+                      p:=record_dec;
+                    aktpackrecords:=oldaktpackrecords;
+                  end;
+                readtypesym:=nil;
+              end;
+            _CLASS,
+            _OBJECT:
+              begin
+                p:=object_dec(name,nil);
+                readtypesym:=nil;
+              end;
+            _PROCEDURE:
+              begin
+                consume(_PROCEDURE);
+                p:=new(pprocvardef,init);
+                if token=_LKLAMMER then
+                 parameter_dec(pprocvardef(p));
+                if token=_OF then
+                  begin
+                    consume(_OF);
+                    consume(_OBJECT);
+{$ifdef INCLUDEOK}
+                    include(pprocvardef(p)^.procoptions,po_methodpointer);
+{$else}
+                    pprocvardef(p)^.procoptions:=pprocvardef(p)^.procoptions+[po_methodpointer];
+{$endif}
+                  end;
+                readtypesym:=nil;
+              end;
+            _FUNCTION:
+              begin
+                consume(_FUNCTION);
+                p:=new(pprocvardef,init);
+                if token=_LKLAMMER then
+                 parameter_dec(pprocvardef(p));
+                consume(_COLON);
+                pprocvardef(p)^.retdef:=single_type(hs,false);
+                if token=_OF then
+                  begin
+                    consume(_OF);
+                    consume(_OBJECT);
+{$ifdef INCLUDEOK}
+                    include(pprocvardef(p)^.procoptions,po_methodpointer);
+{$else}
+                    pprocvardef(p)^.procoptions:=pprocvardef(p)^.procoptions+[po_methodpointer];
+{$endif}
+                  end;
+                readtypesym:=nil;
+              end;
+            else
+              expr_type;
+         end;
+         if p=nil then
+          p:=generrordef;
+         read_type:=p;
+      end;
+
+end.
+{
+  $Log$
+  Revision 1.1  1999-10-22 10:39:35  peter
+    * split type reading from pdecl to ptype unit
+    * parameter_dec routine is now used for procedure and procvars
+
+}

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно