A r t i c l e s
Navigation

Note: This site is
a bit older, personal views
may have changed.

M a i n P a g e

D i r e c t o r y

FPC Read_Exports


This is part of the parsing for FPC. Explaining the source code to the free pascal compiler in English, will help people who are keen on learning how compilers work. Sometimes the source code comments aren't enough for someone who hasn't seen the code before.
This procedure is called when the compiler parses the "exports" keyword. After parsing the exports keyword, each procedure or function, separated by commas, is then dealt with appropriately until a semi-colon is hit. --L505

    procedure read_exports;
      var
        hp        : texported_item;
        orgs,
        DefString : string;
        InternalProcName : string;
        pt               : tnode;
        srsym            : tsym;
        srsymtable : tsymtable;

        function IsGreater(hp1,hp2:texported_item):boolean;
        var
          i2 : boolean;
        begin
          i2:=(hp2.options and eo_index)<>0;
          if (hp1.options and eo_index)<>0 then
           begin
             if i2 then
               IsGreater:=hp1.index>hp2.index
             else
               IsGreater:=false;
           end
          else
            IsGreater:=i2;
        end;

      begin
         DefString:='';
         InternalProcName:='';
         // try to find (eat up) the word 'exports' in the code
         consume(_EXPORTS);
         repeat
           hp:=texported_item.create;
           if token=_ID then
             begin
                orgs:=orgpattern;
                consume_sym(srsym,srsymtable);
                hp.sym:=srsym;
                InternalProcName:='';
                case srsym.typ of  
                //is it a global var, a constant, or a procedure/function that we are 
                //trying to export in the code, after the exports keyword...
                  globalvarsym :
                    InternalProcName:=tglobalvarsym(srsym).mangledname;
                  typedconstsym :
                    InternalProcName:=ttypedconstsym(srsym).mangledname;
                  procsym :
                    begin
                      if (Tprocsym(srsym).procdef_count>1) or
                         ((tf_need_export in target_info.flags) and
                          not(po_exports in tprocsym(srsym).first_procdef.procoptions)) then
                        Message(parser_e_illegal_symbol_exported)
                      else
                        InternalProcName:=tprocsym(srsym).first_procdef.mangledname;
                    end;
                  else
                    Message(parser_e_illegal_symbol_exported)
                end;
                if InternalProcName<>'' then
                 begin
                   { This is wrong if the first is not
                     an underline }
                   if InternalProcName[1]='_' then
                     delete(InternalProcName,1,1)
                   //if the system is dos or win32
                   else if (target_info.system in system_i386_win32,system_i386_wdosx) and UseDeffileForExports then
                     begin
                       Message(parser_e_dlltool_unit_var_problem);
                       Message(parser_e_dlltool_unit_var_problem2);
                     end;
                   if length(InternalProcName)<2 then
                    Message(parser_e_procname_to_short_for_export);
                   DefString:=srsym.realname+'='+InternalProcName;
                 end;
                if try_to_consume(_INDEX) then
                 begin
                   pt:=comp_expr(true);
                   if pt.nodetype=ordconstn then
                    hp.index:=tordconstnode(pt).value
                   else
                    begin
                      hp.index:=0;
                      consume(_INTCONST);
                    end;
                   hp.options:=hp.options or eo_index;
                   pt.free;
                   //only on windows and dos systems... 
                   if target_info.system in system_i386_win32,system_i386_wdosx then
                    DefString:=srsym.realname+'='+InternalProcName+' @ '+tostr(hp.index)
                   else
                    DefString:=srsym.realname+'='+InternalProcName; {Index ignored!}
                 end;
                //compiler tries to find the "name" keyword after export procedure/function is declared
                if try_to_consume(_NAME) then
                 begin
                   pt:=comp_expr(true);
                   //if a string was found after the 'name' keyword
                   if pt.nodetype=stringconstn then
                    hp.name:=stringdup(strpas(tstringconstnode(pt).value_str))
                   else
                    begin
                      hp.name:=stringdup('');
                      consume(_CSTRING);
                    end;
                   hp.options:=hp.options or eo_name;
                   pt.free;
                   DefString:=hp.name^+'='+InternalProcName;
                 end;
                if try_to_consume(_RESIDENT) then
                 begin
                   hp.options:=hp.options or eo_resident;
                   DefString:=srsym.realname+'='+InternalProcName;{Resident ignored!}
                 end;
                //if deffile is used (for MS Windows and OS/2)
                if (DefString<>'') and UseDeffileForExports then
                 DefFile.AddExport(DefString);
                { Default to generate a name entry with the provided name }
                if not assigned(hp.name) then
                 begin
                   hp.name:=stringdup(orgs);
                   hp.options:=hp.options or eo_name;
                 end;
                if hp.sym.typ=procsym then
                  exportlib.exportprocedure(hp)
                else
                  exportlib.exportvar(hp);
             end
           else
             consume(_ID);
         //repeat the routine after each comma, which separates each export
         until not try_to_consume(_COMMA);
         //end of exports section when we hit semicolon (;)
         consume(_SEMICOLON);
        if not DefFile.empty then
         DefFile.writefile;
      end;






About
This site is about programming and other things.
_ _ _