mirror of
https://github.com/byteworksinc/ORCA-C.git
synced 2024-08-31 23:28:55 +00:00
There were a couple issues here: *If the type name contained a semicolon (for struct/union member declarations), a spurious error would be reported. *Tags or enumeration constants declared in the type name should be in scope within the loop, but were not. These both stemmed from the way the parser handled the third expression, which was to save the tokens from it and re-inject them at the end of the loop. To get the scope issues right, the expression really needs to be evaluated at the point where it occurs, so we now do that. To enable that while still placing the code at the end of the loop, a mechanism to remove and re-insert sections of generated code is introduced. Here is an example illustrating the issues: int main(void) { int i, j, x; for (i = 0; i < 123; i += sizeof(struct {int a;})) for (j = 0; j < 123; j += sizeof(enum E {A,B,C})) x = i + j + A; }
4797 lines
177 KiB
ObjectPascal
4797 lines
177 KiB
ObjectPascal
{$optimize 1}
|
|
{---------------------------------------------------------------}
|
|
{ }
|
|
{ Parser }
|
|
{ }
|
|
{ External Subroutines: }
|
|
{ }
|
|
{ DoDeclaration - process a variable or function declaration }
|
|
{ DoStatement - process a statement from a function }
|
|
{ AutoInit - generate code to initialize an auto variable }
|
|
{ InitParser - initialize the parser }
|
|
{ Match - insure that the next token is of the specified type }
|
|
{ TermParser - shut down the parser }
|
|
{ DeclarationSpecifiers - handle a type specifier }
|
|
{ }
|
|
{---------------------------------------------------------------}
|
|
|
|
unit Parser;
|
|
|
|
{$LibPrefix '0/obj/'}
|
|
|
|
interface
|
|
|
|
uses CCommon, Table, MM, CGI, Scanner, Header, Symbol, Expression, Asm;
|
|
|
|
{$segment 'parser'}
|
|
|
|
{---------------------------------------------------------------}
|
|
|
|
procedure DoDeclaration (doingPrototypes: boolean);
|
|
|
|
{ process a variable or function declaration }
|
|
{ }
|
|
{ parameters: }
|
|
{ doingPrototypes - are we processing a parameter list? }
|
|
|
|
|
|
procedure DoStatement;
|
|
|
|
{ process a statement from a function }
|
|
|
|
|
|
function TypeName: typePtr;
|
|
|
|
{ process a type name (used for casts and sizeof/_Alignof) }
|
|
{ }
|
|
{ returns: a pointer to the type }
|
|
|
|
|
|
procedure AutoInit (variable: identPtr; line: longint;
|
|
isCompoundLiteral: boolean);
|
|
|
|
{ generate code to initialize an auto variable }
|
|
{ }
|
|
{ parameters: }
|
|
{ variable - the variable to initialize }
|
|
{ line - line number (used for debugging) }
|
|
{ isCompoundLiteral - initializing a compound literal? }
|
|
|
|
|
|
function MakeFuncIdentifier: identPtr;
|
|
|
|
{ Make the predefined identifier __func__. }
|
|
{ }
|
|
{ It is inserted in the symbol table as if the following }
|
|
{ declaration appeared at the beginning of the function body: }
|
|
{ }
|
|
{ static const char __func__[] = "function-name"; }
|
|
{ }
|
|
{ This must only be called within a function body. }
|
|
|
|
|
|
function MakeCompoundLiteral(tp: typePtr): identPtr;
|
|
|
|
{ Make the identifier for a compound literal. }
|
|
{ }
|
|
{ parameters: }
|
|
{ tp - the type of the compound literal }
|
|
|
|
|
|
procedure InitParser;
|
|
|
|
{ Initialize the parser }
|
|
|
|
|
|
procedure Match (kind: tokenEnum; err: integer);
|
|
|
|
{ insure that the next token is of the specified type }
|
|
{ }
|
|
{ parameters: }
|
|
{ kind - expected token kind }
|
|
{ err - error number if the expected token is not found }
|
|
|
|
|
|
procedure TermParser;
|
|
|
|
{ shut down the parser }
|
|
|
|
{---------------------------------------------------------------}
|
|
|
|
implementation
|
|
|
|
const
|
|
maxBitField = 32; {max # of bits in a bit field}
|
|
|
|
type
|
|
|
|
identList = ^identNode; {list of ids; used for initializers}
|
|
identNode = record
|
|
next: identList;
|
|
id: identPtr;
|
|
end;
|
|
|
|
{ The switch record is used to record the values for the }
|
|
{ switch jump table. The linked list of entries is in order }
|
|
{ of increasing switch value (val). }
|
|
|
|
switchPtr = ^switchRecord; {switch label table entry}
|
|
switchRecord = record
|
|
next,last: switchPtr; {doubly linked list (for inserts)}
|
|
lab: integer; {label to branch to}
|
|
val: longlong; {switch value}
|
|
end;
|
|
|
|
{statement stack}
|
|
{---------------}
|
|
statementPtr = ^statementRecord;
|
|
{kinds of nestable statements}
|
|
statementKind = (compoundSt,ifSt,elseSt,doSt,whileSt,forSt,switchSt);
|
|
statementRecord = record {element of the statement stack}
|
|
next: statementPtr; {next element on the stack}
|
|
breakLab, continueLab: integer; {branch points for break, continue}
|
|
case kind: statementKind of
|
|
compoundSt: (
|
|
doingDeclaration: boolean; {doing declarations? (or statements)}
|
|
lFenvAccess: boolean; {previous value of fenvAccess just}
|
|
);
|
|
ifSt: (
|
|
ifLab: integer; {branch point}
|
|
);
|
|
elseSt: (
|
|
elseLab: integer; {branch point}
|
|
);
|
|
doSt: (
|
|
doLab: integer; {branch point}
|
|
);
|
|
whileSt: (
|
|
whileTop: integer; {label at top of while loop}
|
|
whileEnd: integer; {label at bottom of while loop}
|
|
);
|
|
forSt: (
|
|
forLoop: integer; {branch here to loop}
|
|
e3Code: codeRef; {code for last expression}
|
|
);
|
|
switchSt: (
|
|
maxVal: longint; {max switch value}
|
|
ln: integer; {temp var number}
|
|
size: integer; {temp var size}
|
|
labelCount: integer; {# of switch labels}
|
|
switchExit: integer; {branch point}
|
|
switchLab: integer; {branch point}
|
|
switchList: switchPtr; {list of labels and values}
|
|
switchDefault: integer; {default branch point}
|
|
);
|
|
end;
|
|
|
|
{type info for a declaration}
|
|
{---------------------------}
|
|
declSpecifiersRecord = record
|
|
storageClass: tokenEnum; {storage class of the declaration}
|
|
typeSpec: typePtr; {type specifier}
|
|
declarationModifiers: tokenSet; {all storage class specifiers, type }
|
|
{qualifiers, function specifiers, & }
|
|
{alignment specifiers in declaration}
|
|
end;
|
|
|
|
var
|
|
anonNumber: integer; {number for next anonymous struct/union}
|
|
firstCompoundStatement: boolean; {are we doing a function level compound statement?}
|
|
fType: typePtr; {return type of the current function}
|
|
functionName: stringPtr; {name of the current function}
|
|
isForwardDeclared: boolean; {is the field list component }
|
|
{ referencing a forward struct/union? }
|
|
isFunction: boolean; {is the declaration a function?}
|
|
returnLabel: integer; {label for exit point}
|
|
statementList: statementPtr; {list of open statements}
|
|
savedVolatile: boolean; {saved copy of volatile}
|
|
doingForLoopClause1: boolean; {doing the first clause of a for loop?}
|
|
compoundLiteralNumber: integer; {number of compound literal}
|
|
compoundLiteralToAllocate: identPtr; {compound literal that needs space allocated}
|
|
vaInfoLLN: integer; {label number of internal va info (0 for none)}
|
|
declaredTagOrEnumConst: boolean; {was a tag or enum const declared?}
|
|
returnCount: integer; {number of return statements}
|
|
skipReturn: boolean; {skip the ordinary return at end of function?}
|
|
structReturnVar: identPtr; {static variable to hold a struct/union return value}
|
|
|
|
{parameter processing variables}
|
|
{------------------------------}
|
|
lastParameter: identPtr; {next parameter to process}
|
|
numberOfParameters: integer; {number of indeclared parameters}
|
|
pfunc: identPtr; {func. for which parms are being defined}
|
|
protoType: typePtr; {type from a parameter list}
|
|
protoVariable: identPtr; {variable from a parameter list}
|
|
|
|
{syntactic classes of tokens}
|
|
{---------------------------}
|
|
{ specifierQualifierListElement: tokenSet; (in CCommon)}
|
|
{ topLevelDeclarationStart: tokenSet; (in CCommon)}
|
|
localDeclarationStart: tokenSet;
|
|
declarationSpecifiersElement: tokenSet;
|
|
structDeclarationStart: tokenSet;
|
|
|
|
{-- External procedures ----------------------------------------}
|
|
|
|
function slt64(a,b: longlong): boolean; extern;
|
|
|
|
function sgt64(a,b: longlong): boolean; extern;
|
|
|
|
{-- External conversion functions; imported from CGC.pas -------}
|
|
|
|
procedure CnvXLL (var result: longlong; val: extended); extern;
|
|
|
|
procedure CnvXULL (var result: longlong; val: extended); extern;
|
|
|
|
function CnvLLX (val: longlong): extended; extern;
|
|
|
|
function CnvULLX (val: longlong): extended; extern;
|
|
|
|
{-- Parser Utility Procedures ----------------------------------}
|
|
|
|
procedure Match {kind: tokenEnum; err: integer};
|
|
|
|
{ insure that the next token is of the specified type }
|
|
{ }
|
|
{ parameters: }
|
|
{ kind - expected token kind }
|
|
{ err - error number if the expected token is not found }
|
|
|
|
begin {Match}
|
|
if token.kind = kind then
|
|
NextToken
|
|
else
|
|
Error(err);
|
|
end; {Match}
|
|
|
|
|
|
procedure SkipStatement;
|
|
|
|
{ Skip the remainder of the current statement }
|
|
|
|
var
|
|
bracketCount: integer; {for error skip}
|
|
|
|
begin {SkipStatement}
|
|
bracketCount := 0;
|
|
while (token.kind <> eofsy) and
|
|
((token.kind <> semicolonch) or (bracketCount <> 0)) do begin
|
|
if token.kind = lbrackch then
|
|
bracketCount := bracketCount+1;
|
|
if token.kind = rbrackch then
|
|
if bracketCount <> 0 then
|
|
bracketCount := bracketCount-1;
|
|
NextToken;
|
|
end; {while}
|
|
if token.kind = semicolonch then
|
|
NextToken;
|
|
end; {SkipStatement}
|
|
|
|
|
|
procedure GotoLabel (op: pcodes);
|
|
|
|
{ Find a label in the goto label list, creating one if one }
|
|
{ does not already exist. Generate the label or a jump to it }
|
|
{ based on op. }
|
|
{ }
|
|
{ parameters: }
|
|
{ op - operation code to create }
|
|
|
|
label 1;
|
|
|
|
var
|
|
gt: gotoPtr; {work pointer}
|
|
|
|
begin {GotoLabel}
|
|
gt := gotoList; {try to find an existing label}
|
|
while gt <> nil do begin
|
|
if gt^.name^ = token.name^ then
|
|
goto 1;
|
|
gt := gt^.next;
|
|
end; {while}
|
|
gt := pointer(Malloc(sizeof(gotoRecord))); {no label record exists: create one}
|
|
gt^.next := gotoList;
|
|
gotoList := gt;
|
|
gt^.name := token.name;
|
|
gt^.lab := GenLabel;
|
|
gt^.defined := false;
|
|
1:
|
|
if op = dc_lab then begin
|
|
if gt^.defined then
|
|
Error(77)
|
|
else begin
|
|
gt^.defined := true;
|
|
Gen1(dc_lab, gt^.lab);
|
|
end; {else}
|
|
end {if}
|
|
else
|
|
Gen1(pc_ujp, gt^.lab);
|
|
end; {GotoLabel}
|
|
|
|
|
|
{-- Statements -------------------------------------------------}
|
|
|
|
procedure CompoundStatement (makeSymbols: boolean);
|
|
|
|
{ handle a compound statement }
|
|
{ }
|
|
{ Parameters: }
|
|
{ makeSymbols - create a symbol table? (False for a }
|
|
{ function's outer wrapper, true for imbedded statements) }
|
|
|
|
var
|
|
stPtr: statementPtr; {for creating a compound statement record}
|
|
|
|
begin {CompoundStatement}
|
|
new(stPtr); {create a statement record}
|
|
stPtr^.lFenvAccess := fenvAccess; {save existing value of fenvAccess}
|
|
Match(lbracech,27); {make sure there is an opening '{'}
|
|
stPtr^.next := statementList;
|
|
statementList := stPtr;
|
|
stPtr^.kind := compoundSt;
|
|
if makeSymbols then {create a symbol table}
|
|
PushTable;
|
|
stPtr^.doingDeclaration := true; {allow declarations}
|
|
end; {CompoundStatement}
|
|
|
|
|
|
procedure EndCompoundStatement;
|
|
|
|
{ finish off a compound statement }
|
|
|
|
var
|
|
dumpLocal: boolean; {dump the local memory pool?}
|
|
tl: tempPtr; {work pointer}
|
|
stPtr: statementPtr; {work pointer}
|
|
|
|
begin {EndCompoundStatement}
|
|
while compoundLiteralToAllocate <> nil do begin {allocate compound literals}
|
|
Gen2(dc_loc, compoundLiteralToAllocate^.lln,
|
|
long(compoundLiteralToAllocate^.itype^.size).lsw);
|
|
compoundLiteralToAllocate := compoundLiteralToAllocate^.clnext;
|
|
end {while};
|
|
dumpLocal := false;
|
|
stPtr := statementList; {pop the statement record}
|
|
statementList := stPtr^.next;
|
|
doingFunction := statementList <> nil; {see if we're done with the function}
|
|
if not doingFunction then begin {if so, finish it off}
|
|
if not skipReturn then begin
|
|
if doingMain then begin {executing to the end of main returns 0}
|
|
if fType^.kind = scalarType then begin
|
|
if fType^.baseType in [cgByte,cgUByte,cgWord,cgUWord] then begin
|
|
Gen1t(pc_ldc, 0, fType^.baseType);
|
|
Gen2t(pc_str, 0, 0, fType^.baseType);
|
|
end {if}
|
|
else if fType^.baseType in [cgLong,cgULong] then begin
|
|
GenLdcLong(0);
|
|
Gen2t(pc_str, 0, 0, fType^.baseType);
|
|
end; {else if}
|
|
end {if}
|
|
else if fType^.kind = enumType then begin
|
|
Gen1t(pc_ldc, 0, cgWord);
|
|
Gen2t(pc_str, 0, 0, cgWord);
|
|
end; {else if}
|
|
end; {if}
|
|
Gen1(dc_lab, returnLabel);
|
|
if vaInfoLLN <> 0 then begin {clean up variable args, if any}
|
|
Gen2(pc_lda, vaInfoLLN, 0);
|
|
Gen0t(pc_stk, cgULong);
|
|
Gen1tName(pc_cup, -1, cgVoid, @'__va_end');
|
|
end; {if}
|
|
with fType^ do {generate the pc_ret instruction}
|
|
case kind of
|
|
scalarType : Gen0t(pc_ret, baseType);
|
|
arrayType : ;
|
|
structType ,
|
|
unionType : begin
|
|
Gen1Name(pc_lao, 0, structReturnVar^.name);
|
|
Gen0t(pc_rev, cgULong);
|
|
end;
|
|
pointerType : Gen0t(pc_ret, cgULong);
|
|
functionType: ;
|
|
enumConst : ;
|
|
enumType : Gen0t(pc_ret, cgWord);
|
|
definedType : ;
|
|
otherwise: Error(57);
|
|
end; {case}
|
|
end; {if}
|
|
Gen0 (dc_enp); {finish the segment}
|
|
CheckGotoList; {make sure all labels are declared}
|
|
while tempList <> nil do begin {dump the local labels}
|
|
tl := tempList;
|
|
tempList := tl^.next;
|
|
dispose(tl);
|
|
end; {while}
|
|
dumpLocal := true; {dump the local pool}
|
|
nameFound := false; {no pc_nam for the next function (yet)}
|
|
volatile := savedVolatile; {local volatile vars are out of scope}
|
|
fIsNoreturn := false; {not doing a noreturn function}
|
|
functionTable := nil;
|
|
functionName := nil;
|
|
end; {if}
|
|
PopTable; {remove this symbol table}
|
|
fenvAccess := stPtr^.lFenvAccess; {restore old value of fenvAccess}
|
|
dispose(stPtr); {dump the record}
|
|
if dumpLocal then begin
|
|
useGlobalPool := true; {start using the global memory pool}
|
|
LInit; {dispose of the local memory pool}
|
|
end; {if}
|
|
NextToken; {remove the rbracech token}
|
|
end; {EndCompoundStatement}
|
|
|
|
|
|
procedure RecordLineNumber (lineNumber: longint);
|
|
|
|
{ generate debug code to record the line number as specified }
|
|
|
|
var
|
|
newSourceFileGS: gsosOutStringPtr;
|
|
|
|
begin {RecordLineNumber}
|
|
if (lastLine <> lineNumber) or changedSourceFile then begin
|
|
lastLine := lineNumber;
|
|
if changedSourceFile then begin
|
|
newSourceFileGS := pointer(Malloc(sizeof(gsosOutString)));
|
|
newSourceFileGS^ := sourceFileGS;
|
|
Gen2Name(pc_lnm, ord(lineNumber), ord(debugType), pointer(newSourceFileGS));
|
|
changedSourceFile := false;
|
|
end {if}
|
|
else
|
|
Gen2Name(pc_lnm, ord(lineNumber), ord(debugType), nil);
|
|
end; {if}
|
|
end; {RecordLineNumber}
|
|
|
|
|
|
procedure Statement;
|
|
|
|
{ handle a statement }
|
|
|
|
label 1;
|
|
|
|
var
|
|
lToken,tToken: tokenType; {for look-ahead}
|
|
lSuppressMacroExpansions: boolean; {local copy of suppressMacroExpansions}
|
|
|
|
|
|
function GetSwitchRecord: statementPtr;
|
|
|
|
{ Find the enclosing switch statement }
|
|
{ }
|
|
{ Returns a pointer to the closest switch statement record, }
|
|
{ or nil if there are none. }
|
|
|
|
label 1;
|
|
|
|
var
|
|
stPtr: statementPtr; {work pointer}
|
|
|
|
begin {GetSwitchRecord}
|
|
stPtr := statementList;
|
|
while stPtr <> nil do begin
|
|
if stPtr^.kind = switchSt then
|
|
goto 1;
|
|
stPtr := stPtr^.next;
|
|
end; {while}
|
|
1: GetSwitchRecord := stPtr;
|
|
end; {GetSwitchRecord}
|
|
|
|
|
|
procedure AssignmentStatement;
|
|
|
|
{ handle an assignment statement }
|
|
|
|
begin {AssignmentStatement}
|
|
if token.kind in startExpression then begin
|
|
Expression(normalExpression, [semicolonch]);
|
|
if expressionType^.baseType <> cgVoid then
|
|
Gen0t(pc_pop, UsualUnaryConversions);
|
|
if token.kind = semicolonch then
|
|
NextToken
|
|
else begin
|
|
Error(22);
|
|
SkipStatement;
|
|
end; {else}
|
|
end {if}
|
|
else begin
|
|
NextToken;
|
|
Error(92);
|
|
end; {else}
|
|
end; {AssignmentStatement}
|
|
|
|
|
|
procedure BreakStatement;
|
|
|
|
{ handle a break statement }
|
|
|
|
label 1,2;
|
|
|
|
var
|
|
stPtr: statementPtr; {work pointer}
|
|
|
|
begin {BreakStatement}
|
|
stPtr := statementList; {find the proper statement}
|
|
while stPtr <> nil do begin
|
|
if stPtr^.kind in [whileSt,doSt,forSt,switchSt] then
|
|
goto 1;
|
|
stPtr := stPtr^.next;
|
|
end; {while}
|
|
Error(76);
|
|
goto 2;
|
|
|
|
1: if stPtr^.breakLab = 0 then {if there is no break label, create one}
|
|
stPtr^.breakLab := GenLabel;
|
|
Gen1(pc_ujp, stPtr^.breakLab); {branch to the break label}
|
|
2:
|
|
NextToken; {skip the 'break' token}
|
|
Match(semicolonch,22); {insist on a closing ';'}
|
|
end; {BreakStatement}
|
|
|
|
|
|
procedure CaseStatement;
|
|
|
|
{ handle a case statement }
|
|
|
|
var
|
|
stPtr: statementPtr; {switch record for this case label}
|
|
swPtr,swPtr2: switchPtr; {work pointers for inserting new entry}
|
|
val: longlong; {case label value}
|
|
|
|
begin {CaseStatement}
|
|
while token.kind = casesy do begin
|
|
NextToken; {skip the 'case' token}
|
|
stPtr := GetSwitchRecord; {get the proper switch record}
|
|
Expression(arrayExpression, [colonch]); {evaluate the branch condition}
|
|
GetLLExpressionValue(val);
|
|
if stPtr^.size = cgLongSize then begin {convert out-of-range values}
|
|
if val.lo < 0 then
|
|
val.hi := -1
|
|
else
|
|
val.hi := 0;
|
|
end {if}
|
|
else if stPtr^.size = cgWordSize then begin
|
|
if long(val.lo).lsw < 0 then begin
|
|
val.hi := -1;
|
|
val.lo := val.lo | $FFFF0000;
|
|
end {if}
|
|
else begin
|
|
val.hi := 0;
|
|
val.lo := val.lo & $0000FFFF;
|
|
end; {else}
|
|
end; {else if}
|
|
if stPtr = nil then
|
|
Error(72)
|
|
else begin
|
|
new(swPtr2); {create the new label table entry}
|
|
swPtr2^.lab := GenLabel;
|
|
Gen1(dc_lab, swPtr2^.lab);
|
|
swPtr2^.val := val;
|
|
swPtr := stPtr^.switchList;
|
|
if val.lo > stPtr^.maxVal then
|
|
stPtr^.maxVal := val.lo;
|
|
if swPtr = nil then begin {enter it in the table}
|
|
swPtr2^.last := nil;
|
|
swPtr2^.next := nil;
|
|
stPtr^.switchList := swPtr2;
|
|
stPtr^.labelCount := 1;
|
|
end {if}
|
|
else begin
|
|
while (swPtr^.next <> nil) and slt64(swPtr^.val, val) do
|
|
swPtr := swPtr^.next;
|
|
if (swPtr^.val.lo = val.lo) and (swPtr^.val.hi = val.hi) then
|
|
Error(73)
|
|
else if sgt64(swPtr^.val, val) then begin
|
|
swPtr2^.next := swPtr;
|
|
if swPtr^.last = nil then
|
|
stPtr^.switchList := swPtr2
|
|
else
|
|
swPtr^.last^.next := swPtr2;
|
|
swPtr2^.last := swPtr^.last;
|
|
swPtr^.last := swPtr2;
|
|
end {else if}
|
|
else begin {at end of list}
|
|
swPtr2^.next := nil;
|
|
swPtr2^.last := swPtr;
|
|
swPtr^.next := swPtr2;
|
|
end; {else}
|
|
stPtr^.labelCount := stPtr^.labelCount + 1;
|
|
end; {else}
|
|
end; {else}
|
|
|
|
Match(colonch,29); {get the colon}
|
|
end; {while}
|
|
Statement; {process the labeled statement}
|
|
end; {CaseStatement}
|
|
|
|
|
|
procedure ContinueStatement;
|
|
|
|
{ handle a continue statement }
|
|
|
|
label 1,2;
|
|
|
|
var
|
|
stPtr: statementPtr; {work pointer}
|
|
|
|
begin {ContinueStatement}
|
|
stPtr := statementList; {find the proper statement}
|
|
while stPtr <> nil do begin
|
|
if stPtr^.kind in [whileSt,doSt,forSt] then
|
|
goto 1;
|
|
stPtr := stPtr^.next;
|
|
end; {while}
|
|
Error(75);
|
|
goto 2;
|
|
|
|
1: if stPtr^.continueLab = 0 then {if there is no continue label, create one}
|
|
stPtr^.continueLab := GenLabel;
|
|
Gen1(pc_ujp, stPtr^.continueLab); {branch to the continue label}
|
|
2:
|
|
NextToken; {skip the 'continue' token}
|
|
Match(semicolonch,22); {insist on a closing ';'}
|
|
end; {ContinueStatement}
|
|
|
|
|
|
procedure DefaultStatement;
|
|
|
|
{ handle a default statement }
|
|
|
|
var
|
|
stPtr: statementPtr; {work pointer}
|
|
|
|
begin {DefaultStatement}
|
|
NextToken; {skip the 'default' token}
|
|
Match(colonch,29); {get the colon}
|
|
stPtr := GetSwitchRecord; {record the presense of a default label}
|
|
if stPtr = nil then
|
|
Error(72)
|
|
else if stPtr^.switchDefault <> 0 then
|
|
Error(74)
|
|
else begin
|
|
stPtr^.switchDefault := GenLabel;
|
|
Gen1(dc_lab, stPtr^.switchDefault);
|
|
end; {else}
|
|
Statement; {process the labeled statement}
|
|
end; {DefaultStatement}
|
|
|
|
|
|
procedure DoStatement;
|
|
|
|
{ handle a do statement }
|
|
|
|
var
|
|
lab: integer; {branch label}
|
|
stPtr: statementPtr; {work pointer}
|
|
|
|
begin {DoStatement}
|
|
NextToken; {skip the 'do' token}
|
|
new(stPtr); {create a statement record}
|
|
stPtr^.next := statementList;
|
|
statementList := stPtr;
|
|
stPtr^.kind := doSt;
|
|
lab := GenLabel; {create the branch label}
|
|
Gen1(dc_lab, lab);
|
|
stPtr^.doLab := lab;
|
|
stPtr^.breakLab := 0;
|
|
stPtr^.continueLab := 0;
|
|
if c99Scope then PushTable;
|
|
if c99Scope then PushTable;
|
|
Statement; {process the first loop body statement}
|
|
end; {DoStatement}
|
|
|
|
|
|
procedure ForStatement;
|
|
|
|
{ handle a for statement }
|
|
|
|
var
|
|
e3Start: codeRef; {ref to start of code for expression 3}
|
|
forLoop, continueLab, breakLab: integer; {branch points}
|
|
stPtr: statementPtr; {work pointer}
|
|
|
|
begin {ForStatement}
|
|
NextToken; {skip the 'for' token}
|
|
new(stPtr); {create a statement record}
|
|
stPtr^.next := statementList;
|
|
statementList := stPtr;
|
|
stPtr^.kind := forSt;
|
|
forLoop := GenLabel; {create the branch labels}
|
|
continueLab := GenLabel;
|
|
breakLab := GenLabel;
|
|
stPtr^.forLoop := forLoop;
|
|
stPtr^.continueLab := continueLab;
|
|
stPtr^.breakLab := breakLab;
|
|
|
|
if c99Scope then PushTable;
|
|
Match(lparench,13); {evaluate the start condition}
|
|
if allowMixedDeclarations and (token.kind in localDeclarationStart) then begin
|
|
doingForLoopClause1 := true;
|
|
DoDeclaration(false);
|
|
doingForLoopClause1 := false;
|
|
end {if}
|
|
else if token.kind <> semicolonch then begin
|
|
Expression(normalExpression, [semicolonch]);
|
|
Gen0t(pc_pop, UsualUnaryConversions);
|
|
Match(semicolonch,22);
|
|
end {else if}
|
|
else
|
|
NextToken;
|
|
|
|
Gen1(dc_lab, forLoop); {this label points to the condition}
|
|
if token.kind <> semicolonch then {handle the loop test}
|
|
begin {evaluate the expression}
|
|
Expression(normalExpression, [semicolonch]);
|
|
CompareToZero(pc_neq); {Evaluate the condition}
|
|
Gen1(pc_fjp, breakLab);
|
|
end; {if}
|
|
Match(semicolonch,22);
|
|
|
|
e3Start := GetCodeLocation; {generate and save code for expression 3}
|
|
if token.kind <> rparench then begin
|
|
Expression(normalExpression, [rparench]);
|
|
Gen0t(pc_pop, UsualUnaryConversions);
|
|
end; {if}
|
|
stPtr^.e3Code := RemoveCode(e3Start);
|
|
Match(rparench,12); {get the closing for loop paren}
|
|
|
|
if c99Scope then PushTable;
|
|
Statement; {process the first loop body statement}
|
|
end; {ForStatement}
|
|
|
|
|
|
procedure IfStatement;
|
|
|
|
{ handle an if statement }
|
|
|
|
var
|
|
lab: integer; {branch label}
|
|
stPtr: statementPtr; {work pointer}
|
|
|
|
begin {IfStatement}
|
|
NextToken; {skip the 'if' token}
|
|
if c99Scope then PushTable;
|
|
Match(lparench, 13); {evaluate the condition}
|
|
Expression(normalExpression, [rparench]);
|
|
Match(rparench, 12);
|
|
|
|
lab := GenLabel; {create the branch label}
|
|
CompareToZero(pc_neq); {evaluate the condition}
|
|
Gen1(pc_fjp, lab);
|
|
|
|
new(stPtr); {create a statement record}
|
|
stPtr^.next := statementList;
|
|
statementList := stPtr;
|
|
stPtr^.kind := ifSt;
|
|
stPtr^.ifLab := lab;
|
|
if c99Scope then PushTable;
|
|
Statement; {process the 'true' statement}
|
|
end; {IfStatement}
|
|
|
|
|
|
procedure GotoStatement;
|
|
|
|
{ handle a goto statement }
|
|
|
|
begin {GotoStatement}
|
|
NextToken; {skip the 'goto' token}
|
|
if token.kind in [ident,typedef] then begin
|
|
GotoLabel(pc_ujp); {jump to the label}
|
|
NextToken; {skip the token}
|
|
end {if}
|
|
else
|
|
Error(9); {flag the error}
|
|
Match(semicolonch, 22); {insist on a closing ';'}
|
|
end; {GotoStatement}
|
|
|
|
|
|
procedure LabelStatement;
|
|
|
|
{ handle a labeled statement }
|
|
|
|
begin {LabelStatement}
|
|
GotoLabel(dc_lab); {define the label}
|
|
NextToken; {skip the label}
|
|
if token.kind = colonch then {if present, skip the colon}
|
|
NextToken
|
|
else begin {bad statement - flag error and skip it}
|
|
Error(31);
|
|
SkipStatement;
|
|
end; {else}
|
|
end; {LabelStatement}
|
|
|
|
|
|
procedure ReturnStatement;
|
|
|
|
{ handle a return statement }
|
|
|
|
var
|
|
size: longint; {size of the struct/union}
|
|
|
|
|
|
procedure ReturnValue (tp: baseTypeEnum);
|
|
|
|
{ generate code to return a value of specified type }
|
|
|
|
begin {ReturnValue}
|
|
if (returnCount = 0)
|
|
and (token.kind = rbracech)
|
|
and (statementList^.next = nil)
|
|
and (vaInfoLLN = 0)
|
|
and (tp in [cgByte,cgUByte,cgWord,cgUWord,cgLong,cgULong])
|
|
then begin
|
|
Gen0t(pc_rev, tp);
|
|
skipReturn := true;
|
|
end {if}
|
|
else
|
|
Gen2t(pc_str, 0, 0, tp);
|
|
end; {ReturnValue}
|
|
|
|
|
|
begin {ReturnStatement}
|
|
if fIsNoreturn then
|
|
if (lint & lintReturn) <> 0 then
|
|
Error(153);
|
|
NextToken; {skip the 'return' token}
|
|
if token.kind <> semicolonch then {if present, evaluate the return value}
|
|
begin
|
|
if fType^.kind in [structType,unionType] then begin
|
|
Gen1Name(pc_lao, 0, structReturnVar^.name);
|
|
size := fType^.size;
|
|
end {if}
|
|
else if fType^.kind = scalarType then
|
|
if fType^.baseType in [cgQuad,cgUQuad] then
|
|
Gen2t(pc_lod, 0, 0, cgULong);
|
|
Expression(normalExpression, [semicolonch]);
|
|
AssignmentConversion(fType, expressionType, lastWasConst, lastConst,
|
|
true, false);
|
|
Match(semicolonch, 22); {insist on a closing ';'}
|
|
case fType^.kind of
|
|
scalarType: if fType^.baseType in [cgQuad,cgUQuad] then
|
|
Gen0t(pc_sto, fType^.baseType)
|
|
else
|
|
ReturnValue(fType^.baseType);
|
|
enumType: ReturnValue(cgWord);
|
|
pointerType: ReturnValue(cgULong);
|
|
structType,
|
|
unionType: begin
|
|
Gen2(pc_mov, long(size).msw, long(size).lsw);
|
|
Gen0t(pc_pop, cgULong);
|
|
end;
|
|
otherwise: ;
|
|
end; {case}
|
|
end {if}
|
|
else begin
|
|
if (fType^.kind <> scalarType) or (fType^.baseType <> cgVoid) then
|
|
if ((lint & lintC99Syntax) <> 0) or ((lint & lintReturn) <> 0) then
|
|
Error(152);
|
|
Match(semicolonch, 22); {insist on a closing ';'}
|
|
end; {else}
|
|
if not skipReturn then
|
|
Gen1(pc_ujp, returnLabel); {branch to the exit point}
|
|
returnCount := returnCount + 1;
|
|
end; {ReturnStatement}
|
|
|
|
|
|
procedure SwitchStatement;
|
|
|
|
{ handle a switch statement }
|
|
|
|
var
|
|
stPtr: statementPtr; {work pointer}
|
|
tp: typePtr; {for checking type}
|
|
|
|
begin {SwitchStatement}
|
|
NextToken; {skip the 'switch' token}
|
|
new(stPtr); {create a statement record}
|
|
stPtr^.next := statementList;
|
|
statementList := stPtr;
|
|
stPtr^.kind := switchSt;
|
|
stPtr^.maxVal := -maxint4;
|
|
stPtr^.labelCount := 0;
|
|
stPtr^.switchLab := GenLabel;
|
|
stPtr^.switchExit := GenLabel;
|
|
stPtr^.breakLab := stPtr^.switchExit;
|
|
stPtr^.switchList := nil;
|
|
stPtr^.switchDefault := 0;
|
|
if c99Scope then PushTable;
|
|
Match(lparench, 13); {evaluate the condition}
|
|
Expression(normalExpression,[rparench]);
|
|
Match(rparench, 12);
|
|
tp := expressionType; {make sure the expression is integral}
|
|
while tp^.kind = definedType do
|
|
tp := tp^.dType;
|
|
case tp^.kind of
|
|
|
|
scalarType:
|
|
if tp^.baseType in [cgQuad,cgUQuad] then begin
|
|
stPtr^.size := cgQuadSize;
|
|
stPtr^.ln := GetTemp(cgQuadSize);
|
|
Gen2t(pc_str, stPtr^.ln, 0, cgQuad);
|
|
end {if}
|
|
else if tp^.baseType in [cgLong,cgULong] then begin
|
|
stPtr^.size := cgLongSize;
|
|
stPtr^.ln := GetTemp(cgLongSize);
|
|
Gen2t(pc_str, stPtr^.ln, 0, cgLong);
|
|
end {if}
|
|
else if tp^.baseType in [cgByte,cgUByte,cgWord,cgUWord] then begin
|
|
stPtr^.size := cgWordSize;
|
|
stPtr^.ln := GetTemp(cgWordSize);
|
|
Gen2t(pc_str, stPtr^.ln, 0, cgWord);
|
|
end {else if}
|
|
else
|
|
Error(71);
|
|
|
|
enumType: begin
|
|
stPtr^.size := cgWordSize;
|
|
stPtr^.ln := GetTemp(cgWordSize);
|
|
Gen2t(pc_str, stPtr^.ln, 0, cgWord);
|
|
end;
|
|
|
|
otherwise:
|
|
Error(71);
|
|
end; {case}
|
|
Gen1(pc_ujp, stPtr^.switchLab); {branch to the xjp instruction}
|
|
if c99Scope then PushTable;
|
|
Statement; {process the loop body statement}
|
|
end; {SwitchStatement}
|
|
|
|
|
|
procedure WhileStatement;
|
|
|
|
{ handle a while statement }
|
|
|
|
var
|
|
stPtr: statementPtr; {work pointer}
|
|
top, endl: integer; {branch points}
|
|
|
|
begin {WhileStatement}
|
|
NextToken; {skip the 'while' token}
|
|
new(stPtr); {create a statement record}
|
|
stPtr^.next := statementList;
|
|
statementList := stPtr;
|
|
stPtr^.kind := whileSt;
|
|
top := GenLabel; {create the branch labels}
|
|
endl := GenLabel;
|
|
stPtr^.whileTop := top;
|
|
stPtr^.whileEnd := endl;
|
|
stPtr^.breakLab := endl;
|
|
stPtr^.continueLab := top;
|
|
Gen1(dc_lab, top); {define the top label}
|
|
if c99Scope then PushTable;
|
|
Match(lparench, 13); {evaluate the condition}
|
|
Expression(normalExpression, [rparench]);
|
|
Match(rparench, 12);
|
|
CompareToZero(pc_neq); {evaluate the condition}
|
|
Gen1(pc_fjp, endl);
|
|
if c99Scope then PushTable;
|
|
Statement; {process the first loop body statement}
|
|
end; {WhileStatement}
|
|
|
|
begin {Statement}
|
|
1:
|
|
{if trace names are enabled and a line # is due, generate it}
|
|
if traceBack or debugFlag then
|
|
if nameFound or debugFlag then
|
|
RecordLineNumber(lineNumber);
|
|
|
|
{handle the statement}
|
|
case token.kind of
|
|
asmsy: begin
|
|
NextToken;
|
|
AsmStatement;
|
|
end;
|
|
breaksy: BreakStatement;
|
|
casesy: CaseStatement;
|
|
continuesy: ContinueStatement;
|
|
defaultsy: DefaultStatement;
|
|
dosy: DoStatement;
|
|
elsesy: begin Error(25); SkipStatement; end;
|
|
forsy: ForStatement;
|
|
gotosy: GotoStatement;
|
|
typedef,
|
|
ident: begin
|
|
lSuppressMacroExpansions := suppressMacroExpansions;
|
|
suppressMacroExpansions := true;
|
|
lToken := token;
|
|
NextToken;
|
|
tToken := token;
|
|
PutBackToken(token, true, false);
|
|
token := lToken;
|
|
suppressMacroExpansions := lSuppressMacroExpansions;
|
|
if tToken.kind = colonch then begin
|
|
LabelStatement;
|
|
goto 1;
|
|
end {if}
|
|
else
|
|
AssignmentStatement;
|
|
end;
|
|
ifsy: IfStatement;
|
|
lbracech: CompoundStatement(true);
|
|
returnsy: ReturnStatement;
|
|
semicolonch: NextToken;
|
|
switchsy: SwitchStatement;
|
|
whilesy: WhileStatement;
|
|
otherwise: AssignmentStatement;
|
|
end; {case}
|
|
end; {Statement}
|
|
|
|
|
|
procedure EndDoStatement;
|
|
|
|
{ finish off a do statement }
|
|
|
|
var
|
|
stPtr: statementPtr; {work pointer}
|
|
|
|
begin {EndDoStatement}
|
|
if c99Scope then PopTable;
|
|
stPtr := statementList; {get the statement record}
|
|
if token.kind = whilesy then begin {if a while clause exists, process it}
|
|
NextToken; {skip the 'while' token}
|
|
if stPtr^.continueLab <> 0 then {create the continue label}
|
|
Gen1(dc_lab, stPtr^.continueLab);
|
|
Match(lparench, 13); {evaluate the condition}
|
|
Expression(normalExpression, [rparench]);
|
|
Match(rparench, 12);
|
|
CompareToZero(pc_equ); {evaluate the condition}
|
|
Gen1(pc_fjp, stPtr^.doLab);
|
|
Match(semicolonch, 22); {process the closing ';'}
|
|
end {if}
|
|
else
|
|
Error(30); {'while' expected}
|
|
if stPtr^.breakLab <> 0 then {create the break label}
|
|
Gen1(dc_lab, stPtr^.breakLab);
|
|
statementList := stPtr^.next; {pop the statement record}
|
|
dispose(stPtr);
|
|
if c99Scope then PopTable;
|
|
end; {EndDoStatement}
|
|
|
|
|
|
procedure EndIfStatement;
|
|
|
|
{ finish off an if statement }
|
|
|
|
var
|
|
lab1,lab2: integer; {branch labels}
|
|
stPtr: statementPtr; {work pointer}
|
|
|
|
begin {EndIfStatement}
|
|
if c99Scope then PopTable;
|
|
stPtr := statementList; {get the label to branch to}
|
|
lab1 := stPtr^.ifLab;
|
|
statementList := stPtr^.next; {pop the statement record}
|
|
dispose(stPtr);
|
|
|
|
if token.kind = elsesy then begin {if an else clause exists, process it}
|
|
NextToken; {skip 'else'}
|
|
lab2 := GenLabel; {create the branch label}
|
|
Gen1(pc_ujp, lab2); {branch past the else clause}
|
|
Gen1(dc_lab, lab1); {create label for if to branch to}
|
|
new(stPtr); {create a statement record}
|
|
stPtr^.next := statementList;
|
|
statementList := stPtr;
|
|
stPtr^.kind := elseSt;
|
|
stPtr^.elseLab := lab2;
|
|
if c99Scope then PushTable;
|
|
Statement; {evaluate the else clause}
|
|
end {if}
|
|
else begin
|
|
Gen1(dc_lab, lab1); {create label for if to branch to}
|
|
if c99Scope then PopTable;
|
|
end; {else}
|
|
end; {EndIfStatement}
|
|
|
|
|
|
procedure EndElseStatement;
|
|
|
|
{ finish off an else clause }
|
|
|
|
var
|
|
stPtr: statementPtr; {work pointer}
|
|
|
|
begin {EndElseStatement}
|
|
if c99Scope then PopTable;
|
|
stPtr := statementList; {create the label to branch to}
|
|
Gen1(dc_lab, stPtr^.elseLab);
|
|
statementList := stPtr^.next; {pop the statement record}
|
|
dispose(stPtr);
|
|
if c99Scope then PopTable;
|
|
end; {EndElseStatement}
|
|
|
|
|
|
procedure EndForStatement;
|
|
|
|
{ finish off a for statement }
|
|
|
|
var
|
|
stPtr: statementPtr; {work pointer}
|
|
|
|
begin {EndForStatement}
|
|
if c99Scope then PopTable;
|
|
stPtr := statementList;
|
|
Gen1(dc_lab, stPtr^.continueLab); {define the continue label}
|
|
InsertCode(stPtr^.e3Code); {insert code for expression 3}
|
|
Gen1(pc_ujp, stPtr^.forLoop); {loop to the test}
|
|
Gen1(dc_lab, stPtr^.breakLab); {create the exit label}
|
|
statementList := stPtr^.next; {pop the statement record}
|
|
dispose(stPtr);
|
|
if c99Scope then PopTable;
|
|
end; {EndForStatement}
|
|
|
|
|
|
procedure EndSwitchStatement;
|
|
|
|
{ finish off a switch statement }
|
|
|
|
const
|
|
sparse = 5; {label to tableSize ratio for sparse table}
|
|
|
|
var
|
|
default: integer; {default label}
|
|
ltp: baseTypeEnum; {base type}
|
|
minVal: integer; {min switch value}
|
|
stPtr: statementPtr; {work pointer}
|
|
|
|
{copies of vars (for efficiency)}
|
|
{-------------------------------}
|
|
exitLab: integer; {label at the end of the jump table}
|
|
isLong: boolean; {is the case expression long?}
|
|
isLongLong: boolean; {is the case expression long long?}
|
|
swPtr,swPtr2: switchPtr; {switch label table list}
|
|
|
|
begin {EndSwitchStatement}
|
|
if c99Scope then PopTable;
|
|
stPtr := statementList; {get the statement record}
|
|
exitLab := stPtr^.switchExit; {get the exit label}
|
|
isLong := stPtr^.size = cgLongSize; {get the long flag}
|
|
isLongLong := stPtr^.size = cgQuadSize; {get the long long flag}
|
|
swPtr := stPtr^.switchList; {Skip further generation if there were}
|
|
if swPtr <> nil then begin { no labels. }
|
|
default := stPtr^.switchDefault; {get a default label}
|
|
if default = 0 then
|
|
default := exitLab;
|
|
Gen1(pc_ujp, exitLab); {branch past the indexed jump}
|
|
Gen1(dc_lab, stPtr^.switchLab); {create the label for the xjp table}
|
|
if isLongLong then {decide on a base type}
|
|
ltp := cgQuad
|
|
else if isLong then
|
|
ltp := cgLong
|
|
else
|
|
ltp := cgWord;
|
|
if isLong or isLongLong
|
|
or (((stPtr^.maxVal-swPtr^.val.lo) div stPtr^.labelCount) > sparse) then
|
|
begin
|
|
|
|
{Long expressions and sparse switch statements are handled as a }
|
|
{series of if-goto tests. }
|
|
while swPtr <> nil do begin {generate the compares}
|
|
if isLongLong then
|
|
GenLdcQuad(swPtr^.val)
|
|
else if isLong then
|
|
GenLdcLong(swPtr^.val.lo)
|
|
else
|
|
Gen1t(pc_ldc, long(swPtr^.val.lo).lsw, cgWord);
|
|
Gen2t(pc_lod, stPtr^.ln, 0, ltp);
|
|
Gen0t(pc_equ, ltp);
|
|
Gen1(pc_tjp, swPtr^.lab);
|
|
swPtr2 := swPtr;
|
|
swPtr := swPtr^.next;
|
|
dispose(swPtr2);
|
|
end; {while}
|
|
Gen1(pc_ujp, default); {anything else goes to default}
|
|
end {if}
|
|
else begin
|
|
|
|
{compact word switch statements are handled with xjp}
|
|
minVal := long(swPtr^.val.lo).lsw; {record the min label value}
|
|
Gen2t(pc_lod, stPtr^.ln, 0, ltp); {get the value}
|
|
Gen1t(pc_dec, minVal, cgWord); {adjust the range}
|
|
Gen1(pc_xjp, ord(stPtr^.maxVal-minVal+1)); {do the indexed jump}
|
|
while swPtr <> nil do begin {generate the jump table}
|
|
while minVal < swPtr^.val.lo do begin
|
|
Gen1(pc_add, default);
|
|
minVal := minVal+1;
|
|
end; {while}
|
|
minVal := minVal+1;
|
|
Gen1(pc_add, swPtr^.lab);
|
|
swPtr2 := swPtr;
|
|
swPtr := swPtr^.next;
|
|
dispose(swPtr2);
|
|
end; {while}
|
|
Gen1(pc_add, default);
|
|
end; {if}
|
|
Gen1(dc_lab, exitLab); {generate the default label}
|
|
end {if}
|
|
else begin
|
|
Gen1(pc_ujp, exitLab); {branch past the indexed jump}
|
|
Gen1(dc_lab, stPtr^.switchLab); {create the label for the xjp table}
|
|
|
|
default := stPtr^.switchDefault; {if there is one, jump to the default label}
|
|
if default <> 0 then
|
|
Gen1(pc_ujp, default);
|
|
|
|
Gen1(dc_lab, exitLab); {generate the default label}
|
|
end; {else}
|
|
FreeTemp(stPtr^.ln, stPtr^.size); {release temp variable}
|
|
statementList := stPtr^.next; {pop the statement record}
|
|
dispose(stPtr);
|
|
if c99Scope then PopTable;
|
|
end; {EndSwitchStatement}
|
|
|
|
|
|
procedure EndWhileStatement;
|
|
|
|
{ finish off a while statement }
|
|
|
|
var
|
|
stPtr: statementPtr; {work pointer}
|
|
|
|
begin {EndWhileStatement}
|
|
if c99Scope then PopTable;
|
|
stPtr := statementList; {loop to the test}
|
|
Gen1(pc_ujp, stPtr^.whileTop);
|
|
Gen1(dc_lab, stPtr^.whileEnd); {create the exit label}
|
|
statementList := stPtr^.next; {pop the statement record}
|
|
dispose(stPtr);
|
|
if c99Scope then PopTable;
|
|
end; {EndWhileStatement}
|
|
|
|
{-- Type declarations ------------------------------------------}
|
|
|
|
procedure Declarator(declSpecifiers: declSpecifiersRecord;
|
|
var variable: identPtr; space: spaceType; doingPrototypes: boolean);
|
|
|
|
{ handle a declarator }
|
|
{ }
|
|
{ parameters: }
|
|
{ declSpecifiers - type/specifiers to use }
|
|
{ variable - pointer to variable being defined }
|
|
{ space - variable space to use }
|
|
{ doingPrototypes - are we compiling prototype parameter }
|
|
{ declarations? }
|
|
|
|
label 1;
|
|
|
|
type
|
|
typeDefPtr = ^typeDefRecord; {for stacking type records}
|
|
typeDefRecord = record
|
|
next: typeDefPtr;
|
|
typeDef: typePtr;
|
|
end;
|
|
pointerListPtr = ^pointerList; {for stacking pointer types}
|
|
pointerList = record
|
|
next: pointerListPtr;
|
|
qualifiers: typeQualifierSet;
|
|
end;
|
|
|
|
var
|
|
i: integer; {loop variable}
|
|
lastWasIdentifier: boolean; {for deciding if the declarator is a function}
|
|
lastWasPointer: boolean; {was the last type a pointer?}
|
|
madeFunctionTable: boolean; {made symbol table for function type?}
|
|
newName: stringPtr; {new symbol name}
|
|
parameterStorage: boolean; {is the new symbol in a parm list?}
|
|
state: stateKind; {declaration state of the variable}
|
|
tPtr: typePtr; {type of declaration}
|
|
tPtr2: typePtr; {work pointer}
|
|
tsPtr: typeDefPtr; {work pointer}
|
|
typeStack: typeDefPtr; {stack of type definitions}
|
|
lTable: symbolTablePtr; {saved copy of table}
|
|
|
|
{for checking function compatibility}
|
|
{-----------------------------------}
|
|
checkParms: boolean; {do we need to do type checking on the parm?}
|
|
compatible: boolean; {are the parameters compatible?}
|
|
ftoken: tokenType; {for checking extern functions}
|
|
p1,p2,p3: parameterPtr; {used to trace parameter lists}
|
|
pt1,pt2: typePtr; {parameter types}
|
|
t1: typePtr; {function type}
|
|
tk1,tk2: typeKind; {parameter type kinds}
|
|
unnamedParm: boolean; {is this an unnamed prototype?}
|
|
|
|
|
|
procedure StackDeclarations;
|
|
|
|
{ stack the declaration operators }
|
|
|
|
var
|
|
cp,cpList: pointerListPtr; {pointer list}
|
|
done,done2: boolean; {for loop termination}
|
|
isPtr: boolean; {is the parenthesized expr a ptr?}
|
|
isVoid: boolean; {is the type specifier void?}
|
|
wp: parameterPtr; {used to build prototype var list}
|
|
pvar: identPtr; {work pointer}
|
|
tPtr2: typePtr; {work pointer}
|
|
ttPtr: typeDefPtr; {work pointer}
|
|
parencount: integer; {for skipping in parm list}
|
|
gotStatic: boolean; {got 'static' in array declarator?}
|
|
|
|
{variables used to preserve states}
|
|
{ across recursive calls }
|
|
{---------------------------------}
|
|
lisFunction: boolean; {local copy of isFunction}
|
|
lLastParameter: identPtr; {next parameter to process}
|
|
lSuppressMacroExpansions: boolean;{local copy of suppressMacroExpansions}
|
|
ldeclaredTagOrEnumConst: boolean; {local copy of declaredTagOrEnumConst}
|
|
|
|
begin {StackDeclarations}
|
|
lastWasIdentifier := false; {used to see if the declaration is a fn}
|
|
cpList := nil;
|
|
if token.kind = typedef then
|
|
token.kind := ident;
|
|
case token.kind of
|
|
|
|
ident: begin {handle 'ident'}
|
|
if space = fieldListSpace then
|
|
variable := nil
|
|
else
|
|
variable := FindSymbol(token, space, true, true);
|
|
newName := token.name;
|
|
if variable = nil then begin
|
|
if declSpecifiers.storageClass = typedefsy then begin
|
|
tPtr2 := pointer(Calloc(sizeof(typeRecord)));
|
|
{tPtr2^.size := 0;}
|
|
{tPtr2^.saveDisp := 0;}
|
|
tPtr2^.kind := definedType;
|
|
{tPtr2^.qualifiers := [];}
|
|
tPtr2^.dType := tPtr;
|
|
end {if}
|
|
else
|
|
tPtr2 := tPtr;
|
|
if doingParameters then begin
|
|
if not doingPrototypes then
|
|
if not (tPtr2^.kind in
|
|
[enumConst,structType,unionType,definedType,pointerType])
|
|
then Error(50);
|
|
parameterStorage := true;
|
|
end; {if}
|
|
end {if}
|
|
else
|
|
checkParms := true;
|
|
NextToken;
|
|
if token.kind = eqch then
|
|
state := initialized;
|
|
lastWasIdentifier := true;
|
|
end;
|
|
|
|
asteriskch: begin {handle '*' 'declarator'}
|
|
while token.kind = asteriskch do begin
|
|
NextToken;
|
|
new(cp);
|
|
cp^.next := cpList;
|
|
cpList := cp;
|
|
cp^.qualifiers := [];
|
|
while token.kind in [_Alignassy..whilesy] do begin
|
|
if token.kind = constsy then
|
|
cpList^.qualifiers := cpList^.qualifiers + [tqConst]
|
|
else if token.kind = volatilesy then begin
|
|
cpList^.qualifiers := cpList^.qualifiers + [tqVolatile];
|
|
volatile := true
|
|
end {else if}
|
|
else if token.kind = restrictsy then {always allowed for now}
|
|
cpList^.qualifiers := cpList^.qualifiers + [tqRestrict]
|
|
else
|
|
Error(9);
|
|
NextToken;
|
|
end; {while}
|
|
end; {while}
|
|
StackDeclarations;
|
|
end;
|
|
|
|
lparench: begin {handle '(' 'declarator' ')'}
|
|
NextToken;
|
|
isPtr := token.kind = asteriskch;
|
|
StackDeclarations;
|
|
Match(rparench,12);
|
|
if isPtr then
|
|
lastWasIdentifier := false;
|
|
end;
|
|
|
|
otherwise:
|
|
if doingPrototypes then begin {allow for unnamed parameters}
|
|
pvar := pointer(Calloc(sizeof(identRecord)));
|
|
{pvar^.next := nil;}
|
|
{pvar^.saved := 0;}
|
|
pvar^.name := @'?';
|
|
pvar^.itype := tPtr;
|
|
{pvar^.disp := 0;}
|
|
{pvar^.bitDisp := 0;}
|
|
{pvar^.bitsize := 0;}
|
|
{pvar^.initialized := false;}
|
|
{pvar^.iPtr := nil;}
|
|
{pvar^.isForwardDeclared := false;}
|
|
pvar^.class := autosy;
|
|
pvar^.storage := parameter;
|
|
variable := pvar;
|
|
lastWasIdentifier := true;
|
|
newName := nil;
|
|
unnamedParm := true;
|
|
end; {if}
|
|
|
|
end; {case}
|
|
|
|
while token.kind in [lparench,lbrackch] do begin
|
|
|
|
{handle function declarations}
|
|
if token.kind = lparench then begin
|
|
PushTable; {create a symbol table}
|
|
{determine if it's a function}
|
|
isFunction := lastWasIdentifier or isFunction;
|
|
tPtr2 := pointer(GCalloc(sizeof(typeRecord))); {create the function type}
|
|
{tPtr2^.size := 0;}
|
|
{tPtr2^.saveDisp := 0;}
|
|
tPtr2^.kind := functionType;
|
|
{tPtr2^.qualifiers := [];}
|
|
{tPtr2^.varargs := false;}
|
|
{tPtr2^.prototyped := false;}
|
|
{tPtr2^.overrideKR := false;}
|
|
{tPtr2^.parameterList := nil;}
|
|
{tPtr2^.isPascal := false;}
|
|
{tPtr2^.toolNum := 0;}
|
|
{tPtr2^.dispatcher := 0;}
|
|
new(ttPtr);
|
|
ttPtr^.next := typeStack;
|
|
typeStack := ttPtr;
|
|
ttPtr^.typeDef := tPtr2;
|
|
NextToken; {skip the '(' token}
|
|
isVoid := token.kind = voidsy;
|
|
if token.kind = typedef then
|
|
if token.symbolPtr^.itype^.kind = scalarType then
|
|
if token.symbolPtr^.itype^.baseType = cgVoid then
|
|
isVoid := true;
|
|
if isVoid then begin {check for a void prototype}
|
|
lSuppressMacroExpansions := suppressMacroExpansions;
|
|
suppressMacroExpansions := true;
|
|
NextToken;
|
|
suppressMacroExpansions := lSuppressMacroExpansions;
|
|
if token.kind = rparench then begin
|
|
PutBackToken(token, false, false);
|
|
NextToken;
|
|
tPtr2^.prototyped := true;
|
|
end
|
|
else begin
|
|
PutBackToken(token, false, false);
|
|
token.kind := voidsy;
|
|
token.class := reservedSymbol;
|
|
end; {else}
|
|
end; {if}
|
|
{see if we are doing a prototyped list}
|
|
if token.kind in declarationSpecifiersElement then begin
|
|
{handle a prototype variable list}
|
|
numberOfParameters := 0; {don't allow K&R parm declarations}
|
|
done2 := false;
|
|
lisFunction := isFunction; {preserve global variables}
|
|
with tPtr2^ do begin
|
|
prototyped := true; {it is prototyped}
|
|
repeat {collect the declarations}
|
|
if token.kind in declarationSpecifiersElement then begin
|
|
ldeclaredTagOrEnumConst := declaredTagOrEnumConst;
|
|
lLastParameter := lastParameter;
|
|
DoDeclaration(true);
|
|
lastParameter := lLastParameter;
|
|
declaredTagOrEnumConst :=
|
|
ldeclaredTagOrEnumConst or declaredTagOrEnumConst;
|
|
if protoType <> nil then begin
|
|
wp := pointer(Malloc(sizeof(parameterRecord)));
|
|
wp^.next := parameterList;
|
|
parameterList := wp;
|
|
wp^.parameter := protoVariable;
|
|
wp^.parameterType := protoType;
|
|
if protoVariable <> nil then begin
|
|
protoVariable^.pnext := lastParameter;
|
|
lastParameter := protoVariable;
|
|
end; {if}
|
|
end; {if}
|
|
if token.kind = commach then begin
|
|
NextToken;
|
|
if token.kind = dotdotdotsy then begin
|
|
NextToken;
|
|
varargs := true;
|
|
done2 := true;
|
|
end; {if}
|
|
end {if}
|
|
else
|
|
done2 := true;
|
|
end {if}
|
|
else begin
|
|
Error(26);
|
|
parencount := 0;
|
|
while (token.kind <> eofsy)
|
|
and ((parencount > 0) or (token.kind <> rparench)) do
|
|
begin
|
|
if token.kind = rparench then
|
|
parencount := parencount-1
|
|
else if token.kind = lparench then
|
|
parencount := parencount+1;
|
|
NextToken;
|
|
end; {while}
|
|
done2 := true;
|
|
end; {else}
|
|
until done2;
|
|
end; {with}
|
|
isFunction := lisFunction; {restore global variables}
|
|
end {if prototype}
|
|
else if token.kind = ident then begin
|
|
|
|
{handle a K&R variable list}
|
|
if (lint & lintNotPrototyped) <> 0 then
|
|
Error(105);
|
|
if doingFunction or doingPrototypes then
|
|
Error(12)
|
|
else begin
|
|
numberOfParameters := 0; {no function parms yet}
|
|
end; {else}
|
|
repeat {make a list of parameters}
|
|
if not doingFunction then begin
|
|
if token.kind <> ident then begin
|
|
Error(9);
|
|
while not (token.kind in [rparench,commach,ident]) do
|
|
NextToken;
|
|
end; {if}
|
|
if token.kind = ident then begin
|
|
pvar := NewSymbol(token.name, nil, ident, variableSpace,
|
|
declared, false);
|
|
pvar^.storage := parameter;
|
|
pvar^.pnext := lastParameter;
|
|
lastParameter := pvar;
|
|
numberOfParameters := numberOfParameters+1;
|
|
pvar^.bitdisp := numberOfParameters;
|
|
NextToken;
|
|
end; {if}
|
|
end; {if}
|
|
if token.kind = commach then begin
|
|
NextToken;
|
|
done := false;
|
|
end {if}
|
|
else
|
|
done := true;
|
|
until done or (token.kind = eofsy);
|
|
end {else if}
|
|
else if (lint & lintNotPrototyped) <> 0 then
|
|
if not tPtr2^.prototyped then
|
|
Error(105);
|
|
Match(rparench,12); {insist on a closing ')' token}
|
|
if madeFunctionTable or not lastWasIdentifier then
|
|
PopTable
|
|
else
|
|
madeFunctionTable := true;
|
|
end {if}
|
|
|
|
{handle array declarations}
|
|
else {if token.kind = lbrackch then} begin
|
|
lastWasIdentifier := false;
|
|
tPtr2 := pointer(Calloc(sizeof(typeRecord)));
|
|
{tPtr2^.size := 0;}
|
|
{tPtr2^.saveDisp := 0;}
|
|
{tPtr2^.qualifiers := [];}
|
|
tPtr2^.kind := arrayType;
|
|
{tPtr2^.elements := 0;}
|
|
NextToken;
|
|
gotStatic := false;
|
|
if doingParameters and (typeStack = nil) then begin
|
|
tPtr2^.kind := pointerType; {adjust to pointer type}
|
|
tPtr2^.size := cgPointerSize;
|
|
if token.kind = staticsy then begin
|
|
gotStatic := true;
|
|
NextToken;
|
|
end; {if}
|
|
while token.kind in [constsy,volatilesy,restrictsy] do begin
|
|
if token.kind = constsy then
|
|
tPtr2^.qualifiers := tPtr2^.qualifiers + [tqConst]
|
|
else if token.kind = volatilesy then begin
|
|
tPtr2^.qualifiers := tPtr2^.qualifiers + [tqVolatile];
|
|
volatile := true;
|
|
end {else}
|
|
else {if token.kind = restrictsy then}
|
|
tPtr2^.qualifiers := tPtr2^.qualifiers + [tqRestrict];
|
|
NextToken;
|
|
end; {while}
|
|
if not gotStatic then
|
|
if token.kind = staticsy then begin
|
|
gotStatic := true;
|
|
NextToken;
|
|
end; {if}
|
|
end; {if}
|
|
new(ttPtr);
|
|
ttPtr^.next := typeStack;
|
|
typeStack := ttPtr;
|
|
ttPtr^.typeDef := tPtr2;
|
|
if token.kind <> rbrackch then begin
|
|
Expression(arrayExpression, [rbrackch,semicolonch]);
|
|
if expressionValue <= 0 then begin
|
|
Error(45);
|
|
expressionValue := 1;
|
|
end; {if}
|
|
tPtr2^.elements := expressionValue;
|
|
end {if}
|
|
else if gotStatic then
|
|
Error(35);
|
|
Match(rbrackch,24);
|
|
end; {else if}
|
|
end; {while}
|
|
|
|
{stack pointer type records}
|
|
while cpList <> nil do begin
|
|
tPtr2 := pointer(Malloc(sizeof(typeRecord)));
|
|
tPtr2^.size := cgPointerSize;
|
|
tPtr2^.saveDisp := 0;
|
|
tPtr2^.qualifiers := cpList^.qualifiers;
|
|
tPtr2^.kind := pointerType;
|
|
new(ttPtr);
|
|
ttPtr^.next := typeStack;
|
|
typeStack := ttPtr;
|
|
ttPtr^.typeDef := tPtr2;
|
|
cp := cpList;
|
|
cpList := cp^.next;
|
|
dispose(cp);
|
|
end; {for}
|
|
end; {StackDeclarations}
|
|
|
|
begin {Declarator}
|
|
tPtr := declSpecifiers.typeSpec;
|
|
newName := nil; {no identifier, yet}
|
|
unnamedParm := false; {not an unnamed parameter}
|
|
if declSpecifiers.storageClass = externsy then {decide on a storage state}
|
|
state := declared
|
|
else
|
|
state := defined;
|
|
madeFunctionTable := false; {no symbol table for function}
|
|
typeStack := nil; {no types so far}
|
|
parameterStorage := false; {symbol is not in a parameter list}
|
|
checkParms := false; {assume we won't need to check for parameter type errors}
|
|
StackDeclarations; {stack the type records}
|
|
while typeStack <> nil do begin {reverse the type stack}
|
|
tsPtr := typeStack;
|
|
typeStack := tsPtr^.next;
|
|
tPtr2 := tsPtr^.typeDef;
|
|
dispose(tsPtr);
|
|
case tPtr2^.kind of
|
|
pointerType: begin
|
|
tPtr2^.pType := tPtr;
|
|
end;
|
|
functionType: begin
|
|
while tPtr^.kind = definedType do
|
|
tPtr := tPtr^.dType;
|
|
tPtr2^.fType := Unqualify(tPtr);
|
|
if tPtr^.kind in [functionType,arrayType] then
|
|
Error(103);
|
|
end;
|
|
arrayType: begin
|
|
tPtr2^.size := tPtr^.size * tPtr2^.elements;
|
|
tPtr2^.aType := tPtr;
|
|
end;
|
|
otherwise: ;
|
|
end; {case}
|
|
tPtr := tPtr2;
|
|
end; {while}
|
|
|
|
if pascalsy in declSpecifiers.declarationModifiers then
|
|
tptr := MakePascalType(tptr);
|
|
|
|
if doingParameters then {adjust array parameters to pointers}
|
|
if tPtr^.kind = arrayType then
|
|
tPtr := MakePointerTo(tPtr^.aType);
|
|
|
|
if checkParms then begin {check for parameter type conflicts}
|
|
with variable^ do begin
|
|
if doingParameters then begin
|
|
if itype = nil then begin
|
|
itype := tPtr;
|
|
numberOfParameters := numberOfParameters-1;
|
|
if pfunc^.itype^.prototyped then begin
|
|
pfunc^.itype^.overrideKR := true;
|
|
p1 := nil;
|
|
for i := 1 to bitdisp do begin
|
|
p2 := pfunc^.itype^.parameterList;
|
|
while (p2^.next <> p1) and (p2 <> nil) do
|
|
p2 := p2^.next;
|
|
p1 := p2;
|
|
end; {for}
|
|
compatible := false;
|
|
if CompTypes(p1^.parameterType, tPtr) then
|
|
compatible := true
|
|
else begin
|
|
tk1 := p1^.parameterType^.kind;
|
|
tk2 := tPtr^.kind;
|
|
if (tk1 = arrayType) and (tk2 = pointerType) then
|
|
compatible :=
|
|
CompTypes(p1^.parameterType^.aType, tPtr^.pType)
|
|
else if (tk1 = pointerType) and (tk2 = arrayType) then
|
|
compatible :=
|
|
CompTypes(p1^.parameterType^.pType, tPtr^.aType);
|
|
end; {else}
|
|
if not compatible then
|
|
Error(47);
|
|
end; {if}
|
|
end {if}
|
|
else
|
|
Error(42);
|
|
storage := parameter;
|
|
parameterStorage := true;
|
|
end; {if}
|
|
end; {with}
|
|
end {if}
|
|
else if doingParameters then
|
|
if not doingPrototypes then
|
|
if pfunc^.itype^.prototyped then
|
|
if tPtr^.kind in
|
|
[enumConst,structType,unionType,definedType,pointerType]
|
|
then Error(50);
|
|
|
|
if tPtr^.kind = functionType then begin {declare the identifier}
|
|
if variable <> nil then begin
|
|
t1 := variable^.itype;
|
|
if (t1^.kind = functionType) and CompTypes(t1, tPtr) then begin
|
|
if t1^.prototyped and tPtr^.prototyped then begin
|
|
p2 := tPtr^.parameterList;
|
|
p1 := t1^.parameterList;
|
|
while (p1 <> nil) and (p2 <> nil) do begin
|
|
if p1^.parameter = nil then
|
|
pt1 := p1^.parameterType
|
|
else
|
|
pt1 := p1^.parameter^.itype;
|
|
if p2^.parameter = nil then
|
|
pt2 := p2^.parameterType
|
|
else
|
|
pt2 := p2^.parameter^.itype;
|
|
compatible := false;
|
|
if CompTypes(pt1, pt2) then
|
|
compatible := true
|
|
else begin
|
|
tk1 := pt1^.kind;
|
|
tk2 := pt2^.kind;
|
|
if (tk1 = arrayType) and (tk2 = pointerType) then
|
|
compatible := CompTypes(pt1^.aType, pt2^.pType)
|
|
else if (tk1 = pointerType) and (tk2 = arrayType) then
|
|
compatible := CompTypes(pt1^.pType, pt2^.aType)
|
|
end; {else}
|
|
if not compatible then begin
|
|
Error(47);
|
|
goto 1;
|
|
end; {if}
|
|
p1 := p1^.next;
|
|
p2 := p2^.next;
|
|
end; {while}
|
|
if p1 <> p2 then
|
|
Error(47);
|
|
end; {if}
|
|
end {if}
|
|
else
|
|
if (t1^.kind = functionType) and CompTypes(t1^.fType,tPtr^.fType) then
|
|
Error(47)
|
|
else
|
|
Error(42);
|
|
1: end; {if}
|
|
state := declared;
|
|
end; {if}
|
|
if madeFunctionTable then begin
|
|
lTable := table;
|
|
table := table^.next;
|
|
end; {if}
|
|
if newName <> nil then {declare the variable}
|
|
variable := NewSymbol(newName, tPtr, declSpecifiers.storageClass,
|
|
space, state, inlinesy in declSpecifiers.declarationModifiers)
|
|
else if unnamedParm then
|
|
variable^.itype := tPtr
|
|
else begin
|
|
if token.kind <> semicolonch then
|
|
Error(9);
|
|
variable := nil;
|
|
end; {else}
|
|
if madeFunctionTable then
|
|
table := lTable;
|
|
if variable <> nil then begin
|
|
if parameterStorage then
|
|
variable^.storage := parameter;
|
|
if isForwardDeclared then begin {handle forward declarations}
|
|
tPtr := variable^.itype;
|
|
lastWasPointer := false;
|
|
while tPtr^.kind in
|
|
[pointerType,arrayType,functionType,definedType] do begin
|
|
if tPtr^.kind = pointerType then
|
|
lastWasPointer := true
|
|
else if tPtr^.kind <> definedType then
|
|
lastWasPointer := false;
|
|
tPtr := tPtr^.pType;
|
|
end; {while}
|
|
if ((tPtr <> declSpecifiers.typeSpec)
|
|
and (not (tPtr^.kind in [structType,unionType])))
|
|
then begin
|
|
Error(107);
|
|
SkipStatement;
|
|
end; {if}
|
|
variable^.isForwardDeclared := true;
|
|
end; {if}
|
|
end; {if}
|
|
end; {Declarator}
|
|
|
|
|
|
procedure Initializer (var variable: identPtr);
|
|
|
|
{ handle a variable initializer }
|
|
{ }
|
|
{ paramaters: }
|
|
{ variable - ptr to the identifier begin initialized }
|
|
|
|
var
|
|
disp: longint; {disp within overall object being initialized}
|
|
done: boolean; {for loop termination}
|
|
errorFound: boolean; {used to remove bad initializations}
|
|
haveExpression: boolean; {has an expression been parsed but not used?}
|
|
iPtr,jPtr,kPtr: initializerPtr; {for reversing the list}
|
|
ip: identList; {used to place an id in the list}
|
|
isStatic: boolean; {static storage duration (or automatic)?}
|
|
luseGlobalPool: boolean; {local copy of useGlobalPool}
|
|
tToken: tokenType; {temporary copy of token}
|
|
|
|
|
|
procedure InsertInitializerRecord (iPtr: initializerPtr; size: longint);
|
|
|
|
{ Insert an initializer record in the initializer list }
|
|
{ }
|
|
{ parameters: }
|
|
{ iPtr - the record to insert }
|
|
{ size - number of bytes initialized by this record }
|
|
|
|
begin {InsertInitializerRecord}
|
|
iPtr^.disp := disp;
|
|
iPtr^.next := variable^.iPtr;
|
|
variable^.iPtr := iPtr;
|
|
{ writeln('Inserted initializer record with size ', size:1, ' at disp ', disp:1); {debug}
|
|
disp := disp + size;
|
|
end; {InsertInitializerRecord}
|
|
|
|
|
|
procedure GetInitializerExpression;
|
|
|
|
{ get the expression for an initializer }
|
|
|
|
begin {GetInitializerExpression}
|
|
if not isStatic then
|
|
Expression(autoInitializerExpression, [commach,rparench,rbracech])
|
|
else
|
|
Expression(initializerExpression, [commach,rparench,rbracech]);
|
|
end; {GetInitializerExpression}
|
|
|
|
|
|
procedure GetInitializerValue (tp: typePtr; bitsize,bitdisp: integer);
|
|
|
|
{ get the value of an initializer from a single expression }
|
|
{ }
|
|
{ parameters: }
|
|
{ tp - type of the variable being initialized }
|
|
{ bitsize - size of bit field (0 for non-bit fields) }
|
|
{ bitdisp - disp of bit field; unused if bitsize = 0 }
|
|
|
|
label 1,2;
|
|
|
|
var
|
|
bKind: baseTypeEnum; {type of constant}
|
|
etype: typePtr; {expression type}
|
|
i: integer; {loop variable}
|
|
ip: identPtr; {ident in pointer constant}
|
|
iPtr: initializerPtr; {for creating an initializer entry}
|
|
kind: tokenEnum; {kind of constant}
|
|
offset, offset2: longint; {integer offset from a pointer}
|
|
operator: tokenEnum; {operator for constant pointers}
|
|
size: longint; {size of item being initialized}
|
|
tKind: typeKind; {type of constant}
|
|
tree: tokenPtr; {for evaluating pointer constants}
|
|
|
|
|
|
function Subscript (tree: tokenPtr): typePtr;
|
|
|
|
{ handle subscripts in a pointer constant }
|
|
{ }
|
|
{ parameters: }
|
|
{ tree - subscript operators }
|
|
{ }
|
|
{ returns: type of the variable }
|
|
{ }
|
|
{ variables: }
|
|
{ iPtr - initializer location to store the array name }
|
|
{ offset - bytes past the start of the array }
|
|
|
|
var
|
|
ip: identPtr; {ident pointer}
|
|
rtree: tokenPtr; {work pointer}
|
|
tp: typePtr; {for tracking types}
|
|
select: longint; {selector size}
|
|
size: longint; {subscript value}
|
|
|
|
begin {Subscript}
|
|
if tree^.token.kind = uasterisk then begin
|
|
tree := tree^.left;
|
|
if tree^.token.kind = plusch then begin
|
|
rtree := tree^.right;
|
|
if rtree^.token.kind in
|
|
[intconst,uintconst,ushortconst,charconst,scharconst,ucharconst] then
|
|
size := rtree^.token.ival
|
|
else if rtree^.token.kind in [longconst,ulongconst] then
|
|
size := rtree^.token.lval
|
|
else if rtree^.token.kind in [longlongconst,ulonglongconst] then begin
|
|
size := rtree^.token.qval.lo;
|
|
with rtree^.token.qval do
|
|
if not (((hi = 0) and (lo & $ff000000 = 0)) or
|
|
((hi = -1) and (lo & $ff000000 = $ff000000))) then
|
|
Error(6);
|
|
end {else if}
|
|
else begin
|
|
Error(18);
|
|
errorFound := true;
|
|
end; {else}
|
|
tp := Subscript(tree^.left);
|
|
end {if}
|
|
else begin
|
|
size := 0;
|
|
tp := Subscript(tree);
|
|
end; {else}
|
|
if tp^.kind = arrayType then begin
|
|
tp := tp^.atype;
|
|
offset := offset + size*tp^.size;
|
|
Subscript := tp;
|
|
end {if}
|
|
else if tp^.kind = functionType then begin
|
|
Subscript := tp;
|
|
end {else if}
|
|
else begin
|
|
Error(47);
|
|
errorFound := true;
|
|
Subscript := intPtr;
|
|
end; {else}
|
|
end {if}
|
|
else if tree^.token.kind = dotch then begin
|
|
tp := Subscript(tree^.left);
|
|
while tp^.kind = definedType do
|
|
tp := tp^.dType;
|
|
if tp^.kind in [structType,unionType] then begin
|
|
DoSelection(tp, tree^.right, select);
|
|
Subscript := expressionType;
|
|
offset := offset+select;
|
|
if isBitField then
|
|
Error(106);
|
|
end {if}
|
|
else begin
|
|
Error(47);
|
|
errorFound := true;
|
|
Subscript := intPtr;
|
|
end; {else}
|
|
end {else if}
|
|
else if tree^.token.kind = ident then begin
|
|
ip := FindSymbol(tree^.token, variableSpace, false, true);
|
|
if ip = nil then begin
|
|
Error(31);
|
|
errorFound := true;
|
|
Subscript := intPtr;
|
|
iPtr^.pName := @'?';
|
|
end {if}
|
|
else begin
|
|
if ip^.storage in [stackFrame,parameter] then begin
|
|
Error(41);
|
|
errorFound := true;
|
|
end; {if}
|
|
Subscript := ip^.itype;
|
|
iPtr^.pName := ip^.name;
|
|
end; {else}
|
|
end {else if}
|
|
else if tree^.token.kind = stringConst then begin
|
|
Subscript := StringType(tree^.token.prefix);
|
|
iPtr^.isName := false;
|
|
iPtr^.pStr := tree^.token.sval;
|
|
end {else if}
|
|
else begin
|
|
Error(47);
|
|
errorFound := true;
|
|
Subscript := intPtr;
|
|
end; {else}
|
|
end; {Subscript}
|
|
|
|
|
|
begin {GetInitializerValue}
|
|
if not haveExpression then
|
|
GetInitializerExpression
|
|
else begin
|
|
NextToken;
|
|
haveExpression := false;
|
|
end; {else}
|
|
iPtr := pointer(Malloc(sizeof(initializerRecord)));
|
|
if bitsize <> 0 then
|
|
size := (bitdisp + bitsize + 7) div 8
|
|
else
|
|
size := tp^.size;
|
|
InsertInitializerRecord(iPtr, size);
|
|
iPtr^.isConstant := isConstant;
|
|
iPtr^.count := 1;
|
|
iPtr^.bitdisp := bitdisp;
|
|
iPtr^.bitsize := bitsize;
|
|
etype := expressionType;
|
|
AssignmentConversion(tp, expressionType, isConstant, expressionValue,
|
|
false, false);
|
|
if variable^.storage = external then
|
|
variable^.storage := global;
|
|
if isConstant and isStatic then begin
|
|
if etype^.baseType in [cgQuad,cgUQuad] then begin
|
|
iPtr^.qVal := llExpressionValue;
|
|
end {if}
|
|
else begin
|
|
iPtr^.qval.hi := 0;
|
|
iPtr^.iVal := expressionValue;
|
|
end; {else}
|
|
iPtr^.basetype := tp^.baseType;
|
|
case tp^.kind of
|
|
|
|
scalarType: begin
|
|
bKind := tp^.baseType;
|
|
if (etype^.baseType in [cgByte..cgULong,cgQuad,cgUQuad])
|
|
and (bKind in [cgByte..cgULong,cgQuad,cgUQuad]) then begin
|
|
if bKind in [cgLong,cgULong,cgQuad,cgUQuad] then
|
|
if eType^.baseType = cgUByte then
|
|
iPtr^.iVal := iPtr^.iVal & $000000FF
|
|
else if eType^.baseType = cgUWord then
|
|
iPtr^.iVal := iPtr^.iVal & $0000FFFF;
|
|
if bKind in [cgQuad,cgUQuad] then
|
|
if etype^.baseType in [cgByte..cgULong] then
|
|
if (etype^.baseType in [cgByte,cgWord,cgLong])
|
|
and (iPtr^.iVal < 0) then
|
|
iPtr^.qVal.hi := -1
|
|
else
|
|
iPtr^.qVal.hi := 0;
|
|
if tp^.cType = ctBool then
|
|
iPtr^.iVal := ord(expressionValue <> 0);
|
|
goto 2;
|
|
end; {if}
|
|
if bKind in [cgReal,cgDouble,cgComp,cgExtended] then begin
|
|
if etype^.baseType in [cgByte..cgULong] then begin
|
|
iPtr^.rVal := expressionValue;
|
|
if etype^.baseType = cgULong then
|
|
if expressionValue < 0 then
|
|
iPtr^.rVal := iPtr^.rVal + 4294967296.0;
|
|
end {if}
|
|
else if etype^.baseType in
|
|
[cgReal,cgDouble,cgComp,cgExtended] then
|
|
iPtr^.rval := realExpressionValue
|
|
else if eType^.baseType = cgQuad then
|
|
iPtr^.rVal := CnvLLX(llExpressionValue)
|
|
else if eType^.baseType = cgUQuad then
|
|
iPtr^.rVal := CnvULLX(llExpressionValue);
|
|
goto 2;
|
|
end; {if}
|
|
if (etype^.baseType in [cgReal,cgDouble,cgComp,cgExtended])
|
|
and (bKind in [cgByte..cgULong,cgQuad,cgUQuad]) then begin
|
|
if tp^.cType = ctBool then
|
|
iPtr^.iVal := ord(realExpressionValue <> 0)
|
|
else if bKind = cgUQuad then
|
|
CnvXULL(iPtr^.qVal, realExpressionValue)
|
|
else
|
|
CnvXLL(iPtr^.qVal, realExpressionValue);
|
|
goto 2;
|
|
end;
|
|
Error(47);
|
|
errorFound := true;
|
|
end;
|
|
|
|
arrayType: begin
|
|
if tp^.aType^.kind = scalarType then
|
|
if tp^.aType^.baseType in [cgByte,cgUByte] then
|
|
if eType^.baseType = cgString then
|
|
goto 2;
|
|
Error(46);
|
|
errorFound := true;
|
|
end;
|
|
|
|
pointerType:
|
|
if (etype = stringTypePtr) or (etype = utf16StringTypePtr)
|
|
or (etype = utf32StringTypePtr) then begin
|
|
iPtr^.isConstant := true;
|
|
iPtr^.basetype := ccPointer;
|
|
iPtr^.pval := 0;
|
|
iPtr^.pPlus := false;
|
|
iPtr^.isName := false;
|
|
iPtr^.pStr := longstringPtr(expressionValue);
|
|
end {if}
|
|
else if etype^.kind = scalarType then
|
|
if etype^.baseType in [cgByte..cgULong] then
|
|
if expressionValue = 0 then
|
|
iPtr^.basetype := cgULong
|
|
else begin
|
|
Error(47);
|
|
errorFound := true;
|
|
end {else}
|
|
else if etype^.baseType in [cgQuad,cgUQuad] then
|
|
if (llExpressionValue.hi = 0) and
|
|
(llExpressionValue.lo = 0) then
|
|
iPtr^.basetype := cgULong
|
|
else begin
|
|
Error(47);
|
|
errorFound := true;
|
|
end {else}
|
|
else begin
|
|
Error(48);
|
|
errorFound := true;
|
|
end {else}
|
|
else if etype^.kind = pointerType then begin
|
|
iPtr^.basetype := cgULong;
|
|
iPtr^.pval := expressionValue;
|
|
end {else if}
|
|
else begin
|
|
Error(48);
|
|
errorFound := true;
|
|
end; {else}
|
|
|
|
structType,unionType,enumType: begin
|
|
Error(46);
|
|
errorFound := true;
|
|
end;
|
|
|
|
otherwise:
|
|
Error(57);
|
|
|
|
end; {case}
|
|
2: DisposeTree(initializerTree);
|
|
end {if}
|
|
else begin
|
|
if ((tp^.kind = pointerType)
|
|
or ((tp^.kind = scalarType) and (tp^.baseType in [cgLong,cgULong])))
|
|
and (bitsize = 0)
|
|
then begin
|
|
iPtr^.basetype := ccPointer;
|
|
if isStatic then begin
|
|
|
|
{do pointer constants with + or -}
|
|
iPtr^.isConstant := true;
|
|
tree := initializerTree;
|
|
while tree^.token.kind = castoper do
|
|
tree := tree^.left;
|
|
offset := 0;
|
|
operator := tree^.token.kind;
|
|
while operator in [plusch,minusch] do begin
|
|
with tree^.right^.token do
|
|
if kind in [intConst,uintconst,ushortconst,longConst,
|
|
ulongconst,longlongConst,ulonglongconst,charconst,
|
|
scharconst,ucharconst] then begin
|
|
if kind in [intConst,charconst,scharconst,ucharconst] then
|
|
offSet2 := ival
|
|
else if kind in [uintConst,ushortconst] then
|
|
offset2 := ival & $0000ffff
|
|
else if kind in [longConst,ulongconst] then begin
|
|
offset2 := lval;
|
|
if (lval & $ff000000 <> 0)
|
|
and (lval & $ff000000 <> $ff000000) then
|
|
Error(6);
|
|
end {else if}
|
|
else {if kind = longlongConst then} begin
|
|
offset2 := qval.lo;
|
|
with qval do
|
|
if not (((hi = 0) and (lo & $ff000000 = 0)) or
|
|
((hi = -1) and (lo & $ff000000 = $ff000000))) then
|
|
Error(6);
|
|
end; {else}
|
|
if operator = plusch then
|
|
offset := offset + offset2
|
|
else
|
|
offset := offset - offset2;
|
|
end {if}
|
|
else begin
|
|
Error(47);
|
|
errorFound := true;
|
|
end; {else}
|
|
tree := tree^.left;
|
|
operator := tree^.token.kind;
|
|
end; {if}
|
|
kind := tree^.token.kind;
|
|
if kind = ident then begin
|
|
|
|
{handle names of functions or static arrays}
|
|
ip := FindSymbol(tree^.token, variableSpace, false, true);
|
|
if ip = nil then begin
|
|
Error(31);
|
|
errorFound := true;
|
|
end {if}
|
|
else begin
|
|
tKind := ip^.itype^.kind;
|
|
if tKind = functionType then begin
|
|
if operator in [plusch,minusch] then begin
|
|
Error(47);
|
|
errorFound := true;
|
|
end; {if}
|
|
end {if}
|
|
else if (tKind = arrayType)
|
|
and (ip^.storage in [external,global,private]) then begin
|
|
offset := offset*ip^.itype^.atype^.size;
|
|
end {else if}
|
|
else if tKind = pointerType then begin
|
|
Error(48);
|
|
errorFound := true;
|
|
end {else if}
|
|
else begin
|
|
Error(47);
|
|
errorFound := true;
|
|
end; {else}
|
|
iPtr^.pval := offset;
|
|
iPtr^.pPlus := true;
|
|
iPtr^.isName := true;
|
|
iPtr^.pName := ip^.name;
|
|
end; {if}
|
|
end {if}
|
|
else if kind = uand then begin
|
|
tree := tree^.left;
|
|
iPtr^.pPlus := true;
|
|
iPtr^.isName := true;
|
|
if tree^.token.kind = ident then begin
|
|
ip := FindSymbol(tree^.token, variableSpace, false, true);
|
|
if ip = nil then begin
|
|
Error(31);
|
|
errorFound := true;
|
|
end {if}
|
|
else
|
|
if ip^.storage in [external,global,private] then begin
|
|
offset := offset*ip^.itype^.size;
|
|
iPtr^.pName := ip^.name;
|
|
end {if}
|
|
else begin
|
|
Error(47);
|
|
errorFound := true;
|
|
end; {else}
|
|
end {if}
|
|
else begin
|
|
tp := Subscript(tree);
|
|
if offset > 0 then
|
|
iPtr^.pPlus := true
|
|
else begin
|
|
iPtr^.pPlus := false;
|
|
offset := -offset;
|
|
end; {else}
|
|
end; {else}
|
|
iPtr^.pval := offset;
|
|
end {else if}
|
|
else if kind in [dotch,uasterisk] then begin
|
|
iPtr^.isName := true;
|
|
tp := Subscript(tree);
|
|
if offset > 0 then
|
|
iPtr^.pPlus := true
|
|
else begin
|
|
iPtr^.pPlus := false;
|
|
offset := -offset;
|
|
end; {else}
|
|
iPtr^.pval := offset;
|
|
end {else if}
|
|
else if kind = stringConst then begin
|
|
iPtr^.pval := offset;
|
|
iPtr^.pPlus := true;
|
|
iPtr^.isName := false;
|
|
iPtr^.pStr := tree^.token.sval;
|
|
end {else if}
|
|
else begin
|
|
Error(47);
|
|
errorFound := true;
|
|
end; {else}
|
|
DisposeTree(initializerTree);
|
|
goto 1;
|
|
end; {if}
|
|
end; {if}
|
|
|
|
{handle auto variables}
|
|
if isStatic then begin
|
|
Error(41);
|
|
errorFound := true;
|
|
end; {else}
|
|
iPtr^.isConstant := false;
|
|
iPtr^.iTree := initializerTree;
|
|
iPtr^.iType := tp;
|
|
end; {else}
|
|
1:
|
|
end; {GetInitializerValue}
|
|
|
|
|
|
procedure Fill (count: longint);
|
|
|
|
{ fill in space in an initialized data structure with 0 bytes }
|
|
{ }
|
|
{ parameters: }
|
|
{ count - number of zero bytes to create }
|
|
|
|
var
|
|
iPtr: initializerPtr; {for creating an initializer entry}
|
|
tk: tokenPtr; {expression record}
|
|
|
|
begin {Fill}
|
|
while count <> 0 do begin
|
|
iPtr := pointer(Calloc(sizeof(initializerRecord)));
|
|
iPtr^.isConstant := isStatic;
|
|
{iPtr^.bitdisp := 0;}
|
|
{iPtr^.bitsize := 0;}
|
|
if iPtr^.isConstant then
|
|
iPtr^.basetype := cgUByte
|
|
else begin
|
|
new(tk);
|
|
tk^.next := nil;
|
|
tk^.left := nil;
|
|
tk^.middle := nil;
|
|
tk^.right := nil;
|
|
tk^.token.kind := intconst;
|
|
tk^.token.class := intConstant;
|
|
tk^.token.ival := 0;
|
|
iPtr^.iTree := tk;
|
|
iPtr^.iType := charPtr;
|
|
end; {else}
|
|
if count <= maxint then begin
|
|
iPtr^.count := ord(count);
|
|
count := 0;
|
|
end {if}
|
|
else begin
|
|
iPtr^.count := maxint;
|
|
count := count-maxint;
|
|
end; {else}
|
|
InsertInitializerRecord(iPtr, iPtr^.count);
|
|
end; {while}
|
|
end; {Fill}
|
|
|
|
|
|
procedure InitializeTerm (tp: typePtr; bitsize,bitdisp: integer;
|
|
main, nestedDesignator: boolean);
|
|
|
|
{ initialize one level of the type }
|
|
{ }
|
|
{ parameters: }
|
|
{ tp - pointer to the type being initialized }
|
|
{ bitsize - size of bit field (0 for non-bit fields) }
|
|
{ bitdisp - disp of bit field; unused if bitsize = 0 }
|
|
{ main - is this a call from the main level? }
|
|
{ nestedDesignator - handling second or later level of }
|
|
{ designator in a designator list? }
|
|
|
|
label 1,2;
|
|
|
|
var
|
|
bfp: identPtr; {pointer to bit-field in field list}
|
|
bfsize: integer; {number of bytes used by bit-field}
|
|
braces: boolean; {is the initializer inclosed in braces?}
|
|
count,maxCount: longint; {for tracking the size of an initializer}
|
|
ep: tokenPtr; {for forming string expression}
|
|
fillSize: longint; {size to fill with zeros}
|
|
hasNestedDesignator: boolean; {nested designator in current designation?}
|
|
iPtr: initializerPtr; {for creating an initializer entry}
|
|
ip: identPtr; {for tracing field lists}
|
|
kind: typeKind; {base type of an initializer}
|
|
ktp: typePtr; {array type with definedTypes removed}
|
|
lSuppressMacroExpansions: boolean;{local copy of suppressMacroExpansions}
|
|
maxDisp: longint; {maximum disp value so far}
|
|
newDisp: longint; {new disp set by a designator}
|
|
nextTokenKind: tokenEnum; {kind of next token}
|
|
startingDisp: longint; {disp at start of this term}
|
|
stringElementType: typePtr; {element type of string literal}
|
|
stringLength: integer; {elements in a string literal}
|
|
|
|
|
|
procedure RecomputeSizes (tp: typePtr);
|
|
|
|
{ a size has been inferred from an initializer - set the }
|
|
{ appropriate type size values }
|
|
{ }
|
|
{ parameters: }
|
|
{ tp - type to check }
|
|
|
|
begin {RecomputeSizes}
|
|
if tp^.aType^.kind = arrayType then
|
|
RecomputeSizes(tp^.aType);
|
|
with tp^ do
|
|
size := aType^.size*elements;
|
|
end; {RecomputeSizes}
|
|
|
|
begin {InitializeTerm}
|
|
braces := false; {allow for an opening brace}
|
|
if token.kind = lbracech then begin
|
|
NextToken;
|
|
braces := true;
|
|
end; {if}
|
|
|
|
while tp^.kind = definedType do
|
|
tp := tp^.dType;
|
|
kind := tp^.kind;
|
|
{check for designators that need to}
|
|
{be handled at an outer level }
|
|
if token.kind in [dotch,lbrackch] then
|
|
if not (braces or nestedDesignator) then
|
|
goto 1;
|
|
startingDisp := disp;
|
|
|
|
{handle arrays}
|
|
if kind = arrayType then begin
|
|
ktp := tp^.atype;
|
|
while ktp^.kind = definedType do
|
|
ktp := ktp^.dType;
|
|
kind := ktp^.kind;
|
|
|
|
{handle arrays initialized with a string constant}
|
|
if (token.kind = stringConst) and (kind = scalarType) then begin
|
|
stringElementType := StringType(token.prefix)^.aType;
|
|
if ((ktp^.baseType in [cgByte,cgUByte]) and (stringElementType^.size=1))
|
|
or CompTypes(ktp,stringElementType) then begin
|
|
tToken := token;
|
|
NextToken;
|
|
nextTokenKind := token.kind;
|
|
PutBackToken(token, false, true);
|
|
token := tToken;
|
|
if nextTokenKind in [commach, rbracech, semicolonch] then begin
|
|
stringLength :=
|
|
token.sval^.length div ord(stringElementType^.size);
|
|
if tp^.elements = 0 then begin
|
|
tp^.elements := stringLength;
|
|
RecomputeSizes(variable^.itype);
|
|
end {if}
|
|
else if tp^.elements < stringLength-1 then begin
|
|
Error(44);
|
|
errorFound := true;
|
|
end; {else if}
|
|
with ktp^ do begin
|
|
iPtr := pointer(Malloc(sizeof(initializerRecord)));
|
|
iPtr^.count := 1;
|
|
iPtr^.bitdisp := 0;
|
|
iPtr^.bitsize := 0;
|
|
if isStatic then begin
|
|
InsertInitializerRecord(iPtr, token.sval^.length);
|
|
iPtr^.isConstant := true;
|
|
iPtr^.basetype := cgString;
|
|
iPtr^.sval := token.sval;
|
|
count := tp^.elements - stringLength;
|
|
if count > 0 then
|
|
Fill(count * stringElementType^.size)
|
|
else if count = -1 then begin
|
|
iPtr^.sval := pointer(GMalloc(token.sval^.length+2));
|
|
CopyLongString(iPtr^.sval, token.sval);
|
|
iPtr^.sval^.length :=
|
|
iPtr^.sval^.length - ord(stringElementType^.size);
|
|
end; {else if}
|
|
end {if}
|
|
else begin
|
|
InsertInitializerRecord(iPtr,
|
|
tp^.elements * stringElementType^.size);
|
|
iPtr^.isConstant := false;
|
|
new(ep);
|
|
iPtr^.iTree := ep;
|
|
iPtr^.iType := tp;
|
|
ep^.next := nil;
|
|
ep^.left := nil;
|
|
ep^.middle := nil;
|
|
ep^.right := nil;
|
|
ep^.token := token;
|
|
end; {else}
|
|
end; {with}
|
|
NextToken;
|
|
goto 1;
|
|
end; {if}
|
|
end; {if}
|
|
end; {if}
|
|
|
|
{handle arrays not initialized with a string constant}
|
|
if kind in
|
|
[scalarType,pointerType,enumType,arrayType,structType,unionType] then
|
|
begin
|
|
count := 0; {get the expressions|initializers}
|
|
maxCount := tp^.elements;
|
|
maxDisp := disp;
|
|
if token.kind <> rbracech then
|
|
repeat
|
|
hasNestedDesignator := false;
|
|
{handle designators}
|
|
if token.kind in [lbrackch,dotch] then begin
|
|
if not (braces or (nestedDesignator and (disp=startingDisp)))
|
|
then begin
|
|
PutBackToken(token, false, true);
|
|
token.kind := commach;
|
|
token.class := reservedSymbol;
|
|
goto 1;
|
|
end; {if}
|
|
Match(lbrackch, 35);
|
|
Expression(arrayExpression, [rbrackch]);
|
|
if (expressionValue < 0)
|
|
or ((maxCount <> 0) and (expressionValue >= maxCount)) then
|
|
begin
|
|
Error(183);
|
|
errorFound := true;
|
|
count := 0;
|
|
end {if}
|
|
else begin
|
|
count := expressionValue;
|
|
end; {else}
|
|
Match(rbrackch, 24);
|
|
if token.kind in [dotch,lbrackch] then
|
|
hasNestedDesignator := true
|
|
else
|
|
Match(eqch, 182);
|
|
newDisp := startingDisp + count * ktp^.size;
|
|
if braces then begin
|
|
fillSize := newDisp - maxDisp;
|
|
if hasNestedDesignator then
|
|
fillSize := fillSize + ktp^.size;
|
|
if fillSize > 0 then begin
|
|
disp := maxDisp;
|
|
Fill(fillSize);
|
|
maxDisp := disp;
|
|
end; {if}
|
|
end; {if}
|
|
end; {if}
|
|
|
|
disp := startingDisp + count * ktp^.size;
|
|
InitializeTerm(ktp, 0, 0, false, hasNestedDesignator);
|
|
if disp > maxDisp then
|
|
maxDisp := disp;
|
|
count := count+1;
|
|
if (count = maxCount) and not braces then
|
|
done := true
|
|
else if (token.kind = commach) then begin
|
|
NextToken;
|
|
done := token.kind = rbracech;
|
|
if not done then
|
|
if count = maxCount then
|
|
if not (token.kind = lbrackch) then begin
|
|
Error(183);
|
|
errorFound := true;
|
|
count := 0;
|
|
end; {if}
|
|
end {else if}
|
|
else
|
|
done := true;
|
|
until done or (token.kind = eofsy);
|
|
if maxCount = 0 then begin {set the array size}
|
|
if maxDisp <> startingDisp then begin
|
|
maxCount := (maxDisp - startingDisp + ktp^.size-1) div ktp^.size;
|
|
tp^.elements := maxCount;
|
|
RecomputeSizes(variable^.itype);
|
|
end {if}
|
|
else begin
|
|
Error(49);
|
|
errorFound := true;
|
|
end; {else}
|
|
end; {if}
|
|
if braces then begin
|
|
disp := startingDisp + maxCount * ktp^.size;
|
|
if disp > maxDisp then begin {if there weren't enough initializers...}
|
|
fillSize := disp - maxDisp;
|
|
disp := maxDisp;
|
|
Fill(fillSize); { fill in the blank spots}
|
|
end; {if}
|
|
end; {if}
|
|
end {else if}
|
|
|
|
else begin
|
|
Error(47);
|
|
errorFound := true;
|
|
end; {else}
|
|
end {if}
|
|
|
|
{handle structures and unions}
|
|
else if kind in [structType, unionType] then begin
|
|
|
|
{handle initialization with an expression of struct/union type}
|
|
if not braces then
|
|
if not nestedDesignator then
|
|
if not isStatic then
|
|
if (token.kind in startExpression-[stringconst]) then begin
|
|
if not haveExpression then begin
|
|
GetInitializerExpression;
|
|
haveExpression := true;
|
|
PutBackToken(token, false, true);
|
|
token.kind := ident; {dummy expression-starting token}
|
|
token.class := identifier;
|
|
token.name := @'__';
|
|
token.symbolPtr := nil;
|
|
while expressionType^.kind = definedType do
|
|
expressionType := expressionType^.dType;
|
|
end; {if}
|
|
if CompTypes(tp, expressionType) then begin
|
|
GetInitializerValue(tp, 0, 0);
|
|
goto 1;
|
|
end; {if}
|
|
end; {if}
|
|
|
|
{handle struct/union initialization with an initializer list}
|
|
if braces or (not main) then begin
|
|
ip := tp^.fieldList;
|
|
maxDisp := disp;
|
|
lSuppressMacroExpansions := suppressMacroExpansions;
|
|
while true do begin
|
|
if token.kind = rbracech then {fill remainder with zeros}
|
|
goto 2;
|
|
hasNestedDesignator := false;
|
|
{handle designators}
|
|
if token.kind in [dotch,lbrackch] then begin
|
|
if not (braces or (nestedDesignator and (disp=startingDisp)))
|
|
then begin
|
|
PutBackToken(token, false, true);
|
|
token.kind := commach;
|
|
token.class := reservedSymbol;
|
|
goto 1;
|
|
end; {if}
|
|
Match(dotch, 35);
|
|
if token.kind in [ident,typedef] then begin
|
|
ip := tp^.fieldList;
|
|
done := false;
|
|
while (ip <> nil) and not done do
|
|
if ip^.name^ = token.name^ then
|
|
done := true
|
|
else
|
|
ip := ip^.next;
|
|
if ip = nil then begin
|
|
Error(81);
|
|
errorFound := true;
|
|
end; {if}
|
|
if (ip <> nil) and ip^.anonMemberField then begin
|
|
PutBackToken(token, false, true);
|
|
token.kind := dotch;
|
|
token.class := reservedSymbol;
|
|
token.isDigraph := false;
|
|
ip := ip^.anonMember;
|
|
end {if}
|
|
else
|
|
NextToken;
|
|
if token.kind in [dotch,lbrackch] then
|
|
hasNestedDesignator := true
|
|
else
|
|
Match(eqch, 182);
|
|
newDisp := startingDisp + ip^.disp;
|
|
if braces then begin
|
|
fillSize := newDisp - maxDisp;
|
|
if hasNestedDesignator and (ip^.bitsize = 0) then
|
|
fillSize := fillSize + ip^.itype^.size;
|
|
if fillSize > 0 then begin
|
|
disp := maxDisp;
|
|
Fill(fillSize);
|
|
maxDisp := disp;
|
|
end; {if}
|
|
end; {if}
|
|
end {if}
|
|
else begin
|
|
Error(9);
|
|
errorFound := true;
|
|
goto 2;
|
|
end; {else}
|
|
end; {if}
|
|
|
|
if (ip = nil) or (ip^.itype^.size = 0) then
|
|
goto 2;
|
|
if ip^.isForwardDeclared then
|
|
ResolveForwardReference(ip);
|
|
disp := startingDisp + ip^.disp;
|
|
if ip^.bitsize <> 0 then begin {zero out padding bits in bitfields}
|
|
bfp := ip;
|
|
while (bfp^.next <> nil) and (bfp^.next^.disp = bfp^.disp)
|
|
and (bfp^.next^.bitsize <> 0) do
|
|
bfp := bfp^.next;
|
|
bfsize := (bfp^.bitdisp + bfp^.bitsize + 7) div 8;
|
|
if disp + bfsize > maxDisp then
|
|
if (bfp <> ip) or (ip^.bitdisp <> 0)
|
|
or (ip^.bitsize mod 8 <> 0) then begin
|
|
Fill(bfsize);
|
|
maxDisp := disp;
|
|
disp := startingDisp + ip^.disp;
|
|
end; {if}
|
|
end; {if}
|
|
InitializeTerm(ip^.itype, ip^.bitsize, ip^.bitdisp, false,
|
|
hasNestedDesignator);
|
|
if disp > maxDisp then
|
|
maxDisp := disp;
|
|
if kind = unionType then
|
|
ip := nil
|
|
else begin
|
|
ip := ip^.next;
|
|
while (ip <> nil) and ip^.anonMemberField do
|
|
ip := ip^.next;
|
|
end; {else}
|
|
if ((ip = nil) or (ip^.itype^.size = 0)) and not braces then
|
|
goto 2;
|
|
if token.kind = commach then begin
|
|
NextToken;
|
|
if token.kind = commach then
|
|
if ip = nil then
|
|
if braces then begin
|
|
Error(23);
|
|
errorFound := true;
|
|
end; {if}
|
|
end {if}
|
|
else if token.kind <> rbracech then
|
|
ip := nil;
|
|
end; {while}
|
|
2: if braces then begin
|
|
disp := startingDisp + tp^.size;
|
|
if disp > maxDisp then begin {if there weren't enough initializers...}
|
|
fillSize := disp - maxDisp;
|
|
disp := maxDisp;
|
|
Fill(fillSize); { fill in the blank spots}
|
|
end; {if}
|
|
end; {if}
|
|
suppressMacroExpansions := lSuppressMacroExpansions;
|
|
end {if}
|
|
else begin {struct/union assignment initializer}
|
|
Error(47);
|
|
errorFound := true;
|
|
end; {else}
|
|
end {else if}
|
|
|
|
{handle single-valued types}
|
|
else if kind in [scalarType,pointerType,enumType] then
|
|
GetInitializerValue(tp, bitsize, bitdisp)
|
|
|
|
else begin
|
|
Error(47);
|
|
errorFound := true;
|
|
end; {else}
|
|
1:
|
|
if braces then begin {if there was an opening brace then }
|
|
if token.kind = commach then { insist on a closing brace }
|
|
NextToken;
|
|
if token.kind = rbracech then
|
|
NextToken
|
|
else begin
|
|
Error(23);
|
|
while not (token.kind in [rbracech,eofsy]) do
|
|
NextToken;
|
|
NextToken;
|
|
errorFound := true;
|
|
end; {else}
|
|
end; {if}
|
|
end; {InitializeTerm}
|
|
|
|
begin {Initializer}
|
|
disp := 0; {start at beginning of the object}
|
|
errorFound := false; {no errors found so far}
|
|
haveExpression := false; {no expression parsed yet}
|
|
{static or automatic initialization?}
|
|
isStatic := variable^.storage in [external,global,private];
|
|
luseGlobalPool := useGlobalPool; {use global memory for global vars}
|
|
useGlobalPool := isStatic or useGlobalPool;
|
|
{make sure a required '{' is there}
|
|
if not (token.kind in [lbracech,stringConst]) then
|
|
if variable^.itype^.kind = arrayType then begin
|
|
Error(27);
|
|
errorFound := true;
|
|
end; {if}
|
|
InitializeTerm(variable^.itype, 0, 0, true, false); {do the initialization}
|
|
variable^.state := initialized; {mark the variable as initialized}
|
|
iPtr := variable^.iPtr; {reverse the initializer list}
|
|
jPtr := nil;
|
|
while iPtr <> nil do begin
|
|
kPtr := iPtr;
|
|
iPtr := iPtr^.next;
|
|
kPtr^.next := jPtr;
|
|
jPtr := kPtr;
|
|
end; {while}
|
|
variable^.iPtr := jPtr;
|
|
if isStatic then {if doing static initialization }
|
|
if variable^.itype^.kind in [structType,unionType,definedType,arrayType]
|
|
then begin
|
|
disp := 0; {...ensure unnamed members are 0}
|
|
Fill(variable^.itype^.size);
|
|
end; {if}
|
|
if errorFound then {eliminate bad initializers}
|
|
variable^.state := defined;
|
|
useGlobalPool := luseGlobalPool; {restore useGlobalPool}
|
|
end; {Initializer}
|
|
|
|
|
|
procedure DoStaticAssert;
|
|
|
|
{ process a static assertion }
|
|
|
|
begin {DoStaticAssert}
|
|
NextToken;
|
|
Match(lparench, 13);
|
|
Expression(arrayExpression, [commach]);
|
|
if (expressionType = nil) or (expressionType^.kind <> scalarType) then
|
|
Error(18)
|
|
else if expressionValue = 0 then
|
|
Error(132);
|
|
Match(commach, 86);
|
|
Match(stringconst, 83);
|
|
Match(rparench, 12);
|
|
Match(semicolonch, 22);
|
|
end; {DoStaticAssert}
|
|
|
|
|
|
procedure DeclarationSpecifiers (var declSpecifiers: declSpecifiersRecord;
|
|
allowedTokens: tokenSet; badNextTokenError: integer);
|
|
|
|
{ handle declaration specifiers or a specifier-qualifier list }
|
|
{ }
|
|
{ parameters: }
|
|
{ declSpecifiers - record to hold result type & specifiers}
|
|
{ allowedTokens - specifiers/qualifiers that can be used }
|
|
{ badNextTokenError - error code for an unexpected token }
|
|
{ following the declaration specifiers }
|
|
{ }
|
|
{ outputs: }
|
|
{ isForwardDeclared - is the field list component }
|
|
{ referencing a forward struct/union? }
|
|
{ declaredTagOrEnumConst - set if a tag or an enum const }
|
|
{ is declared (otherwise unchanged) }
|
|
|
|
label 1,2,3;
|
|
|
|
var
|
|
done: boolean; {for loop termination}
|
|
enumVal: integer; {default value for the next enum constant}
|
|
tPtr: typePtr; {for building types}
|
|
variable: identPtr; {enumeration variable}
|
|
|
|
structPtr: identPtr; {structure identifier}
|
|
structTypePtr: typePtr; {structure type}
|
|
tKind: typeKind; {defining structure or union?}
|
|
|
|
ttoken: tokenType; {temp variable for struct name}
|
|
lUseGlobalPool: boolean; {local copy of useGlobalPool}
|
|
globalStruct: boolean; {did we force global pool use?}
|
|
|
|
typeSpecifiers: tokenSet; {set of tokens specifying the type}
|
|
typeDone: boolean; {no more type specifiers can be accepted}
|
|
|
|
typeQualifiers: typeQualifierSet; {set of type qualifiers found}
|
|
|
|
myIsForwardDeclared: boolean; {value of isForwardDeclared to generate}
|
|
myTypeSpec: typePtr; {value of typeSpec to generate}
|
|
myDeclarationModifiers: tokenSet; {all modifiers in this declaration}
|
|
myStorageClass: tokenEnum; {storage class}
|
|
|
|
isLongLong: boolean; {is this a "long long" type?}
|
|
|
|
procedure FieldList (tp: typePtr; kind: typeKind);
|
|
|
|
{ handle a field list }
|
|
{ }
|
|
{ parameters }
|
|
{ tp - place to store the type pointer }
|
|
|
|
label 1;
|
|
|
|
type
|
|
anonNameString = packed array [0..11] of char;
|
|
|
|
var
|
|
anonName: ^anonNameString; {name for anonymous struct/union field}
|
|
bitDisp: integer; {current bit disp}
|
|
disp: longint; {current byte disp}
|
|
done: boolean; {for loop termination}
|
|
fl,tfl,ufl: identPtr; {field list}
|
|
ldoingParameters: boolean; {local copy of doingParameters}
|
|
lisForwardDeclared: boolean; {local copy of isForwardDeclared}
|
|
maxDisp: longint; {for determining union sizes}
|
|
variable: identPtr; {variable being defined}
|
|
didFlexibleArray: boolean; {have we seen a flexible array member?}
|
|
fieldDeclSpecifiers: declSpecifiersRecord; {decl specifiers for field}
|
|
tPtr: typePtr; {for building types}
|
|
anonMember: boolean; {processing an anonymous struct/union?}
|
|
|
|
procedure AddField(variable: identPtr; anonMember: identPtr);
|
|
|
|
{ add a field to the field list }
|
|
{ }
|
|
{ parameters }
|
|
{ variable - field to add }
|
|
{ anonMember - anonymous struct/union that this field }
|
|
{ came from, if any (nil if not an anonymous }
|
|
{ member field) }
|
|
|
|
label 1;
|
|
|
|
var
|
|
tfl: identPtr; {for traversing field list}
|
|
|
|
begin {AddField}
|
|
tfl := fl; {(check for dups)}
|
|
while tfl <> nil do begin
|
|
if tfl^.name^ = variable^.name^ then begin
|
|
Error(42);
|
|
goto 1;
|
|
end; {if}
|
|
tfl := tfl^.next;
|
|
end; {while}
|
|
1: variable^.next := fl;
|
|
if anonMember <> nil then begin
|
|
variable^.anonMemberField := true;
|
|
variable^.anonMember := anonMember;
|
|
end {if}
|
|
else
|
|
variable^.anonMemberField := false;
|
|
fl := variable;
|
|
end; {AddField}
|
|
|
|
begin {FieldList}
|
|
ldoingParameters := doingParameters; {allow fields in K&R dec. area}
|
|
doingParameters := false;
|
|
lisForwardDeclared := isForwardDeclared; {stack this value}
|
|
bitDisp := 0; {start allocation from byte 0}
|
|
disp := 0;
|
|
maxDisp := 0;
|
|
didFlexibleArray := false;
|
|
fl := nil; {nothing in the field list, yet}
|
|
{while there are entries in the field list...}
|
|
1: while token.kind in structDeclarationStart do begin
|
|
if token.kind = _Static_assertsy then begin
|
|
DoStaticAssert;
|
|
goto 1;
|
|
end; {if}
|
|
DeclarationSpecifiers(fieldDeclSpecifiers, specifierQualifierListElement, 176);
|
|
repeat {declare the variables...}
|
|
if didFlexibleArray then
|
|
Error(118);
|
|
variable := nil;
|
|
anonMember := false;
|
|
if token.kind <> colonch then begin
|
|
if (token.kind = semicolonch) then begin
|
|
tPtr := fieldDeclSpecifiers.typeSpec;
|
|
while tPtr^.kind = definedType do
|
|
tPtr := tPtr^.dType;
|
|
if (tPtr^.kind in [structType,unionType])
|
|
and (tPtr^.sName = nil)
|
|
and ((structsy in fieldDeclSpecifiers.declarationModifiers)
|
|
or (unionsy in fieldDeclSpecifiers.declarationModifiers))
|
|
then begin
|
|
anonName := pointer(Malloc(sizeof(anonNameString)));
|
|
anonName^ := concat('~anon', cnvis(anonNumber));
|
|
anonNumber := anonNumber+1;
|
|
variable := NewSymbol(anonName, tPtr, ident,
|
|
fieldListSpace, defined, false);
|
|
anonMember := true;
|
|
TermHeader; {cannot record anon member in .sym file}
|
|
end; {if}
|
|
end {if}
|
|
else
|
|
Declarator(fieldDeclSpecifiers, variable, fieldListSpace, false);
|
|
if variable <> nil then {enter the var in the field list}
|
|
AddField(variable, nil);
|
|
end; {if}
|
|
if kind = unionType then begin
|
|
disp := 0;
|
|
bitdisp := 0;
|
|
end; {if}
|
|
if token.kind = colonch then {handle a bit field}
|
|
begin
|
|
NextToken;
|
|
Expression(arrayExpression,[commach,semicolonch]);
|
|
if (expressionValue >= maxBitField) or (expressionValue < 0) then
|
|
begin
|
|
Error(54);
|
|
expressionValue := maxBitField-1;
|
|
end; {if}
|
|
if (bitdisp+long(expressionValue).lsw > maxBitField)
|
|
or (long(expressionValue).lsw = 0) then begin
|
|
disp := disp+((bitDisp+7) div 8);
|
|
bitdisp := 0;
|
|
if long(expressionValue).lsw = 0 then
|
|
if variable <> nil then
|
|
Error(55);
|
|
end; {if}
|
|
if variable <> nil then begin
|
|
variable^.disp := disp;
|
|
variable^.bitdisp := bitdisp;
|
|
variable^.bitsize := long(expressionValue).lsw;
|
|
tPtr := variable^.itype;
|
|
end {if}
|
|
else
|
|
tPtr := fieldDeclSpecifiers.typeSpec;
|
|
bitdisp := bitdisp+long(expressionValue).lsw;
|
|
if kind = unionType then
|
|
if ((bitDisp+7) div 8) > maxDisp then
|
|
maxDisp := ((bitDisp+7) div 8);
|
|
if (tPtr^.kind <> scalarType)
|
|
or not (tPtr^.baseType in
|
|
[cgByte,cgUByte,cgWord,cgUWord,cgLong,cgULong])
|
|
or (expressionValue > tPtr^.size*8)
|
|
or ((expressionValue > 1) and (tPtr^.cType = ctBool)) then
|
|
Error(115);
|
|
if _Alignassy in fieldDeclSpecifiers.declarationModifiers then
|
|
Error(142);
|
|
end {if}
|
|
else if variable <> nil then begin
|
|
if bitdisp <> 0 then begin
|
|
disp := disp+((bitDisp+7) div 8);
|
|
bitdisp := 0;
|
|
end; {if}
|
|
variable^.disp := disp;
|
|
variable^.bitdisp := bitdisp;
|
|
variable^.bitsize := 0;
|
|
if anonMember then begin
|
|
tfl := variable^.itype^.fieldList;
|
|
while tfl <> nil do begin
|
|
ufl := pointer(Malloc(sizeof(identRecord)));
|
|
ufl^ := tfl^;
|
|
AddField(ufl, variable);
|
|
ufl^.disp := ufl^.disp + disp;
|
|
tfl := tfl^.next;
|
|
end; {while}
|
|
end; {if}
|
|
disp := disp + variable^.itype^.size;
|
|
if disp > maxDisp then
|
|
maxDisp := disp;
|
|
if variable^.itype^.size = 0 then
|
|
if (variable^.itype^.kind = arrayType)
|
|
and (disp > 0) then begin {handle flexible array member}
|
|
didFlexibleArray := true;
|
|
tp^.flexibleArrayMember := true;
|
|
end {if}
|
|
else
|
|
Error(117);
|
|
end {if}
|
|
else
|
|
Error(116);
|
|
|
|
if variable <> nil then {check for a const member}
|
|
tPtr := variable^.itype
|
|
else
|
|
tPtr := fieldDeclSpecifiers.typeSpec;
|
|
while tPtr^.kind in [definedType,arrayType] do begin
|
|
if tqConst in tPtr^.qualifiers then
|
|
tp^.constMember := true;
|
|
if tPtr^.kind = definedType then
|
|
tPtr := tPtr^.dType
|
|
else {if tPtr^.kind = arrayType then}
|
|
tPtr := tPtr^.aType;
|
|
end; {while}
|
|
if tqConst in tPtr^.qualifiers then
|
|
tp^.constMember := true;
|
|
if tPtr^.kind in [structType,unionType] then begin
|
|
if tPtr^.constMember then
|
|
tp^.constMember := true;
|
|
if tPtr^.flexibleArrayMember then
|
|
if kind = structType then
|
|
Error(169)
|
|
else {if kind = unionType then}
|
|
tp^.flexibleArrayMember := true;
|
|
end; {if}
|
|
|
|
if token.kind = commach then {allow repeated declarations}
|
|
begin
|
|
NextToken;
|
|
done := false;
|
|
end {if}
|
|
else
|
|
done := true;
|
|
until done or (token.kind = eofsy);
|
|
Match(semicolonch,22); {insist on a closing ';'}
|
|
end; {while}
|
|
if fl <> nil then begin
|
|
ufl := nil; {reverse the field list}
|
|
while fl <> nil do begin
|
|
tfl := fl;
|
|
fl := fl^.next;
|
|
tfl^.next := ufl;
|
|
ufl := tfl;
|
|
end; {while}
|
|
if kind = structType then begin {return the field list}
|
|
if bitdisp <> 0 then
|
|
disp := disp+((bitDisp+7) div 8);
|
|
tp^.size := disp;
|
|
end {if}
|
|
else
|
|
tp^.size := maxDisp;
|
|
tp^.fieldList := ufl;
|
|
end {if}
|
|
else
|
|
Error(26); {error if no named declarations}
|
|
isForwardDeclared := lisForwardDeclared; {restore the forward flag}
|
|
doingParameters := ldoingParameters; {restore the parameters flag}
|
|
end; {FieldList}
|
|
|
|
|
|
procedure ResolveType;
|
|
|
|
{ Resolve a set of type specifier keywords to a type }
|
|
|
|
begin {ResolveType}
|
|
{See C17 6.7.2}
|
|
if typeSpecifiers = [voidsy] then
|
|
myTypeSpec := voidPtr
|
|
else if typeSpecifiers = [charsy] then
|
|
myTypeSpec := charPtr
|
|
else if typeSpecifiers = [signedsy,charsy] then
|
|
myTypeSpec := sCharPtr
|
|
else if typeSpecifiers = [unsignedsy,charsy] then
|
|
myTypeSpec := uCharPtr
|
|
else if (typeSpecifiers = [shortsy])
|
|
or (typeSpecifiers = [signedsy,shortsy])
|
|
or (typeSpecifiers = [shortsy,intsy])
|
|
or (typeSpecifiers = [signedsy,shortsy,intsy]) then
|
|
myTypeSpec := shortPtr
|
|
else if (typeSpecifiers = [unsignedsy,shortsy])
|
|
or (typeSpecifiers = [unsignedsy,shortsy,intsy]) then
|
|
myTypeSpec := uShortPtr
|
|
else if (typeSpecifiers = [intsy])
|
|
or (typeSpecifiers = [signedsy])
|
|
or (typeSpecifiers = [signedsy,intsy]) then begin
|
|
if unix_1 then
|
|
myTypeSpec := int32Ptr
|
|
else
|
|
myTypeSpec := intPtr;
|
|
end {else if}
|
|
else if (typeSpecifiers = [unsignedsy])
|
|
or (typeSpecifiers = [unsignedsy,intsy]) then begin
|
|
if unix_1 then
|
|
myTypeSpec := uInt32Ptr
|
|
else
|
|
myTypeSpec := uIntPtr;
|
|
end {else if}
|
|
else if (typeSpecifiers = [longsy])
|
|
or (typeSpecifiers = [signedsy,longsy])
|
|
or (typeSpecifiers = [longsy,intsy])
|
|
or (typeSpecifiers = [signedsy,longsy,intsy]) then begin
|
|
if isLongLong then
|
|
myTypeSpec := longLongPtr
|
|
else
|
|
myTypeSpec := longPtr;
|
|
end {else if}
|
|
else if (typeSpecifiers = [unsignedsy,longsy])
|
|
or (typeSpecifiers = [unsignedsy,longsy,intsy]) then begin
|
|
if isLongLong then
|
|
myTypeSpec := uLongLongPtr
|
|
else
|
|
myTypeSpec := uLongPtr;
|
|
end {else if}
|
|
else if typeSpecifiers = [floatsy] then
|
|
myTypeSpec := floatPtr
|
|
else if typeSpecifiers = [doublesy] then
|
|
myTypeSpec := doublePtr
|
|
else if (typeSpecifiers = [longsy,doublesy])
|
|
or (typeSpecifiers = [extendedsy]) then
|
|
myTypeSpec := extendedPtr
|
|
else if typeSpecifiers = [compsy] then
|
|
myTypeSpec := compPtr
|
|
else if typeSpecifiers = [_Boolsy] then begin
|
|
myTypeSpec := boolPtr;
|
|
end {else if}
|
|
else
|
|
Error(badNextTokenError);
|
|
end; {ResolveType}
|
|
|
|
|
|
begin {DeclarationSpecifiers}
|
|
myTypeSpec := nil;
|
|
myIsForwardDeclared := false; {not doing a forward reference (yet)}
|
|
myDeclarationModifiers := [];
|
|
myStorageClass := ident;
|
|
typeQualifiers := [];
|
|
typeSpecifiers := [];
|
|
typeDone := false;
|
|
isLongLong := false;
|
|
while token.kind in allowedTokens do begin
|
|
case token.kind of
|
|
{storage class specifiers}
|
|
autosy,externsy,registersy,staticsy,typedefsy: begin
|
|
myDeclarationModifiers := myDeclarationModifiers + [token.kind];
|
|
if myStorageClass <> ident then begin
|
|
if typeDone or (typeSpecifiers <> []) then
|
|
Error(badNextTokenError)
|
|
else
|
|
Error(26);
|
|
end; {if}
|
|
myStorageClass := token.kind;
|
|
if not doingFunction then
|
|
if token.kind = autosy then
|
|
Error(62);
|
|
if doingParameters then begin
|
|
if token.kind <> registersy then
|
|
Error(87);
|
|
end {if}
|
|
else if myStorageClass in [staticsy,typedefsy] then begin
|
|
{Error if we may have allocated type info in local pool.}
|
|
{This should not come up with current use of MM pools. }
|
|
if not useGlobalPool then
|
|
if typeDone then
|
|
Error(57);
|
|
useGlobalPool := true;
|
|
end; {else if}
|
|
if doingForLoopClause1 then
|
|
if not (myStorageClass in [autosy,registersy]) then
|
|
Error(127);
|
|
if _Thread_localsy in myDeclarationModifiers then
|
|
if not (myStorageClass in [staticsy,externsy]) then
|
|
Error(177);
|
|
NextToken;
|
|
end;
|
|
|
|
_Thread_localsy: begin
|
|
myDeclarationModifiers := myDeclarationModifiers + [token.kind];
|
|
if doingParameters then
|
|
Error(87);
|
|
if not (myStorageClass in [ident,staticsy,externsy]) then
|
|
Error(177);
|
|
NextToken;
|
|
end;
|
|
|
|
{function specifiers}
|
|
inlinesy,_Noreturnsy,asmsy,pascalsy: begin
|
|
myDeclarationModifiers := myDeclarationModifiers + [token.kind];
|
|
NextToken;
|
|
end;
|
|
|
|
{type qualifiers}
|
|
constsy: begin
|
|
myDeclarationModifiers := myDeclarationModifiers + [token.kind];
|
|
typeQualifiers := typeQualifiers + [tqConst];
|
|
NextToken;
|
|
end;
|
|
|
|
volatilesy: begin
|
|
myDeclarationModifiers := myDeclarationModifiers + [token.kind];
|
|
typeQualifiers := typeQualifiers + [tqVolatile];
|
|
volatile := true;
|
|
NextToken;
|
|
end;
|
|
|
|
restrictsy: begin
|
|
myDeclarationModifiers := myDeclarationModifiers + [token.kind];
|
|
typeQualifiers := typeQualifiers + [tqRestrict];
|
|
if typeDone or (typeSpecifiers <> []) then
|
|
if (myTypeSpec^.kind <> pointerType)
|
|
or (myTypeSpec^.pType^.kind = functionType) then
|
|
Error(143);
|
|
NextToken;
|
|
end;
|
|
|
|
_Atomicsy: begin
|
|
myDeclarationModifiers := myDeclarationModifiers + [token.kind];
|
|
Error(137);
|
|
NextToken;
|
|
if token.kind = lparench then begin
|
|
{_Atomic(typename) as type specifier}
|
|
if typeDone or (typeSpecifiers <> []) then
|
|
Error(badNextTokenError);
|
|
NextToken;
|
|
myTypeSpec := TypeName;
|
|
Match(rparench, 12);
|
|
end; {if}
|
|
typeDone := true;
|
|
end;
|
|
|
|
{type specifiers}
|
|
unsignedsy,signedsy,intsy,longsy,charsy,shortsy,floatsy,doublesy,voidsy,
|
|
compsy,extendedsy,_Boolsy: begin
|
|
if typeDone then
|
|
Error(badNextTokenError)
|
|
else if token.kind in typeSpecifiers then begin
|
|
if (token.kind = longsy) and
|
|
((myTypeSpec = longPtr) or (myTypeSpec = uLongPtr)) then begin
|
|
isLongLong := true;
|
|
ResolveType;
|
|
end
|
|
else
|
|
Error(badNextTokenError);
|
|
end {if}
|
|
else begin
|
|
if restrictsy in myDeclarationModifiers then begin
|
|
myDeclarationModifiers := myDeclarationModifiers - [restrictsy];
|
|
Error(143);
|
|
end; {if}
|
|
typeSpecifiers := typeSpecifiers + [token.kind];
|
|
ResolveType;
|
|
end; {else}
|
|
NextToken;
|
|
end;
|
|
|
|
_Complexsy,_Imaginarysy: begin
|
|
Error(136);
|
|
NextToken;
|
|
end;
|
|
|
|
enumsy: begin {enum}
|
|
if typeDone or (typeSpecifiers <> []) then
|
|
Error(badNextTokenError)
|
|
else if restrictsy in myDeclarationModifiers then
|
|
Error(143);
|
|
NextToken; {skip the 'enum' token}
|
|
if token.kind in [ident,typedef] then begin {handle a type definition}
|
|
ttoken := token;
|
|
NextToken;
|
|
variable :=
|
|
FindSymbol(ttoken, tagSpace, token.kind = lbracech, true);
|
|
if token.kind = lbracech then begin
|
|
if (variable <> nil) and (variable^.itype^.kind = enumType) then
|
|
if not looseTypeChecks then
|
|
Error(53);
|
|
end {if}
|
|
else
|
|
if (variable <> nil) and (variable^.itype^.kind = enumType) then
|
|
begin
|
|
if looseTypeChecks then
|
|
declaredTagOrEnumConst := true;
|
|
goto 1;
|
|
end {if}
|
|
else begin
|
|
declaredTagOrEnumConst := true;
|
|
if not looseTypeChecks then
|
|
Error(171);
|
|
end; {else}
|
|
tPtr := pointer(Malloc(sizeof(typeRecord)));
|
|
tPtr^.size := cgWordSize;
|
|
tPtr^.saveDisp := 0;
|
|
tPtr^.qualifiers := [];
|
|
tPtr^.kind := enumType;
|
|
variable :=
|
|
NewSymbol(ttoken.name, tPtr, ident, tagSpace, defined, false);
|
|
end {if}
|
|
else if token.kind <> lbracech then
|
|
Error(9);
|
|
enumVal := 0; {set the default value}
|
|
if token.kind = lbracech then begin
|
|
declaredTagOrEnumConst := true;
|
|
NextToken; {skip the '{'}
|
|
repeat {declare the enum constants}
|
|
tPtr := pointer(Malloc(sizeof(typeRecord)));
|
|
tPtr^.size := cgWordSize;
|
|
tPtr^.saveDisp := 0;
|
|
tPtr^.qualifiers := [];
|
|
tPtr^.kind := enumConst;
|
|
if token.kind = ident then begin
|
|
variable := NewSymbol(token.name, tPtr, ident, variableSpace,
|
|
defined, false);
|
|
NextToken;
|
|
end {if}
|
|
else
|
|
Error(9);
|
|
if token.kind = eqch then begin {handle explicit enumeration values}
|
|
NextToken;
|
|
Expression(arrayExpression,[commach,rbracech]);
|
|
enumVal := long(expressionValue).lsw;
|
|
if enumVal <> expressionValue then
|
|
Error(6)
|
|
else if enumVal < 0 then
|
|
if expressionType^.kind = scalarType then
|
|
if expressionType^.baseType in [cgULong,cgUQuad] then
|
|
Error(6);
|
|
end; {if}
|
|
tPtr^.eval := enumVal; {set the enumeration constant value}
|
|
enumVal := enumVal+1; {inc the default enumeration value}
|
|
if token.kind = commach then {next enumeration...}
|
|
begin
|
|
done := false;
|
|
NextToken;
|
|
{kws -- allow trailing , in enum }
|
|
{ C99 6.7.2.2 Enumeration specifiers }
|
|
if token.kind = rbracech then done := true;
|
|
end {if}
|
|
else
|
|
done := true;
|
|
until done or (token.kind = eofsy);
|
|
if token.kind = rbracech then
|
|
NextToken
|
|
else begin
|
|
Error(23);
|
|
SkipStatement;
|
|
end; {else}
|
|
end; {if}
|
|
1: myTypeSpec := intPtr;
|
|
typeDone := true;
|
|
end;
|
|
|
|
structsy, {struct}
|
|
unionsy: begin {union}
|
|
if typeDone or (typeSpecifiers <> []) then
|
|
Error(badNextTokenError)
|
|
else if restrictsy in myDeclarationModifiers then
|
|
Error(143);
|
|
globalStruct := false; {we didn't make it global}
|
|
if token.kind = structsy then {set the type kind to use}
|
|
tKind := structType
|
|
else
|
|
tKind := unionType;
|
|
structPtr := nil; {no record, yet}
|
|
structTypePtr := defaultStruct; {use int as a default type}
|
|
NextToken; {skip 'struct' or 'union'}
|
|
if token.kind in [ident,typedef] {if there is a struct name then...}
|
|
then begin
|
|
{look up the name}
|
|
structPtr := FindSymbol(token, tagSpace, true, true);
|
|
ttoken := token; {record the structure name}
|
|
NextToken; {skip the structure name}
|
|
if (token.kind = lbracech) or
|
|
((token.kind = semicolonch) and (myDeclarationModifiers = []))
|
|
then
|
|
declaredTagOrEnumConst := true;
|
|
if structPtr = nil then begin {if the name hasn't been defined then...}
|
|
if token.kind <> lbracech then
|
|
if (token.kind <> semicolonch) or
|
|
(myDeclarationModifiers <> []) then
|
|
structPtr := FindSymbol(ttoken, tagSpace, false, true);
|
|
if structPtr <> nil then
|
|
structTypePtr := structPtr^.itype
|
|
else begin
|
|
myIsForwardDeclared := true;
|
|
globalStruct := doingParameters and (token.kind <> lbracech);
|
|
if globalStruct then begin
|
|
lUseGlobalPool := useGlobalPool;
|
|
useGlobalPool := true;
|
|
end; {if}
|
|
structTypePtr := pointer(Calloc(sizeof(typeRecord)));
|
|
{structTypePtr^.size := 0;}
|
|
{structTypePtr^.saveDisp := 0;}
|
|
{structTypePtr^.qualifiers := [];}
|
|
structTypePtr^.kind := tkind;
|
|
{structTypePtr^.fieldList := nil;}
|
|
{structTypePtr^.sName := nil;}
|
|
{structTypePtr^.constMember := false;}
|
|
{structTypePtr^.flexibleArrayMember := false;}
|
|
structPtr := NewSymbol(ttoken.name, structTypePtr, ident,
|
|
tagSpace, defined, false);
|
|
structTypePtr^.sName := structPtr^.name;
|
|
declaredTagOrEnumConst := true;
|
|
end;
|
|
end {if}
|
|
{the name has been defined, so...}
|
|
else if structPtr^.itype^.kind <> tKind then begin
|
|
Error(42); {it's an error if it's not a struct}
|
|
declaredTagOrEnumConst := true; {avoid extra errors}
|
|
structPtr := nil;
|
|
end {else}
|
|
else begin {record the existing structure type}
|
|
structTypePtr := structPtr^.itype;
|
|
end; {else}
|
|
end {if}
|
|
else if token.kind <> lbracech then begin
|
|
Error(9); {its an error if there's no name or struct}
|
|
declaredTagOrEnumConst := true; {avoid extra errors}
|
|
end; {else if}
|
|
2: if token.kind = lbracech then {handle a structure definition...}
|
|
begin {error if we already have one!}
|
|
if (structTypePtr <> defaultStruct)
|
|
and (structTypePtr^.fieldList <> nil) then begin
|
|
Error(53);
|
|
structPtr := nil;
|
|
end; {if}
|
|
NextToken; {skip the '{'}
|
|
if structTypePtr = defaultStruct then begin
|
|
structTypePtr := pointer(Calloc(sizeof(typeRecord)));
|
|
{structTypePtr^.size := 0;}
|
|
{structTypePtr^.saveDisp := 0;}
|
|
{structTypePtr^.qualifiers := [];}
|
|
structTypePtr^.kind := tkind;
|
|
{structTypePtr^.fieldList := nil;}
|
|
{structTypePtr^.sName := nil;}
|
|
{structTypePtr^.constMember := false;}
|
|
{structTypePtr^.flexibleArrayMember := false;}
|
|
end; {if}
|
|
if structPtr <> nil then
|
|
structPtr^.itype := structTypePtr;
|
|
FieldList(structTypePtr,tKind); {define the fields}
|
|
if token.kind = rbracech then {insist on a closing rbrace}
|
|
NextToken
|
|
else begin
|
|
Error(23);
|
|
SkipStatement;
|
|
end; {else}
|
|
end; {if}
|
|
if globalStruct then
|
|
useGlobalPool := lUseGlobalPool;
|
|
myTypeSpec := structTypePtr;
|
|
if tKind = structType then
|
|
myDeclarationModifiers := myDeclarationModifiers + [structsy]
|
|
else
|
|
myDeclarationModifiers := myDeclarationModifiers + [unionsy];
|
|
typeDone := true;
|
|
end;
|
|
|
|
typedef: begin {named type definition}
|
|
if (typeSpecifiers = []) and not typeDone then begin
|
|
myTypeSpec := token.symbolPtr^.itype;
|
|
if restrictsy in myDeclarationModifiers then
|
|
if (myTypeSpec^.kind <> pointerType)
|
|
or (myTypeSpec^.pType^.kind = functionType) then
|
|
Error(143);
|
|
NextToken;
|
|
typeDone := true;
|
|
end {if}
|
|
else {interpret as declarator, not type specifier}
|
|
goto 3;
|
|
end;
|
|
|
|
{alignment specifier}
|
|
_Alignassy: begin
|
|
myDeclarationModifiers := myDeclarationModifiers + [token.kind];
|
|
NextToken;
|
|
Match(lparench, 13);
|
|
if token.kind in specifierQualifierListElement then begin
|
|
tPtr := TypeName;
|
|
with tPtr^ do
|
|
if (size = 0) or ((kind = arrayType) and (elements = 0)) then
|
|
Error(133);
|
|
end {if}
|
|
else begin
|
|
Expression(arrayExpression, [rparench]);
|
|
if (expressionValue <> 0) and (expressionValue <> 1) then
|
|
Error(138);
|
|
end;
|
|
Match(rparench, 12);
|
|
end;
|
|
|
|
otherwise: begin
|
|
Error(57);
|
|
NextToken;
|
|
end;
|
|
end; {case}
|
|
end; {while}
|
|
3:
|
|
isForwardDeclared := myIsForwardDeclared;
|
|
declSpecifiers.declarationModifiers := myDeclarationModifiers;
|
|
if _Thread_localsy in myDeclarationModifiers then
|
|
if myStorageClass = ident then
|
|
if doingFunction then
|
|
Error(177);
|
|
if myTypeSpec = nil then begin
|
|
myTypeSpec := intPtr; {under C89, default type is int}
|
|
if (lint & lintC99Syntax) <> 0 then
|
|
Error(151);
|
|
end; {if}
|
|
declSpecifiers.typeSpec := {apply type qualifiers}
|
|
MakeQualifiedType(myTypeSpec, typeQualifiers);
|
|
declSpecifiers.storageClass := myStorageClass;
|
|
end; {DeclarationSpecifiers}
|
|
|
|
|
|
{-- Externally available subroutines ---------------------------}
|
|
|
|
procedure DoDeclaration {doingPrototypes: boolean};
|
|
|
|
{ process a variable or function declaration }
|
|
{ }
|
|
{ parameters: }
|
|
{ doingPrototypes - is this a prototype parameter decl? }
|
|
|
|
label 1,2,3,4;
|
|
|
|
var
|
|
declarationSpecifierFound: boolean; {has some decl specifier been found?}
|
|
first: boolean; {handling first declarator in decl?}
|
|
fName: stringPtr; {for forming uppercase names}
|
|
i: integer; {loop variable}
|
|
isAsm: boolean; {has the asm modifier been used?}
|
|
isInline: boolean; {has the inline specifier been used?}
|
|
isNoreturn: boolean; {has the _Noreturn specifier been used?}
|
|
alignmentSpecified: boolean; {was an alignment explicitly specified?}
|
|
lDoingParameters: boolean; {local copy of doingParameters}
|
|
lInhibitHeader: boolean; {local copy of inhibitHeader}
|
|
lp,tlp,tlp2: identPtr; {for tracing parameter list}
|
|
lUseGlobalPool: boolean; {local copy of useGlobalPool}
|
|
nextPdisp: integer; {for calculating parameter disps}
|
|
p1,p2,p3: parameterPtr; {for reversing prototyped parameters}
|
|
variable: identPtr; {pointer to the variable being declared}
|
|
fnType: typePtr; {function type}
|
|
segType: integer; {segment type}
|
|
tp: typePtr; {for tracing type lists}
|
|
startLine: longint; {line where this declaration starts}
|
|
declSpecifiers: declSpecifiersRecord; {type & specifiers for the declaration}
|
|
|
|
|
|
procedure CheckArray (v: identPtr; firstVariable: boolean);
|
|
|
|
{ make sure all required array sizes are specified }
|
|
{ }
|
|
{ parameters: }
|
|
{ v - pointer to the identifier to check }
|
|
{ firstVariable - can the first array subscript be of a }
|
|
{ non-fixed size? }
|
|
|
|
label 1;
|
|
|
|
var
|
|
tp: typePtr; {work pointer}
|
|
|
|
begin {CheckArray}
|
|
if v <> nil then begin {skip check if there's no variable}
|
|
tp := v^.itype; {initialize the type pointer}
|
|
while tp <> nil do begin {check all types}
|
|
if tp^.kind = arrayType then {if it's an array with an unspecified }
|
|
begin
|
|
if tp^.elements = 0 then { size and an unspecified size is not }
|
|
if not firstVariable then { allowed here, flag an error. }
|
|
begin
|
|
Error(49);
|
|
goto 1;
|
|
end; {if}
|
|
if tp^.aType^.size = 0 then begin
|
|
Error(123);
|
|
goto 1;
|
|
end; {if}
|
|
if tp^.aType^.kind in [structType,unionType] then
|
|
if tp^.aType^.flexibleArrayMember then
|
|
Error(169);
|
|
end; {if}
|
|
firstVariable := false; {unspecified sizes are only allowed in }
|
|
{ the first subscript }
|
|
case tp^.kind of {next type...}
|
|
arrayType:
|
|
tp := tp^.aType;
|
|
pointerType: begin
|
|
tp := tp^.pType;
|
|
firstVariable := true; {(also allowed for pointers to arrays)}
|
|
end;
|
|
functionType:
|
|
tp := tp^.fType;
|
|
otherwise:
|
|
tp := nil;
|
|
end; {case}
|
|
end; {while}
|
|
end; {if}
|
|
1:
|
|
end; {CheckArray}
|
|
|
|
|
|
procedure SegmentStatement;
|
|
|
|
{ compile a segment statement }
|
|
{ }
|
|
{ statement syntax: }
|
|
{ }
|
|
{ 'segment' string-constant [',' 'dynamic'] }
|
|
|
|
var
|
|
i: integer; {loop variable}
|
|
len: integer; {segment name length}
|
|
|
|
begin {SegmentStatement}
|
|
NextToken;
|
|
if token.kind = stringConst then begin
|
|
for i := 1 to 10 do begin
|
|
defaultSegment[i] := chr(0);
|
|
currentSegment[i] := chr(0);
|
|
end; {for}
|
|
len := token.sval^.length;
|
|
if len > 10 then
|
|
len := 10;
|
|
for i := 1 to len do
|
|
defaultSegment[i] := token.sval^.str[i];
|
|
for i := 1 to len do
|
|
currentSegment[i] := token.sval^.str[i];
|
|
FlagPragmas(p_segment);
|
|
NextToken;
|
|
if token.kind = commach then begin
|
|
NextToken;
|
|
if token.kind = ident then begin
|
|
if token.name^ = 'dynamic' then
|
|
segmentKind := $8000
|
|
else Error(84);
|
|
NextToken;
|
|
end {if}
|
|
else Error(84);
|
|
end {if}
|
|
else
|
|
segmentKind := 0;
|
|
defaultSegmentKind := segmentKind;
|
|
inhibitHeader := lInhibitHeader;
|
|
Match(semicolonch,22);
|
|
inhibitHeader := true;
|
|
end {if}
|
|
else begin
|
|
Error(83);
|
|
SkipStatement;
|
|
end; {else}
|
|
end; {SegmentStatement}
|
|
|
|
|
|
function InPartialList (fName: stringPtr): boolean;
|
|
|
|
{ See if the function is in the partial compile list. }
|
|
{ }
|
|
{ If the function is in the list, the function name is }
|
|
{ removed from the list, and true is returned. If not, }
|
|
{ false is returned. }
|
|
{ }
|
|
{ parameters: }
|
|
{ fName - name of the function to check for }
|
|
|
|
label 1,2;
|
|
|
|
var
|
|
ch: char; {work character}
|
|
i,j: integer; {loop variable}
|
|
len: integer; {length of fName}
|
|
|
|
begin {InPartialList}
|
|
i := partialFileGS.theString.size; {strip trailing blanks}
|
|
while (i > 0) and (partialFileGS.theString.theString[i] = ' ') do begin
|
|
partialFileGS.theString.theString[i] := chr(0);
|
|
i := i-1;
|
|
end; {while}
|
|
while partialFileGS.theString.theString[1] = ' ' do {skip leading blanks}
|
|
for i := 1 to partialFileGS.theString.size do
|
|
partialFileGS.theString.theString[i] :=
|
|
partialFileGS.theString.theString[i+1];
|
|
InPartialList := true; {assume success}
|
|
i := 1; {scan the name list}
|
|
len := length(fName^);
|
|
while partialFileGS.theString.theString[i] <> chr(0) do begin
|
|
for j := 1 to len do begin
|
|
if partialFileGS.theString.theString[i+j-1] <> fName^[j] then
|
|
goto 1;
|
|
end; {for}
|
|
if partialFileGS.theString.theString[i+len] in [' ', chr(0)] then begin
|
|
|
|
{found a match - remove from list & return}
|
|
j := i+len;
|
|
while partialFileGS.theString.theString[j] = ' ' do
|
|
j := j+1;
|
|
repeat
|
|
ch := partialFileGS.theString.theString[j];
|
|
partialFileGS.theString.theString[i] := ch;
|
|
i := i+1;
|
|
j := j+1;
|
|
until ch = chr(0);
|
|
goto 2;
|
|
end; {if}
|
|
1: {no match - skip to next name}
|
|
while not (partialFileGS.theString.theString[i] in [chr(0), ' ']) do
|
|
i := i+1;
|
|
while partialFileGS.theString.theString[i] = ' ' do
|
|
i := i+1;
|
|
end; {while}
|
|
InPartialList := false; {no match found}
|
|
2:
|
|
end; {InPartialList}
|
|
|
|
|
|
procedure SkipFunction (isAsm: boolean);
|
|
|
|
{ Skip a function body for a partial compile }
|
|
{ }
|
|
{ Parameters: }
|
|
{ isAsm - are we compiling an asm function? }
|
|
|
|
var
|
|
braceCount: integer; {# of unmatched { chars}
|
|
|
|
begin {SkipFunction}
|
|
Match(lbracech,27); {skip to the closing rbrackch}
|
|
braceCount := 1;
|
|
while (not (token.kind = eofsy)) and (braceCount <> 0) do begin
|
|
if token.kind = lbracech then
|
|
braceCount := braceCount+1
|
|
else if token.kind = rbracech then
|
|
braceCount := braceCount-1;
|
|
NextToken;
|
|
end; {while}
|
|
nameFound := false; {no pc_nam for the next function (yet)}
|
|
doingFunction := false; {no longer doing a function}
|
|
end; {SkipFunction}
|
|
|
|
|
|
begin {DoDeclaration}
|
|
lInhibitHeader:= inhibitHeader;
|
|
inhibitHeader := true; {block imbedded includes in headers}
|
|
if token.kind = _Static_assertsy then begin
|
|
DoStaticAssert;
|
|
goto 4;
|
|
end; {if}
|
|
lDoingParameters := doingParameters; {record the status}
|
|
first := true; {preparing to handle first declarator}
|
|
if doingPrototypes then {prototypes implies a parm list}
|
|
doingParameters := true
|
|
else
|
|
lastParameter := nil; {init parm list if we're not doing prototypes}
|
|
startLine := lineNumber;
|
|
if not doingFunction then {handle any segment statements}
|
|
while token.kind = segmentsy do
|
|
SegmentStatement;
|
|
lUseGlobalPool := useGlobalPool;
|
|
{handle a TypeSpecifier/declarator}
|
|
declarationSpecifierFound := token.kind in declarationSpecifiersElement;
|
|
declaredTagOrEnumConst := false;
|
|
DeclarationSpecifiers(declSpecifiers, declarationSpecifiersElement, 176);
|
|
isAsm := asmsy in declSpecifiers.declarationModifiers;
|
|
isInline := inlinesy in declSpecifiers.declarationModifiers;
|
|
isNoreturn := _Noreturnsy in declSpecifiers.declarationModifiers;
|
|
alignmentSpecified := _Alignassy in declSpecifiers.declarationModifiers;
|
|
if token.kind = semicolonch then
|
|
if not doingPrototypes then
|
|
if not declaredTagOrEnumConst then
|
|
Error(176);
|
|
|
|
3:
|
|
isFunction := false; {assume it's not a function}
|
|
variable := nil;
|
|
Declarator(declSpecifiers, variable, variableSpace, doingPrototypes);
|
|
if variable = nil then begin
|
|
inhibitHeader := lInhibitHeader;
|
|
if token.kind = semicolonch then begin
|
|
if not first then
|
|
Error(176);
|
|
NextToken;
|
|
end {if}
|
|
else begin
|
|
Error(22);
|
|
SkipStatement;
|
|
end; {else}
|
|
goto 1;
|
|
end; {if}
|
|
|
|
{handle a function declaration}
|
|
if isFunction then begin
|
|
|
|
if not declarationSpecifierFound then
|
|
if first then
|
|
if doingPrototypes or (token.kind in [commach,semicolonch]) then
|
|
Error(26)
|
|
else
|
|
if (lint & lintNoFnType) <> 0 then
|
|
if (lint & lintC99Syntax) = 0 then
|
|
Error(104);
|
|
if doingParameters then {a function cannot be a parameter}
|
|
Error(28);
|
|
fnType := variable^.itype; {get the type of the function}
|
|
while (fnType <> nil) and (fnType^.kind <> functionType) do
|
|
case fnType^.kind of
|
|
arrayType : fnType := fnType^.aType;
|
|
pointerType: fnType := fnType^.pType;
|
|
definedType: fnType := fnType^.dType;
|
|
otherwise : fnType := nil;
|
|
end; {case}
|
|
if fnType = nil then begin
|
|
SkipStatement;
|
|
goto 1;
|
|
end; {if}
|
|
if isInline or isNoreturn then
|
|
if not (isNewDeskAcc or isClassicDeskAcc or isCDev or isNBA or isXCMD) then
|
|
if variable^.name^ = 'main' then
|
|
Error(181);
|
|
if alignmentSpecified then
|
|
Error(142);
|
|
if _Thread_localsy in declSpecifiers.declarationModifiers then
|
|
Error(178);
|
|
|
|
{handle functions in the parameter list}
|
|
if doingPrototypes then
|
|
PopTable
|
|
|
|
{external or forward declaration}
|
|
else if token.kind in [commach,semicolonch,inlinesy] then begin
|
|
if token.kind = inlinesy then {handle tool declarations}
|
|
with fnType^ do begin
|
|
NextToken;
|
|
Match(lparench,13);
|
|
if token.kind in
|
|
[intconst,uintconst,ushortconst,charconst,scharconst,ucharconst]
|
|
then begin
|
|
toolNum := token.ival;
|
|
NextToken;
|
|
end {if}
|
|
else
|
|
Error(18);
|
|
Match(commach,86);
|
|
if token.kind in [longconst,ulongconst] then begin
|
|
dispatcher := token.lval;
|
|
NextToken;
|
|
end {if}
|
|
else if token.kind in
|
|
[intconst,uintconst,ushortconst,charconst,scharconst,ucharconst]
|
|
then begin
|
|
dispatcher := token.ival;
|
|
NextToken;
|
|
end {if}
|
|
else
|
|
Error(18);
|
|
Match(rparench,12);
|
|
end; {with}
|
|
doingParameters := doingPrototypes; {not doing parms any more}
|
|
if token.kind = semicolonch then begin
|
|
inhibitHeader := lInhibitHeader;
|
|
NextToken; {skip the trailing semicolon}
|
|
end {if}
|
|
else if (token.kind = commach) and (not doingPrototypes) then begin
|
|
PopTable; {pop the symbol table}
|
|
NextToken; {allow further declarations}
|
|
first := false;
|
|
goto 3;
|
|
end {else if}
|
|
else begin
|
|
Error(22);
|
|
SkipStatement;
|
|
end; {else}
|
|
PopTable; {pop the symbol table}
|
|
end {if}
|
|
|
|
{cannot imbed functions...}
|
|
else if doingFunction then begin
|
|
Error(28);
|
|
while token.kind <> eofsy do
|
|
NextToken;
|
|
end {if}
|
|
|
|
{local declaration}
|
|
else begin
|
|
if (not first) or (declSpecifiers.storageClass = typedefsy) then
|
|
Error(22);
|
|
if variable^.state = defined then
|
|
Error(42);
|
|
ftype := fnType^.ftype; {record the type of the function}
|
|
while fType^.kind = definedType do
|
|
fType := fType^.dType;
|
|
fIsNoreturn := isNoreturn; {record if function is _Noreturn}
|
|
variable^.state := defined; {note that the function is defined}
|
|
pfunc := variable; {set the identifier for parm checks}
|
|
doingFunction := true; {read the parameter list}
|
|
doingParameters := true;
|
|
{declare the parameters}
|
|
lp := lastParameter; {(save now; it's volatile)}
|
|
while not (token.kind in [lbracech,eofsy]) do
|
|
if token.kind in declarationSpecifiersElement then
|
|
DoDeclaration(false)
|
|
else begin
|
|
Error(27);
|
|
NextToken;
|
|
end; {else}
|
|
if numberOfParameters <> 0 then {default K&R parm type is int}
|
|
begin
|
|
tlp := lp;
|
|
while tlp <> nil do begin
|
|
if tlp^.itype = nil then begin
|
|
tlp^.itype := intPtr;
|
|
if (lint & lintC99Syntax) <> 0 then
|
|
if (lint & lintNotPrototyped) = 0 then
|
|
Error(147); {C99+ require K&R params to be declared}
|
|
end; {if}
|
|
tlp := tlp^.pnext;
|
|
end; {while}
|
|
end; {if}
|
|
tlp := lp; {make sure all parameters have an}
|
|
while tlp <> nil do begin { identifier and a complete type }
|
|
if tlp^.name^ = '?' then begin
|
|
Error(113);
|
|
tlp := nil;
|
|
end {if}
|
|
else begin
|
|
if tlp^.itype^.size = 0 then
|
|
if not (tlp^.itype^.kind in [arrayType,functionType]) then
|
|
Error(148);
|
|
tlp := tlp^.pnext;
|
|
end; {else}
|
|
end; {while}
|
|
doingParameters := false;
|
|
fName := variable^.name; {skip if this is not needed for a }
|
|
if doingPartial then { partial compile }
|
|
if not InPartialList(fName) then begin
|
|
SkipFunction(isAsm);
|
|
goto 2;
|
|
end; {if}
|
|
TermHeader; {make sure the header file is closed}
|
|
if progress then {write progress information}
|
|
writeln('Compiling ', fName^);
|
|
useGlobalPool := false; {start a local label pool}
|
|
if not codegenStarted and (liDCBGS.kFlag <> 0) then begin {init the code generator (if it needs it)}
|
|
CodeGenInit (outFileGS, liDCBGS.kFlag, doingPartial);
|
|
liDCBGS.kFlag := 3;
|
|
codegenStarted := true;
|
|
end; {if}
|
|
foundFunction := true; {got one...}
|
|
segType := ord(variable^.class = staticsy) * $4000;
|
|
if (variable^.storage = external) and variable^.inlineDefinition then begin
|
|
new(fname);
|
|
fname^ := concat('~inline~', variable^.name^);
|
|
segType := $4000;
|
|
end {if}
|
|
else if fnType^.isPascal then begin
|
|
fName := pointer(Malloc(length(variable^.name^)+1));
|
|
CopyString(pointer(fName), pointer(variable^.name));
|
|
for i := 1 to length(fName^) do
|
|
if fName^[i] in ['a'..'z'] then
|
|
fName^[i] := chr(ord(fName^[i]) & $5F);
|
|
end; {if}
|
|
Gen2Name(dc_str, segType, 0, fName);
|
|
doingMain := variable^.name^ = 'main';
|
|
hasVarargsCall := false;
|
|
firstCompoundStatement := true;
|
|
Gen0 (dc_pin);
|
|
if not isAsm then
|
|
Gen1Name(pc_ent, 0, variable^.name);
|
|
functionName := variable^.name;
|
|
nextLocalLabel := 1; {initialize GetLocalLabel}
|
|
returnLabel := GenLabel; {set up an exit point}
|
|
tempList := nil; {initialize the work label list}
|
|
if not isAsm then {generate traceback, profile code}
|
|
if traceBack or profileFlag then begin
|
|
if traceBack then
|
|
nameFound := true;
|
|
debugSourceFileGS := sourceFileGS;
|
|
GenPS(pc_nam, variable^.name);
|
|
end; {if}
|
|
changedSourceFile := false;
|
|
nextPdisp := 0; {assign displacements to the parameters}
|
|
if not fnType^.isPascal then begin
|
|
tlp := lp;
|
|
lp := nil;
|
|
while tlp <> nil do begin
|
|
tlp2 := tlp;
|
|
tlp := tlp^.pnext;
|
|
tlp2^.pnext := lp;
|
|
lp := tlp2;
|
|
end; {while}
|
|
end; {if}
|
|
while lp <> nil do begin
|
|
lp^.pdisp := nextPdisp;
|
|
if lp^.itype^.kind = arrayType then
|
|
nextPdisp := nextPdisp + cgPointerSize
|
|
else begin
|
|
if (lp^.itype^.kind = scalarType) and
|
|
(lp^.itype^.baseType in [cgReal,cgDouble,cgComp]) then begin
|
|
if extendedParameters then
|
|
{all floating-point params are treated as extended}
|
|
lp^.itype :=
|
|
MakeQualifiedType(extendedPtr, lp^.itype^.qualifiers);
|
|
nextPdisp := nextPdisp + cgExtendedSize;
|
|
end {if}
|
|
else begin
|
|
nextPdisp := nextPdisp + long(lp^.itype^.size).lsw;
|
|
if (long(lp^.itype^.size).lsw = 1)
|
|
and (lp^.itype^.kind = scalarType) then
|
|
nextPdisp := nextPdisp+1;
|
|
end; {else}
|
|
end; {else}
|
|
lp := lp^.pnext;
|
|
end; {while}
|
|
gotoList := nil; {initialize the label list}
|
|
fenvAccessInFunction := fenvAccess;
|
|
skipReturn := false;
|
|
returnCount := 0;
|
|
if isAsm then begin
|
|
AsmFunction(variable); {handle assembly language functions}
|
|
PopTable;
|
|
end {if}
|
|
else begin
|
|
{set up struct/union area}
|
|
if variable^.itype^.ftype^.kind in [structType,unionType] then
|
|
structReturnVar := NewSymbol(@'@struct', variable^.itype^.ftype,
|
|
staticsy, variablespace, declared, false);
|
|
{generate parameter labels}
|
|
if fnType^.overrideKR then
|
|
GenParameters(nil)
|
|
else
|
|
GenParameters(fnType^.parameterList);
|
|
savedVolatile := volatile;
|
|
functionTable := table;
|
|
if fnType^.varargs then begin {make internal va info for varargs funcs}
|
|
lp := NewSymbol(@'__orcac_va_info', vaInfoPtr, autosy,
|
|
variableSpace, declared, false);
|
|
lp^.lln := GetLocalLabel;
|
|
lp^.used := true;
|
|
Gen2(dc_loc, lp^.lln, ord(vaInfoPtr^.size));
|
|
Gen2(pc_lda, lastParameterLLN, lastParameterSize);
|
|
Gen2t(pc_cop, lp^.lln, 0, cgULong);
|
|
Gen2t(pc_str, lp^.lln, cgPointerSize, cgULong);
|
|
vaInfoLLN := lp^.lln;
|
|
end {if}
|
|
else
|
|
vaInfoLLN := 0;
|
|
CompoundStatement(false); {process the statements}
|
|
end; {else}
|
|
end; {else}
|
|
2: ;
|
|
end {if}
|
|
|
|
{handle a variable declaration}
|
|
else {if not isFunction then} begin
|
|
if not declarationSpecifierFound then
|
|
if first then
|
|
Error(26);
|
|
if alignmentSpecified then
|
|
if declSpecifiers.storageClass in [typedefsy,registersy] then
|
|
Error(142);
|
|
if isInline then
|
|
Error(119);
|
|
if isNoreturn then
|
|
Error(141);
|
|
if token.kind = eqch then begin
|
|
if declSpecifiers.storageClass = typedefsy then
|
|
Error(52)
|
|
else if declSpecifiers.storageClass = externsy then
|
|
if doingFunction then
|
|
Error(22);
|
|
if doingPrototypes or doingParameters then
|
|
Error(88);
|
|
{allocate copy of incomplete array type,}
|
|
tp := variable^.itype; {so it can be completed by Initializer}
|
|
if (tp^.kind = arrayType) and (tp^.elements = 0) then begin
|
|
variable^.itype := pointer(Malloc(sizeof(typeRecord)));
|
|
variable^.itype^ := tp^;
|
|
variable^.itype^.saveDisp := 0;
|
|
end;
|
|
TermHeader; {make sure the header file is closed}
|
|
NextToken; {handle an initializer}
|
|
Initializer(variable);
|
|
end; {if}
|
|
{check to insure array sizes are specified}
|
|
if declSpecifiers.storageClass <> typedefsy then
|
|
CheckArray(variable,
|
|
(declSpecifiers.storageClass = externsy)
|
|
or doingParameters or not doingFunction);
|
|
{allocate space}
|
|
if variable^.storage = stackFrame then begin
|
|
variable^.lln := GetLocalLabel;
|
|
Gen2(dc_loc, variable^.lln, long(variable^.itype^.size).lsw);
|
|
if variable^.state = initialized then
|
|
AutoInit(variable, startLine, false); {initialize auto variable}
|
|
end; {if}
|
|
if (token.kind = commach) and (not doingPrototypes) then begin
|
|
NextToken; {allow multiple variables on one line}
|
|
first := false;
|
|
goto 3;
|
|
end; {if}
|
|
if doingPrototypes then begin
|
|
protoVariable := variable; {make the var available to Declarator}
|
|
if protoVariable = nil then
|
|
protoType := declSpecifiers.typeSpec
|
|
else
|
|
protoType := protoVariable^.iType;
|
|
end {if}
|
|
else begin
|
|
inhibitHeader := lInhibitHeader;
|
|
if token.kind = semicolonch then {must end with a semicolon}
|
|
NextToken
|
|
else begin
|
|
Error(22);
|
|
SkipStatement;
|
|
end; {else}
|
|
end; {else}
|
|
end; {else}
|
|
1:
|
|
doingParameters := lDoingParameters; {restore the status}
|
|
useGlobalPool := lUseGlobalPool;
|
|
4:
|
|
inhibitHeader := lInhibitHeader;
|
|
end; {DoDeclaration}
|
|
|
|
|
|
function TypeName{: typePtr};
|
|
|
|
{ process a type name (used for casts and sizeof/_Alignof) }
|
|
{ }
|
|
{ returns: a pointer to the type }
|
|
|
|
var
|
|
tl,tp: typePtr; {for creating/reversing the type list}
|
|
declSpecifiers: declSpecifiersRecord; {type & specifiers for the type name}
|
|
|
|
|
|
procedure AbstractDeclarator;
|
|
|
|
{ process an abstract declarator }
|
|
{ }
|
|
{ abstract-declarator: }
|
|
{ empty-abstract-declarator }
|
|
{ nonempty-abstract-declarator }
|
|
|
|
|
|
procedure NonEmptyAbstractDeclarator;
|
|
|
|
{ process a nonempty abstract declarator }
|
|
{ }
|
|
{ nonempty-abstract-declarator: }
|
|
{ ( nonempty-abstract-declarator ) }
|
|
{ abstract-declarator ( ) }
|
|
{ abstract-declarator [ expression OPT ] }
|
|
{ * abstract-declarator }
|
|
|
|
var
|
|
pcount: integer; {paren counter}
|
|
tp: typePtr; {work pointer}
|
|
|
|
begin {NonEmptyAbstractDeclarator}
|
|
if token.kind = lparench then begin
|
|
NextToken;
|
|
if token.kind = rparench then begin
|
|
|
|
{create a function type}
|
|
tp := pointer(Calloc(sizeof(typeRecord)));
|
|
{tp^.size := 0;}
|
|
{tp^.saveDisp := 0;}
|
|
{tp^.qualifiers := [];}
|
|
tp^.kind := functionType;
|
|
{tp^.varargs := false;}
|
|
{tp^.prototyped := false;}
|
|
{tp^.overrideKR := false;}
|
|
{tp^.parameterList := nil;}
|
|
{tp^.isPascal := false;}
|
|
{tp^.toolNum := 0;}
|
|
{tp^.dispatcher := 0;}
|
|
tp^.fType := Unqualify(tl);
|
|
tl := tp;
|
|
NextToken;
|
|
end {if}
|
|
else begin
|
|
|
|
{handle a parenthesized type}
|
|
if not (token.kind in [lparench,asteriskch,lbrackch]) then
|
|
begin
|
|
Error(82);
|
|
while not (token.kind in
|
|
[eofsy,lparench,asteriskch,lbrackch,rparench]) do
|
|
NextToken;
|
|
end; {if}
|
|
if token.kind in [lparench,asteriskch,lbrackch] then
|
|
NonEmptyAbstractDeclarator;
|
|
Match(rparench,12);
|
|
end; {else}
|
|
end {if token.kind = lparench}
|
|
else if token.kind = asteriskch then begin
|
|
|
|
{create a pointer type}
|
|
NextToken;
|
|
tp := pointer(Malloc(sizeof(typeRecord)));
|
|
tp^.size := cgPointerSize;
|
|
tp^.saveDisp := 0;
|
|
tp^.qualifiers := [];
|
|
tp^.kind := pointerType;
|
|
while token.kind in [constsy,volatilesy,restrictsy] do begin
|
|
if token.kind = constsy then
|
|
tp^.qualifiers := tp^.qualifiers + [tqConst]
|
|
else if token.kind = volatilesy then begin
|
|
tp^.qualifiers := tp^.qualifiers + [tqVolatile];
|
|
volatile := true;
|
|
end {else}
|
|
else {if token.kind = restrictsy then}
|
|
tp^.qualifiers := tp^.qualifiers + [tqRestrict];
|
|
NextToken;
|
|
end; {while}
|
|
AbstractDeclarator;
|
|
tp^.fType := tl;
|
|
tl := tp;
|
|
end {else if token.kind = asteriskch}
|
|
else {if token.kind = lbrackch then} begin
|
|
|
|
{create an array type}
|
|
NextToken;
|
|
if token.kind = rbrackch then
|
|
expressionValue := 0
|
|
else begin
|
|
Expression(arrayExpression, [rbrackch]);
|
|
if expressionValue <= 0 then begin
|
|
Error(45);
|
|
expressionValue := 1;
|
|
end; {if}
|
|
end; {else}
|
|
tp := pointer(Malloc(sizeof(typeRecord)));
|
|
tp^.saveDisp := 0;
|
|
tp^.kind := arrayType;
|
|
tp^.elements := expressionValue;
|
|
tp^.fType := tl;
|
|
tl := tp;
|
|
Match(rbrackch,24);
|
|
end; {else}
|
|
|
|
if token.kind = lparench then begin
|
|
{create a function type}
|
|
NextToken;
|
|
pcount := 1;
|
|
while (token.kind <> eofsy) and (pcount <> 0) do begin
|
|
if token.kind = rparench then
|
|
pcount := pcount-1
|
|
else if token.kind = lparench then
|
|
pcount := pcount+1;
|
|
NextToken;
|
|
end; {while}
|
|
tp := pointer(Calloc(sizeof(typeRecord)));
|
|
{tp^.size := 0;}
|
|
{tp.saveDisp := 0;}
|
|
{tp^.qualifiers := [];}
|
|
tp^.kind := functionType;
|
|
{tp^.varargs := false;}
|
|
{tp^.prototyped := false;}
|
|
{tp^.overrideKR := false;}
|
|
{tp^.parameterList := nil;}
|
|
{tp^.isPascal := false;}
|
|
{tp^.toolNum := 0;}
|
|
{tp^.dispatcher := 0;}
|
|
tp^.fType := Unqualify(tl);
|
|
tl := tp;
|
|
end; {if}
|
|
end; {NonEmptyAbstractDeclarator}
|
|
|
|
|
|
begin {AbstractDeclarator}
|
|
while token.kind in [lparench,asteriskch,lbrackch] do
|
|
NonEmptyAbstractDeclarator;
|
|
end; {AbstractDeclarator}
|
|
|
|
|
|
begin {TypeName}
|
|
{read and process the type specifier}
|
|
DeclarationSpecifiers(declSpecifiers, specifierQualifierListElement, 12);
|
|
|
|
{_Alignas is not allowed in most uses of type names. }
|
|
{TODO: _Alignas should be allowed in compound literals. }
|
|
if _Alignassy in declSpecifiers.declarationModifiers then
|
|
Error(142);
|
|
|
|
{handle the abstract-declarator part}
|
|
tl := nil; {no types so far}
|
|
AbstractDeclarator; {create the type list}
|
|
while tl <> nil do begin {reverse the list & compute array sizes}
|
|
tp := tl^.aType; {NOTE: assumes aType, pType and fType overlap in typeRecord}
|
|
tl^.aType := declSpecifiers.typeSpec;
|
|
if tl^.kind = arrayType then
|
|
tl^.size := tl^.elements * declSpecifiers.typeSpec^.size;
|
|
declSpecifiers.typeSpec := tl;
|
|
tl := tp;
|
|
end; {while}
|
|
if pascalsy in declSpecifiers.declarationModifiers then
|
|
declSpecifiers.typeSpec := MakePascalType(declSpecifiers.typeSpec);
|
|
TypeName := declSpecifiers.typeSpec;
|
|
end; {TypeName}
|
|
|
|
|
|
procedure DoStatement;
|
|
|
|
{ process a statement from a function }
|
|
|
|
var
|
|
lToken: tokenType; {temporary copy of old token}
|
|
nToken: tokenType; {new token}
|
|
hasStatementNext: boolean; {is a stmt next within a compound stmt?}
|
|
lSuppressMacroExpansions: boolean; {local copy of suppressMacroExpansions}
|
|
|
|
begin {DoStatement}
|
|
case statementList^.kind of
|
|
|
|
compoundSt: begin
|
|
hasStatementNext := true;
|
|
if token.kind = rbracech then begin
|
|
hasStatementNext := false;
|
|
EndCompoundStatement;
|
|
end {if}
|
|
else if (statementList^.doingDeclaration or allowMixedDeclarations)
|
|
and (token.kind in localDeclarationStart)
|
|
then begin
|
|
hasStatementNext := false;
|
|
if token.kind <> typedef then
|
|
DoDeclaration(false)
|
|
else begin
|
|
lToken := token;
|
|
lSuppressMacroExpansions := suppressMacroExpansions;
|
|
suppressMacroExpansions := true; {inhibit token echo}
|
|
NextToken;
|
|
suppressMacroExpansions := lSuppressMacroExpansions;
|
|
nToken := token;
|
|
PutBackToken(nToken, false, false);
|
|
token := lToken;
|
|
if nToken.kind <> colonch then
|
|
DoDeclaration(false)
|
|
else
|
|
hasStatementNext := true;
|
|
end {else}
|
|
end; {else if}
|
|
|
|
if hasStatementNext then begin
|
|
if statementList^.doingDeclaration then begin
|
|
statementList^.doingDeclaration := false;
|
|
if firstCompoundStatement then begin
|
|
Gen1Name(dc_sym, ord(doingMain), pointer(table));
|
|
firstCompoundStatement := false;
|
|
end; {if}
|
|
end; {if}
|
|
Statement;
|
|
end; {else}
|
|
end;
|
|
|
|
ifSt:
|
|
EndIfStatement;
|
|
|
|
elseSt:
|
|
EndElseStatement;
|
|
|
|
doSt:
|
|
EndDoStatement;
|
|
|
|
whileSt:
|
|
EndWhileStatement;
|
|
|
|
forSt:
|
|
EndForStatement;
|
|
|
|
switchSt:
|
|
EndSwitchStatement;
|
|
|
|
otherwise: Error(57);
|
|
end; {case}
|
|
end; {DoStatement}
|
|
|
|
|
|
procedure AutoInit {variable: identPtr; line: longint;
|
|
isCompoundLiteral: boolean};
|
|
|
|
{ generate code to initialize an auto variable }
|
|
{ }
|
|
{ parameters: }
|
|
{ variable - the variable to initialize }
|
|
{ line - line number (used for debugging) }
|
|
{ isCompoundLiteral - initializing a compound literal? }
|
|
|
|
var
|
|
iPtr: initializerPtr; {pointer to the next initializer}
|
|
codeCount: longint; {number of initializer expressions}
|
|
treeCount: integer; {current number of distinct trees}
|
|
ldoDispose: boolean; {local copy of doDispose}
|
|
|
|
|
|
procedure InitializeOneElement;
|
|
|
|
{ initialize (part of) a variable using the initializer iPtr }
|
|
{ }
|
|
{ variables: }
|
|
{ variable - the variable to initialize }
|
|
{ count - number of times to re-use the initializer }
|
|
{ iPtr - pointer to the initializer record to use }
|
|
|
|
label 1,2,3,4;
|
|
|
|
var
|
|
count: integer; {initializer counter}
|
|
disp: longint; {displacement to initialize at}
|
|
elements: longint; {# array elements}
|
|
itype: typePtr; {the type being initialized}
|
|
size: integer; {fill size}
|
|
|
|
{assignment conversion}
|
|
{---------------------}
|
|
tree: tokenPtr; {expression tree}
|
|
val: longint; {constant expression value}
|
|
isConstant: boolean; {is the expression a constant?}
|
|
|
|
|
|
procedure LoadAddress;
|
|
|
|
{ Load the address of the operand }
|
|
|
|
begin {LoadAddress}
|
|
if variable^.storage = stackFrame then
|
|
Gen2(pc_lda, variable^.lln, ord(disp))
|
|
else
|
|
Error(57);
|
|
end; {LoadAddress}
|
|
|
|
|
|
procedure AddOperation;
|
|
|
|
{ Deal with a new initializer expression in a compound }
|
|
{ literal, adding expression tree nodes as appropriate. }
|
|
{ This aims to produce a balanced binary tree. }
|
|
|
|
var
|
|
val: longint;
|
|
|
|
begin {AddOperation}
|
|
treeCount := treeCount + 1;
|
|
codeCount := codeCount + 1;
|
|
val := codeCount;
|
|
while (val & 1) = 0 do begin
|
|
Gen0t(pc_bno, cgVoid);
|
|
treeCount := treeCount - 1;
|
|
val := val >> 1;
|
|
end; {end}
|
|
end; {AddOperation}
|
|
|
|
|
|
begin {InitializeOneElement}
|
|
disp := iPtr^.disp;
|
|
count := iPtr^.count;
|
|
3: itype := iPtr^.iType;
|
|
while itype^.kind = definedType do
|
|
itype := itype^.dType;
|
|
case itype^.kind of
|
|
|
|
scalarType,pointerType,enumType,functionType: begin
|
|
tree := iptr^.itree;
|
|
if tree = nil then goto 2; {don't generate code in error case}
|
|
LoadAddress; {load the destination address}
|
|
{generate the expression value}
|
|
doDispose := ldoDispose and (count = 1);
|
|
{see if this is a constant}
|
|
{do assignment conversions}
|
|
while tree^.token.kind = castoper do
|
|
tree := tree^.left;
|
|
isConstant :=
|
|
tree^.token.class in [intConstant,longConstant,longlongConstant];
|
|
if isConstant then
|
|
if tree^.token.class = intConstant then
|
|
val := tree^.token.ival
|
|
else if tree^.token.class = longConstant then
|
|
val := tree^.token.lval
|
|
else {if tree^.token.class = longlongConstant then} begin
|
|
if (tree^.token.qval.hi = 0) and (tree^.token.qval.lo >= 0) then
|
|
val := tree^.token.qval.lo
|
|
else
|
|
isConstant := false;
|
|
end; {else}
|
|
|
|
if isConstant then
|
|
if val = 0 then
|
|
if count > 1 then
|
|
if itype^.size = 1 then begin
|
|
{call ~ZERO for > 50 zero bytes}
|
|
if count > 50 then begin
|
|
Gen0t(pc_stk, cgULong);
|
|
Gen1t(pc_ldc, count, cgWord);
|
|
Gen0t(pc_stk, cgWord);
|
|
Gen0t(pc_bno, cgWord);
|
|
Gen1tName(pc_cup, -1, cgVoid, @'~ZERO');
|
|
if isCompoundLiteral then
|
|
AddOperation;
|
|
goto 4;
|
|
end {if}
|
|
else begin {zero-initialize two bytes at a time}
|
|
itype := shortPtr;
|
|
count := count - 1;
|
|
end; {else}
|
|
end; {if}
|
|
|
|
{ if isConstant then
|
|
if tree^.token.class = intConstant then
|
|
Writeln('loc 2: bitsize = ', iPtr^.bitsize:1, '; ival = ', tree^.token.ival:1) {debug}
|
|
{ else
|
|
Writeln('loc 2: bitsize = ', iPtr^.bitsize:1, '; lval = ', tree^.token.lval:1) {debug}
|
|
{ else
|
|
Writeln('loc 2: bitsize = ', iPtr^.bitsize:1); {debug}
|
|
|
|
GenerateCode(iptr^.iTree);
|
|
AssignmentConversion(itype, expressionType, isConstant, val, true,
|
|
false);
|
|
case itype^.kind of {save the value}
|
|
scalarType:
|
|
if iptr^.bitsize <> 0 then
|
|
Gen2t(pc_sbf, iptr^.bitdisp, iptr^.bitsize, itype^.basetype)
|
|
else
|
|
Gen0t(pc_sto, itype^.baseType);
|
|
enumType:
|
|
Gen0t(pc_sto, cgWord);
|
|
pointerType,functionType:
|
|
Gen0t(pc_sto, cgULong);
|
|
end; {case}
|
|
if isCompoundLiteral then
|
|
AddOperation;
|
|
2: end;
|
|
|
|
arrayType: begin
|
|
elements := itype^.elements;
|
|
if elements = 0 then goto 1; {don't init flexible array member}
|
|
if itype^.aType^.kind = scalarType then
|
|
if iPtr^.iTree^.token.kind = stringConst then begin
|
|
elements := elements * itype^.aType^.size;
|
|
size := iPtr^.iTree^.token.sval^.length;
|
|
if size >= elements then
|
|
size := ord(elements)
|
|
else
|
|
size := size-1;
|
|
if size <> 0 then begin
|
|
LoadAddress;
|
|
GenS(pc_lca, iPtr^.iTree^.token.sval);
|
|
Gen2(pc_mov, 0, size);
|
|
Gen0t(pc_pop, cgULong);
|
|
if isCompoundLiteral then
|
|
AddOperation;
|
|
end; {if}
|
|
if size < elements then begin
|
|
elements := elements - size;
|
|
disp := disp + size;
|
|
LoadAddress;
|
|
Gen0t(pc_stk, cgULong);
|
|
Gen1t(pc_ldc, ord(elements), cgWord);
|
|
Gen0t(pc_stk, cgWord);
|
|
Gen0t(pc_bno, cgWord);
|
|
Gen1tName(pc_cup, -1, cgVoid, @'~ZERO');
|
|
if isCompoundLiteral then
|
|
AddOperation;
|
|
end; {if}
|
|
end; {if}
|
|
1: end;
|
|
|
|
structType,unionType: begin
|
|
LoadAddress; {load the destination address}
|
|
GenerateCode(iptr^.iTree); {load the struct address}
|
|
{do the assignment}
|
|
AssignmentConversion(itype, expressionType, isConstant, val,
|
|
true, false);
|
|
with expressionType^ do
|
|
Gen2(pc_mov, long(size).msw, long(size).lsw);
|
|
Gen0t(pc_pop, UsualUnaryConversions);
|
|
if isCompoundLiteral then
|
|
AddOperation;
|
|
end; {if}
|
|
|
|
otherwise: Error(57);
|
|
end; {case}
|
|
if count <> 1 then begin
|
|
count := count - 1;
|
|
disp := disp + itype^.size;
|
|
goto 3;
|
|
end; {if}
|
|
4:
|
|
end; {InitializeOneElement}
|
|
|
|
|
|
begin {AutoInit}
|
|
iPtr := variable^.iPtr;
|
|
if isCompoundLiteral then begin
|
|
treeCount := 0;
|
|
codeCount := 0;
|
|
ldoDispose := doDispose;
|
|
end {if}
|
|
else
|
|
ldoDispose := true;
|
|
if variable^.class <> staticsy then begin
|
|
if traceBack or debugFlag then
|
|
if nameFound or debugFlag then
|
|
if (statementList <> nil) and not statementList^.doingDeclaration then
|
|
if lineNumber <> 0 then
|
|
RecordLineNumber(line);
|
|
while iPtr <> nil do begin
|
|
InitializeOneElement;
|
|
iPtr := iPtr^.next;
|
|
end; {while}
|
|
end; {if}
|
|
if isCompoundLiteral then begin
|
|
while treeCount > 1 do begin
|
|
Gen0t(pc_bno, cgVoid);
|
|
treeCount := treeCount - 1;
|
|
end; {while}
|
|
doDispose := lDoDispose;
|
|
end; {if}
|
|
end; {AutoInit}
|
|
|
|
|
|
function MakeFuncIdentifier{: identPtr};
|
|
|
|
{ Make the predefined identifier __func__. }
|
|
{ }
|
|
{ It is inserted in the symbol table as if the following }
|
|
{ declaration appeared at the beginning of the function body: }
|
|
{ }
|
|
{ static const char __func__[] = "function-name"; }
|
|
{ }
|
|
{ This must only be called within a function body. }
|
|
|
|
var
|
|
lTable: symbolTablePtr; {saved copy of current symbol table}
|
|
tp: typePtr; {the type of __func__}
|
|
id: identPtr; {the identifier for __func__}
|
|
sval: longstringPtr; {the initializer string}
|
|
iPtr: initializerPtr; {the initializer}
|
|
i: integer; {loop variable}
|
|
len: integer; {string length}
|
|
|
|
begin {MakeFuncIdentifier}
|
|
lTable := table;
|
|
table := functionTable;
|
|
|
|
len := ord(functionName^[0]) + 1;
|
|
tp := pointer(GCalloc(sizeof(typeRecord)));
|
|
tp^.size := len;
|
|
{tp^.saveDisp := 0;}
|
|
{tp^.qualifiers := [];}
|
|
tp^.kind := arrayType;
|
|
tp^.aType := constCharPtr;
|
|
tp^.elements := len;
|
|
id := NewSymbol(@'__func__', tp, staticsy, variableSpace, initialized, false);
|
|
|
|
sval := pointer(GCalloc(len + sizeof(integer)));
|
|
sval^.length := len;
|
|
for i := 1 to len-1 do
|
|
sval^.str[i] := functionName^[i];
|
|
{sval^.str[len] := chr(0);}
|
|
iPtr := pointer(GCalloc(sizeof(initializerRecord)));
|
|
{iPtr^.next := nil;}
|
|
iPtr^.count := 1;
|
|
{iPtr^.bitdisp := 0;}
|
|
{iPtr^.bitsize := 0;}
|
|
iPtr^.isConstant := true;
|
|
iPtr^.basetype := cgString;
|
|
iPtr^.sval := sval;
|
|
id^.iPtr := iPtr;
|
|
|
|
table := lTable;
|
|
MakeFuncIdentifier := id;
|
|
end; {MakeFuncIdentifier}
|
|
|
|
|
|
function MakeCompoundLiteral{tp: typePtr): identPtr};
|
|
|
|
{ Make the identifier for a compound literal. }
|
|
{ }
|
|
{ parameters: }
|
|
{ tp - the type of the compound literal }
|
|
|
|
type
|
|
nameString = packed array [0..24] of char;
|
|
|
|
var
|
|
id: identPtr; {the identifier for the literal}
|
|
name: ^nameString; {the name for the identifier}
|
|
class: tokenEnum; {storage class}
|
|
|
|
begin {MakeCompoundLiteral}
|
|
if functionTable <> nil then
|
|
class := autosy
|
|
else
|
|
class := staticsy;
|
|
name := pointer(Malloc(25));
|
|
name^ := concat('~CompoundLiteral', cnvis(compoundLiteralNumber));
|
|
id := NewSymbol(name, tp, class, variableSpace, defined, false);
|
|
compoundLiteralNumber := compoundLiteralNumber + 1;
|
|
if compoundLiteralNumber = 0 then
|
|
Error(57);
|
|
Initializer(id);
|
|
MakeCompoundLiteral := id;
|
|
if class = autosy then begin
|
|
id^.lln := GetLocalLabel;
|
|
id^.clnext := compoundLiteralToAllocate;
|
|
compoundLiteralToAllocate := id;
|
|
end;
|
|
end; {MakeCompoundLiteral}
|
|
|
|
|
|
procedure InitParser;
|
|
|
|
{ Initialize the parser }
|
|
|
|
var
|
|
typeSpecifierStart: tokenSet;
|
|
storageClassSpecifiers: tokenSet;
|
|
typeQualifiers: tokenSet;
|
|
functionSpecifiers: tokenSet;
|
|
alignmentSpecifiers: tokenSet;
|
|
|
|
begin {InitParser}
|
|
doingFunction := false; {not doing a function (yet)}
|
|
doingParameters := false; {not processing parameters}
|
|
lastLine := 0; {no pc_lnm generated yet}
|
|
nameFound := false; {no pc_nam generated yet}
|
|
statementList := nil; {no open statements}
|
|
codegenStarted := false; {code generator is not started}
|
|
doingForLoopClause1 := false; {not doing a for loop}
|
|
fIsNoreturn := false; {not doing a noreturn function}
|
|
compoundLiteralNumber := 1; {no compound literals yet}
|
|
compoundLiteralToAllocate := nil; {no compound literals needing space yet}
|
|
anonNumber := 0; {no anonymous structs/unions yet}
|
|
|
|
{init syntactic classes of tokens}
|
|
{See C17 section 6.7 ff.}
|
|
typeSpecifierStart :=
|
|
[voidsy,charsy,shortsy,intsy,longsy,floatsy,doublesy,signedsy,unsignedsy,
|
|
extendedsy,compsy,_Boolsy,_Complexsy,_Imaginarysy,_Atomicsy,
|
|
structsy,unionsy,enumsy,typedef];
|
|
|
|
storageClassSpecifiers :=
|
|
[typedefsy,externsy,staticsy,_Thread_localsy,autosy,registersy];
|
|
|
|
typeQualifiers :=
|
|
[constsy,volatilesy,restrictsy,_Atomicsy];
|
|
|
|
functionSpecifiers := [inlinesy,_Noreturnsy,pascalsy,asmsy];
|
|
|
|
alignmentSpecifiers := [_Alignassy];
|
|
|
|
declarationSpecifiersElement := typeSpecifierStart + storageClassSpecifiers
|
|
+ typeQualifiers + functionSpecifiers + alignmentSpecifiers;
|
|
|
|
specifierQualifierListElement :=
|
|
typeSpecifierStart + typeQualifiers + alignmentSpecifiers + [pascalsy];
|
|
|
|
structDeclarationStart := specifierQualifierListElement + [_Static_assertsy];
|
|
|
|
topLevelDeclarationStart :=
|
|
declarationSpecifiersElement + [ident,segmentsy,_Static_assertsy];
|
|
|
|
localDeclarationStart :=
|
|
declarationSpecifiersElement + [_Static_assertsy] - [asmsy];
|
|
end; {InitParser}
|
|
|
|
|
|
procedure TermParser;
|
|
|
|
{ shut down the parser }
|
|
|
|
begin {TermParser}
|
|
if statementList <> nil then
|
|
case statementList^.kind of
|
|
compoundSt : Error(34);
|
|
doSt : Error(33);
|
|
elseSt : Error(67);
|
|
forSt : Error(69);
|
|
ifSt : Error(32);
|
|
switchSt : Error(70);
|
|
whileSt : Error(68);
|
|
otherwise: Error(57);
|
|
end; {case}
|
|
end; {TermParser}
|
|
|
|
end.
|