Eliminate global variables for declaration specifiers.

They are now represented in local structures instead. This keeps the representation of declaration specifiers together and eliminates the need for awkward and error-prone code to save and restore the global variables.
This commit is contained in:
Stephen Heumann 2022-10-01 21:28:16 -05:00
parent 05ecf5eef3
commit 1fa3ec8fdd
3 changed files with 81 additions and 99 deletions

View File

@ -515,10 +515,6 @@ var
isConstant: boolean; {is the initializer expression constant?}
expressionIsLongLong: boolean; {is the last constant expression long long?}
{type specifier results}
{----------------------}
typeSpec: typePtr; {type specifier}
{flags}
{-----}
codegenStarted: boolean; {have we started the code generator?}

View File

@ -250,12 +250,11 @@ procedure Match (kind: tokenEnum; err: integer); extern;
{ err - error number if the expected token is not found }
procedure TypeName; extern;
function TypeName: typePtr; extern;
{ process a type name (used for casts and sizeof/_Alignof) }
{ }
{ outputs: }
{ typeSpec - pointer to the type }
{ returns: a pointer to the type }
function MakeFuncIdentifier: identPtr; extern;
@ -756,6 +755,7 @@ var
opStack: tokenPtr; {operation stack}
parenCount: integer; {# of open parenthesis}
stack: tokenPtr; {operand stack}
tType: typePtr; {type for cast/sizeof/etc.}
op,sp: tokenPtr; {work pointers}
@ -2002,8 +2002,7 @@ var
while not (token.kind in [colonch,commach,rparench,eofsy]) do
NextToken;
end; {if}
TypeName; {get the type name}
currentType := typeSpec;
currentType := TypeName; {get the type name}
if (currentType^.size = 0) or (currentType^.kind = functionType) then
Error(133);
tl := typesSeen; {check if it is a duplicate}
@ -2214,7 +2213,7 @@ if token.kind in startExpression then begin
doingSizeof := true
else if opStack^.token.kind = _Alignofsy then
doingAlignof := true;
TypeName;
tType := TypeName;
if doingSizeof or doingAlignof then begin
{handle a sizeof operator}
@ -2229,10 +2228,10 @@ if token.kind in startExpression then begin
sp^.token.kind := ulongconst;
sp^.token.class := longConstant;
if doingSizeof then
sp^.token.lval := typeSpec^.size
sp^.token.lval := tType^.size
else {if doingAlignof then}
sp^.token.lval := 1;
with typeSpec^ do
with tType^ do
if (size = 0) or ((kind = arrayType) and (elements = 0)) then
Error(133);
sp^.next := stack;
@ -2246,7 +2245,7 @@ if token.kind in startExpression then begin
op^.left := nil;
op^.middle := nil;
op^.right := nil;
op^.castType := typeSpec;
op^.castType := tType;
op^.token.kind := castoper;
op^.token.class := reservedWord;
op^.next := opStack;

View File

@ -40,12 +40,11 @@ procedure DoStatement;
{ process a statement from a function }
procedure TypeName;
function TypeName: typePtr;
{ process a type name (used for casts and sizeof/_Alignof) }
{ }
{ outputs: }
{ typeSpec - pointer to the type }
{ returns: a pointer to the type }
procedure AutoInit (variable: identPtr; line: integer;
@ -172,6 +171,16 @@ type
);
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
firstCompoundStatement: boolean; {are we doing a function level compound statement?}
fType: typePtr; {return type of the current function}
@ -198,14 +207,6 @@ var
protoType: typePtr; {type from a parameter list}
protoVariable: identPtr; {variable from a parameter list}
{type info for the current declaration}
{-------------------------------------}
storageClass: tokenEnum; {storage class of the declaration}
{ typeSpec: typePtr; (in CCommon) {type specifier}
declarationModifiers: tokenSet; {all storage class specifiers, type }
{qualifiers, function specifiers, & }
{alignment specifiers in declaration}
{syntactic classes of tokens}
{---------------------------}
{ specifierQualifierListElement: tokenSet; (in CCommon)}
@ -1256,13 +1257,13 @@ end; {EndWhileStatement}
{-- Type declarations ------------------------------------------}
procedure Declarator(tPtr: typePtr; var variable: identPtr; space: spaceType;
doingPrototypes: boolean);
procedure Declarator(declSpecifiers: declSpecifiersRecord;
var variable: identPtr; space: spaceType; doingPrototypes: boolean);
{ handle a declarator }
{ }
{ parameters: }
{ tPtr - pointer to the type to use }
{ declSpecifiers - type/specifiers to use }
{ variable - pointer to variable being defined }
{ space - variable space to use }
{ doingPrototypes - are we compiling prototype parameter }
@ -1289,6 +1290,7 @@ var
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}
@ -1328,8 +1330,6 @@ var
lisFunction: boolean; {local copy of isFunction}
lisPascal: boolean; {local copy of isPascal}
lLastParameter: identPtr; {next parameter to process}
lstorageClass: tokenEnum; {storage class of the declaration}
ltypeSpec: typePtr; {type specifier}
luseGlobalPool: boolean; {local copy of useGlobalPool}
lSuppressMacroExpansions: boolean;{local copy of suppressMacroExpansions}
@ -1347,12 +1347,12 @@ var
variable := FindSymbol(token, space, true, true);
newName := token.name;
if variable = nil then begin
if storageClass = typedefsy then begin
if declSpecifiers.storageClass = typedefsy then begin
tPtr2 := pointer(Calloc(sizeof(typeRecord)));
{tPtr2^.size := 0;}
{tPtr2^.saveDisp := 0;}
tPtr2^.kind := definedType;
{tPtr^.qualifiers := [];}
{tPtr2^.qualifiers := [];}
tPtr2^.dType := tPtr;
end {if}
else
@ -1483,8 +1483,6 @@ var
useGlobalPool := true;
done2 := false;
lisFunction := isFunction; {preserve global variables}
ltypeSpec := typeSpec;
lstorageClass := storageClass;
with tPtr2^ do begin
prototyped := true; {it is prototyped}
repeat {collect the declarations}
@ -1533,8 +1531,6 @@ var
until done2;
end; {with}
isFunction := lisFunction; {restore global variables}
storageClass := lstorageClass;
typeSpec := ltypeSpec;
useGlobalPool := luseGlobalPool;
end {if prototype}
else if token.kind = ident then begin
@ -1651,9 +1647,10 @@ var
end; {StackDeclarations}
begin {Declarator}
tPtr := declSpecifiers.typeSpec;
newName := nil; {no identifier, yet}
unnamedParm := false; {not an unnamed parameter}
if storageClass = externsy then {decide on a storage state}
if declSpecifiers.storageClass = externsy then {decide on a storage state}
state := declared
else
state := defined;
@ -1820,7 +1817,7 @@ if tPtr^.kind = functionType then begin {declare the identifier}
if tPtr^.kind = functionType then
state := declared;
if newName <> nil then {declare the variable}
variable := NewSymbol(newName, tPtr, storageClass, space, state)
variable := NewSymbol(newName, tPtr, declSpecifiers.storageClass, space, state)
else if unnamedParm then
variable^.itype := tPtr
else begin
@ -1842,7 +1839,8 @@ if variable <> nil then begin
lastWasPointer := false;
tPtr := tPtr^.pType;
end; {while}
if ((tPtr <> typeSpec) and (not (tPtr^.kind in [structType,unionType])))
if ((tPtr <> declSpecifiers.typeSpec)
and (not (tPtr^.kind in [structType,unionType])))
then begin
Error(107);
SkipStatement;
@ -2746,12 +2744,13 @@ Match(semicolonch, 22);
end; {DoStaticAssert}
procedure DeclarationSpecifiers (allowedTokens: tokenSet;
expectedNext: tokenEnum);
procedure DeclarationSpecifiers (var declSpecifiers: declSpecifiersRecord;
allowedTokens: tokenSet; expectedNext: tokenEnum);
{ handle declaration specifiers or a specifier-qualifier list }
{ }
{ parameters: }
{ declSpecifiers - record to hold result type & specifiers}
{ allowedTokens - specifiers/qualifiers that can be used }
{ expectedNext - token usually expected after declaration }
{ specifiers (used for error messages only) }
@ -2761,10 +2760,6 @@ procedure DeclarationSpecifiers (allowedTokens: tokenSet;
{ referencing a forward struct/union? }
{ skipDeclarator - for enum,struct,union with no }
{ declarator }
{ typespec - type specifier }
{ declarationModifiers - all storage class specifiers, }
{ type qualifiers, function specifiers, and }
{ alignment specifiers in this declaration }
label 1,2,3;
@ -2791,6 +2786,7 @@ var
mySkipDeclarator: boolean; {value of skipDeclarator 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?}
@ -2810,18 +2806,15 @@ var
fl,tfl,ufl: identPtr; {field list}
ldoingParameters: boolean; {local copy of doingParameters}
lisForwardDeclared: boolean; {local copy of isForwardDeclared}
lstorageClass: tokenEnum; {storage class of the declaration}
maxDisp: longint; {for determining union sizes}
variable: identPtr; {variable being defined}
didFlexibleArray: boolean; {have we seen a flexible array member?}
alignmentSpecified: boolean; {was alignment explicitly specified?}
fieldDeclSpecifiers: declSpecifiersRecord; {decl specifiers for field}
begin {FieldList}
ldoingParameters := doingParameters; {allow fields in K&R dec. area}
doingParameters := false;
lisForwardDeclared := isForwardDeclared; {stack this value}
lStorageClass := storageClass; {don't allow auto in a struct}
storageClass := ident;
bitDisp := 0; {start allocation from byte 0}
disp := 0;
maxDisp := 0;
@ -2833,15 +2826,14 @@ var
DoStaticAssert;
goto 1;
end; {if}
DeclarationSpecifiers(specifierQualifierListElement, ident);
alignmentSpecified := _Alignassy in declarationModifiers;
DeclarationSpecifiers(fieldDeclSpecifiers, specifierQualifierListElement, ident);
if not skipDeclarator then
repeat {declare the variables...}
if didFlexibleArray then
Error(118);
variable := nil;
if token.kind <> colonch then begin
Declarator(typeSpec, variable, fieldListSpace, false);
Declarator(fieldDeclSpecifiers, variable, fieldListSpace, false);
if variable <> nil then {enter the var in the field list}
begin
tfl := fl; {(check for dups)}
@ -2882,7 +2874,7 @@ var
tPtr := variable^.itype;
end {if}
else
tPtr := typeSpec;
tPtr := fieldDeclSpecifiers.typeSpec;
bitdisp := bitdisp+long(expressionValue).lsw;
if kind = unionType then
if ((bitDisp+7) div 8) > maxDisp then
@ -2893,7 +2885,7 @@ var
or (expressionValue > tPtr^.size*8)
or ((expressionValue > 1) and (tPtr^.cType = ctBool)) then
Error(115);
if alignmentSpecified then
if _Alignassy in fieldDeclSpecifiers.declarationModifiers then
Error(142);
end {if}
else if variable <> nil then begin
@ -2922,7 +2914,7 @@ var
if variable <> nil then {check for a const member}
tPtr := variable^.itype
else
tPtr := typeSpec;
tPtr := fieldDeclSpecifiers.typeSpec;
while tPtr^.kind in [definedType,arrayType] do begin
if tqConst in tPtr^.qualifiers then
tp^.constMember := true;
@ -2974,7 +2966,6 @@ var
end {if}
else
Error(26); {error if no named declarations}
storageClass := lStorageClass; {restore default storage class}
isForwardDeclared := lisForwardDeclared; {restore the forward flag}
doingParameters := ldoingParameters; {restore the parameters flag}
end; {FieldList}
@ -3055,6 +3046,7 @@ myTypeSpec := nil;
myIsForwardDeclared := false; {not doing a forward reference (yet)}
mySkipDeclarator := false; {declarations are required (so far)}
myDeclarationModifiers := [];
myStorageClass := ident;
typeQualifiers := [];
typeSpecifiers := [];
typeDone := false;
@ -3064,13 +3056,13 @@ while token.kind in allowedTokens do begin
{storage class specifiers}
autosy,externsy,registersy,staticsy,typedefsy: begin
myDeclarationModifiers := myDeclarationModifiers + [token.kind];
if storageClass <> ident then begin
if myStorageClass <> ident then begin
if typeDone or (typeSpecifiers <> []) then
UnexpectedTokenError(expectedNext)
else
Error(26);
end; {if}
storageClass := token.kind;
myStorageClass := token.kind;
if not doingFunction then
if token.kind = autosy then
Error(62);
@ -3078,7 +3070,7 @@ while token.kind in allowedTokens do begin
if token.kind <> registersy then
Error(87);
end {if}
else if storageClass in [staticsy,typedefsy] then begin
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
@ -3087,7 +3079,7 @@ while token.kind in allowedTokens do begin
useGlobalPool := true;
end; {else if}
if doingForLoopClause1 then
if not (storageClass in [autosy,registersy]) then
if not (myStorageClass in [autosy,registersy]) then
Error(127);
NextToken;
end;
@ -3137,8 +3129,7 @@ while token.kind in allowedTokens do begin
if typeDone or (typeSpecifiers <> []) then
UnexpectedTokenError(expectedNext);
NextToken;
TypeName;
myTypeSpec := typeSpec;
myTypeSpec := TypeName;
Match(rparench, 12);
end; {if}
typeDone := true;
@ -3370,8 +3361,8 @@ while token.kind in allowedTokens do begin
NextToken;
Match(lparench, 13);
if token.kind in specifierQualifierListElement then begin
TypeName;
with typeSpec^ do
tPtr := TypeName;
with tPtr^ do
if (size = 0) or ((kind = arrayType) and (elements = 0)) then
Error(133);
end {if}
@ -3392,13 +3383,15 @@ while token.kind in allowedTokens do begin
3:
isForwardDeclared := myIsForwardDeclared;
skipDeclarator := mySkipDeclarator;
declarationModifiers := myDeclarationModifiers;
declSpecifiers.declarationModifiers := myDeclarationModifiers;
if myTypeSpec = nil then begin
myTypeSpec := intPtr; {under C89, default type is int}
if (lint & lintC99Syntax) <> 0 then
Error(151);
end; {if}
typeSpec := MakeQualifiedType(myTypeSpec, typeQualifiers); {apply type qualifiers}
declSpecifiers.typeSpec := {apply type qualifiers}
MakeQualifiedType(myTypeSpec, typeQualifiers);
declSpecifiers.storageClass := myStorageClass;
end; {DeclarationSpecifiers}
@ -3424,7 +3417,6 @@ var
lDoingParameters: boolean; {local copy of doingParameters}
lisPascal: boolean; {local copy of isPascal}
lp,tlp,tlp2: identPtr; {for tracing parameter list}
ltypeSpec: typePtr; {copy of type specifier}
lUseGlobalPool: boolean; {local copy of useGlobalPool}
nextPdisp: integer; {for calculating parameter disps}
noFDefinitions: boolean; {are function definitions inhibited?}
@ -3436,6 +3428,7 @@ var
tk: tokenType; {work token}
typeFound: boolean; {has some type specifier been found?}
startLine: integer; {line where this declaration starts}
declSpecifiers: declSpecifiersRecord; {type & specifiers for the declaration}
procedure CheckArray (v: identPtr; firstVariable: boolean);
@ -3659,19 +3652,18 @@ if not doingFunction then {handle any segment statements}
SegmentStatement;
inhibitHeader := true; {block imbedded includes in headers}
lUseGlobalPool := useGlobalPool;
storageClass := ident;
{handle a TypeSpecifier/declarator}
typeFound := token.kind in declarationSpecifiersElement;
DeclarationSpecifiers(declarationSpecifiersElement, ident);
isPascal := pascalsy in declarationModifiers;
isAsm := asmsy in declarationModifiers;
isInline := inlinesy in declarationModifiers;
isNoreturn := _Noreturnsy in declarationModifiers;
alignmentSpecified := _Alignassy in declarationModifiers;
DeclarationSpecifiers(declSpecifiers, declarationSpecifiersElement, ident);
isPascal := pascalsy in declSpecifiers.declarationModifiers;
isAsm := asmsy in declSpecifiers.declarationModifiers;
isInline := inlinesy in declSpecifiers.declarationModifiers;
isNoreturn := _Noreturnsy in declSpecifiers.declarationModifiers;
alignmentSpecified := _Alignassy in declSpecifiers.declarationModifiers;
lisPascal := isPascal;
if not skipDeclarator then begin
variable := nil;
Declarator(typeSpec, variable, variableSpace, doingPrototypes);
Declarator(declSpecifiers, variable, variableSpace, doingPrototypes);
if variable = nil then begin
inhibitHeader := false;
if token.kind = semicolonch then
@ -3715,7 +3707,7 @@ if isFunction then begin
goto 1;
end; {if}
if isInline then
if storageClass <> staticsy then
if declSpecifiers.storageClass <> staticsy then
Error(120);
if alignmentSpecified then
Error(142);
@ -3777,7 +3769,7 @@ if isFunction then begin
NextToken; {allow further declarations}
variable := nil;
isFunction := false;
Declarator (typeSpec, variable, variableSpace, doingPrototypes);
Declarator(declSpecifiers, variable, variableSpace, doingPrototypes);
if variable = nil then begin
inhibitHeader := false;
if token.kind = semicolonch then
@ -3980,7 +3972,7 @@ if isFunction then begin
else {if not isFunction then} begin
noFDefinitions := true;
if alignmentSpecified then
if storageClass in [typedefsy,registersy] then
if declSpecifiers.storageClass in [typedefsy,registersy] then
Error(142);
if not SkipDeclarator then
repeat
@ -3991,7 +3983,7 @@ else {if not isFunction then} begin
if isNoreturn then
Error(141);
if token.kind = eqch then begin
if storageClass = typedefsy then
if declSpecifiers.storageClass = typedefsy then
Error(52);
if doingPrototypes then
Error(88);
@ -4004,14 +3996,13 @@ else {if not isFunction then} begin
end;
TermHeader; {make sure the header file is closed}
NextToken; {handle an initializer}
ltypeSpec := typeSpec;
Initializer(variable);
typeSpec := ltypeSpec;
end; {if}
{check to insure array sizes are specified}
if storageClass <> typedefsy then
if declSpecifiers.storageClass <> typedefsy then
CheckArray(variable,
(storageClass = externsy) or doingParameters or not doingFunction);
(declSpecifiers.storageClass = externsy)
or doingParameters or not doingFunction);
{allocate space}
if variable^.storage = stackFrame then begin
variable^.lln := GetLocalLabel;
@ -4023,7 +4014,7 @@ else {if not isFunction then} begin
done := false; {allow multiple variables on one line}
NextToken;
variable := nil;
Declarator(typeSpec, variable, variableSpace, doingPrototypes);
Declarator(declSpecifiers, variable, variableSpace, doingPrototypes);
if variable = nil then begin
if token.kind = semicolonch then
NextToken
@ -4041,7 +4032,7 @@ else {if not isFunction then} begin
if doingPrototypes then begin
protoVariable := variable; {make the var available to Declarator}
if protoVariable = nil then
protoType := typeSpec
protoType := declSpecifiers.typeSpec
else
protoType := protoVariable^.iType;
end {if}
@ -4063,16 +4054,15 @@ inhibitHeader := false;
end; {DoDeclaration}
procedure TypeName;
function TypeName{: typePtr};
{ process a type name (used for casts and sizeof/_Alignof) }
{ }
{ outputs: }
{ typeSpec - pointer to the type }
{ returns: a pointer to the type }
var
tl,tp: typePtr; {for creating/reversing the type list}
isPascal: boolean; {is the type "pascal" qualified?}
declSpecifiers: declSpecifiersRecord; {type & specifiers for the type name}
procedure AbstractDeclarator;
@ -4097,7 +4087,6 @@ var
var
pcount: integer; {paren counter}
tp: typePtr; {work pointer}
ltypeSpec: typePtr; {copy of type specifier}
begin {NonEmptyAbstractDeclarator}
if token.kind = lparench then begin
@ -4167,9 +4156,7 @@ var
if token.kind = rbrackch then
expressionValue := 0
else begin
ltypeSpec := typeSpec;
Expression(arrayExpression, [rbrackch]);
typeSpec := ltypeSpec;
if expressionValue <= 0 then begin
Error(45);
expressionValue := 1;
@ -4221,12 +4208,11 @@ var
begin {TypeName}
{read and process the type specifier}
DeclarationSpecifiers(specifierQualifierListElement, rparench);
isPascal := pascalsy in declarationModifiers;
DeclarationSpecifiers(declSpecifiers, specifierQualifierListElement, rparench);
{_Alignas is not allowed in most uses of type names. }
{TODO: _Alignas should be allowed in compound literals. }
if _Alignassy in declarationModifiers then
if _Alignassy in declSpecifiers.declarationModifiers then
Error(142);
{handle the abstract-declarator part}
@ -4234,14 +4220,15 @@ 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 := typeSpec;
tl^.aType := declSpecifiers.typeSpec;
if tl^.kind = arrayType then
tl^.size := tl^.elements * typeSpec^.size;
typeSpec := tl;
tl^.size := tl^.elements * declSpecifiers.typeSpec^.size;
declSpecifiers.typeSpec := tl;
tl := tp;
end; {while}
if isPascal then
typeSpec := MakePascalType(typeSpec);
if pascalsy in declSpecifiers.declarationModifiers then
declSpecifiers.typeSpec := MakePascalType(declSpecifiers.typeSpec);
TypeName := declSpecifiers.typeSpec;
end; {TypeName}