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;
|