mirror of
https://github.com/byteworksinc/ORCA-C.git
synced 2024-06-03 23:29:28 +00:00
Implement _Generic expressions (from C11).
Note that this code relies on CompTypes for type compatibility testing, and it has slightly non-standard behavior in some cases.
This commit is contained in:
parent
2b7e72ac49
commit
bccd86a627
156
Expression.pas
156
Expression.pas
|
@ -1829,7 +1829,150 @@ var
|
||||||
NextToken;
|
NextToken;
|
||||||
errorFound := true;
|
errorFound := true;
|
||||||
end; {Skip}
|
end; {Skip}
|
||||||
|
|
||||||
|
|
||||||
|
procedure DoGeneric;
|
||||||
|
|
||||||
|
{ process a generic selection expression }
|
||||||
|
|
||||||
|
label 10;
|
||||||
|
|
||||||
|
type
|
||||||
|
typeListPtr = ^typeList;
|
||||||
|
typeList = record
|
||||||
|
next: typeListPtr;
|
||||||
|
theType: typePtr;
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
lCodeGeneration: boolean; {local copy of codeGeneration}
|
||||||
|
tempExpr: tokenPtr; {temporary to hold expression trees}
|
||||||
|
controllingType: typeRecord; {type of controlling expression}
|
||||||
|
typesSeen: typeListPtr; {types that already have associations}
|
||||||
|
tl: typeListPtr; {temporary type list pointer}
|
||||||
|
resultExpr: tokenPtr; {the result expression}
|
||||||
|
defaultExpr: tokenPtr; {the default expression}
|
||||||
|
currentType: typePtr; {the type for the current association}
|
||||||
|
typesMatch: boolean; {does the current type match}
|
||||||
|
foundMatch: boolean; {have we found a matching type?}
|
||||||
|
foundDefault: boolean; {have we found the default case?}
|
||||||
|
|
||||||
|
begin {DoGeneric}
|
||||||
|
if not expectingTerm then begin
|
||||||
|
Error(36);
|
||||||
|
Skip;
|
||||||
|
goto 1;
|
||||||
|
end; {if}
|
||||||
|
NextToken;
|
||||||
|
if token.kind <> lparench then begin
|
||||||
|
Error(36);
|
||||||
|
Skip;
|
||||||
|
goto 1;
|
||||||
|
end; {if}
|
||||||
|
new(op); {record it like a parenthesized expr}
|
||||||
|
op^.next := opStack;
|
||||||
|
op^.left := nil;
|
||||||
|
op^.middle := nil;
|
||||||
|
op^.right := nil;
|
||||||
|
opStack := op;
|
||||||
|
op^.token.kind := lparench;
|
||||||
|
op^.token.class := reservedSymbol;
|
||||||
|
parenCount := parenCount+1;
|
||||||
|
NextToken; {process the controlling expression}
|
||||||
|
tempExpr := ExpressionTree(normalExpression, [commach]);
|
||||||
|
lCodeGeneration := codeGeneration;
|
||||||
|
codeGeneration := false;
|
||||||
|
GenerateCode(tempExpr);
|
||||||
|
codeGeneration := lCodeGeneration and (numErrors = 0);
|
||||||
|
{get controlling type after conversions}
|
||||||
|
if expressionType^.kind = functionType then begin
|
||||||
|
controllingType.size := cgLongSize;
|
||||||
|
controllingType.saveDisp := 0;
|
||||||
|
controllingType.isConstant := false;
|
||||||
|
controllingType.kind := pointerType;
|
||||||
|
controllingType.pType := expressionType;
|
||||||
|
end {if}
|
||||||
|
else
|
||||||
|
controllingType := expressionType^;
|
||||||
|
if controllingType.kind = arrayType then
|
||||||
|
controllingType.kind := pointerType;
|
||||||
|
controllingType.isConstant := false;
|
||||||
|
|
||||||
|
typesSeen := nil;
|
||||||
|
resultExpr := nil;
|
||||||
|
defaultExpr := nil;
|
||||||
|
foundMatch := false;
|
||||||
|
foundDefault := false;
|
||||||
|
while token.kind = commach do begin {process the generic associations}
|
||||||
|
NextToken;
|
||||||
|
typesMatch := false;
|
||||||
|
if token.kind <> defaultsy then begin
|
||||||
|
TypeName; {get the type name}
|
||||||
|
currentType := typeSpec;
|
||||||
|
if (currentType^.size = 0) or (currentType^.kind = functionType) then
|
||||||
|
Error(161);
|
||||||
|
tl := typesSeen; {check if it is a duplicate}
|
||||||
|
while tl <> nil do begin
|
||||||
|
if CompTypes(currentType, tl^.theType) then begin
|
||||||
|
Error(158);
|
||||||
|
goto 10;
|
||||||
|
end; {if}
|
||||||
|
tl := tl^.next;
|
||||||
|
end; {while}
|
||||||
|
new(tl); {record it as seen}
|
||||||
|
tl^.next := typesSeen;
|
||||||
|
tl^.theType := currentType;
|
||||||
|
typesSeen := tl;
|
||||||
|
{see if the types match}
|
||||||
|
typesMatch := CompTypes(currentType, controllingType);
|
||||||
|
if typesMatch then begin
|
||||||
|
if foundMatch then begin {sanity check - should never happen}
|
||||||
|
typesMatch := false;
|
||||||
|
Error(158);
|
||||||
|
end; {if}
|
||||||
|
foundMatch := true;
|
||||||
|
end; {if}
|
||||||
|
end {if}
|
||||||
|
else begin {handle default association}
|
||||||
|
NextToken;
|
||||||
|
currentType := nil;
|
||||||
|
if foundDefault then
|
||||||
|
Error(159);
|
||||||
|
foundDefault := true;
|
||||||
|
end; {else}
|
||||||
|
10:
|
||||||
|
if token.kind = colonch then {skip the colon}
|
||||||
|
NextToken
|
||||||
|
else
|
||||||
|
Error(29);
|
||||||
|
{get the expression in this association}
|
||||||
|
if (currentType = nil) and (defaultExpr = nil) and not foundMatch then
|
||||||
|
defaultExpr := ExpressionTree(kind, [commach,rparench])
|
||||||
|
else if typesMatch then
|
||||||
|
resultExpr := ExpressionTree(kind, [commach,rparench])
|
||||||
|
else
|
||||||
|
tempExpr := ExpressionTree(normalExpression, [commach,rparench]);
|
||||||
|
end; {while}
|
||||||
|
if token.kind <> rparench then
|
||||||
|
Error(12);
|
||||||
|
|
||||||
|
if not foundMatch then {use default if no match found}
|
||||||
|
if foundDefault then
|
||||||
|
resultExpr := defaultExpr;
|
||||||
|
if not (foundMatch or foundDefault) then begin
|
||||||
|
Error(160); {report error & synthesize a token}
|
||||||
|
resultExpr := pointer(Calloc(sizeof(tokenRecord)));
|
||||||
|
resultExpr^.token.kind := intconst;
|
||||||
|
resultExpr^.token.class := intConstant;
|
||||||
|
resultExpr^.token.ival := 0;
|
||||||
|
end; {if}
|
||||||
|
if resultExpr <> nil then begin
|
||||||
|
resultExpr^.next := stack; {stack the resulting expression}
|
||||||
|
stack := resultExpr;
|
||||||
|
end; {if}
|
||||||
|
expectingTerm := false;
|
||||||
|
end; {DoGeneric}
|
||||||
|
|
||||||
|
|
||||||
begin {ExpressionTree}
|
begin {ExpressionTree}
|
||||||
opStack := nil;
|
opStack := nil;
|
||||||
|
@ -1856,11 +1999,6 @@ if token.kind in startExpression then begin
|
||||||
|
|
||||||
{handle a complex operand}
|
{handle a complex operand}
|
||||||
DoOperand
|
DoOperand
|
||||||
else if token.kind = _Genericsy then begin
|
|
||||||
Error(144);
|
|
||||||
Skip;
|
|
||||||
goto 1;
|
|
||||||
end
|
|
||||||
else begin
|
else begin
|
||||||
{handle a constant operand}
|
{handle a constant operand}
|
||||||
new(sp);
|
new(sp);
|
||||||
|
@ -1982,6 +2120,8 @@ if token.kind in startExpression then begin
|
||||||
parenCount := parenCount+1;
|
parenCount := parenCount+1;
|
||||||
end;
|
end;
|
||||||
end {else if}
|
end {else if}
|
||||||
|
else if token.kind = _Genericsy then {handle _Generic}
|
||||||
|
DoGeneric
|
||||||
else begin {handle an operation...}
|
else begin {handle an operation...}
|
||||||
if expectingTerm then {convert unary operators to separate tokens}
|
if expectingTerm then {convert unary operators to separate tokens}
|
||||||
if token.kind in [asteriskch,minusch,plusch,andch] then
|
if token.kind in [asteriskch,minusch,plusch,andch] then
|
||||||
|
@ -4549,10 +4689,10 @@ procedure InitExpression;
|
||||||
begin {InitExpression}
|
begin {InitExpression}
|
||||||
startTerm := [ident,intconst,uintconst,longconst,ulongconst,longlongconst,
|
startTerm := [ident,intconst,uintconst,longconst,ulongconst,longlongconst,
|
||||||
ulonglongconst,floatconst,doubleconst,extendedconst,compconst,
|
ulonglongconst,floatconst,doubleconst,extendedconst,compconst,
|
||||||
charconst,scharconst,ucharconst,stringconst,_Genericsy];
|
charconst,scharconst,ucharconst,stringconst];
|
||||||
startExpression:= startTerm +
|
startExpression:= startTerm +
|
||||||
[lparench,asteriskch,andch,plusch,minusch,excch,tildech,sizeofsy,
|
[lparench,asteriskch,andch,plusch,minusch,excch,tildech,sizeofsy,
|
||||||
plusplusop,minusminusop,typedef,_Alignofsy];
|
plusplusop,minusminusop,typedef,_Alignofsy,_Genericsy];
|
||||||
end; {InitExpression}
|
end; {InitExpression}
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
|
@ -682,7 +682,7 @@ if list or (numErr <> 0) then begin
|
||||||
141: msg := @'_Noreturn specifier is only allowed on functions';
|
141: msg := @'_Noreturn specifier is only allowed on functions';
|
||||||
142: msg := @'_Alignas may not be used in this declaration or type name';
|
142: msg := @'_Alignas may not be used in this declaration or type name';
|
||||||
143: msg := @'only object pointer types may be restrict-qualified';
|
143: msg := @'only object pointer types may be restrict-qualified';
|
||||||
144: msg := @'generic selection expressions are not supported by ORCA/C';
|
{144: msg := @'generic selection expressions are not supported by ORCA/C';}
|
||||||
145: msg := @'invalid universal character name';
|
145: msg := @'invalid universal character name';
|
||||||
146: msg := @'Unicode character cannot be represented in execution character set';
|
146: msg := @'Unicode character cannot be represented in execution character set';
|
||||||
147: msg := @'lint: not all parameters were declared with a type';
|
147: msg := @'lint: not all parameters were declared with a type';
|
||||||
|
@ -696,6 +696,10 @@ if list or (numErr <> 0) then begin
|
||||||
155: msg := @'lint: non-void function may not return a value or has unreachable code';
|
155: msg := @'lint: non-void function may not return a value or has unreachable code';
|
||||||
156: msg := @'invalid suffix on numeric constant';
|
156: msg := @'invalid suffix on numeric constant';
|
||||||
157: msg := @'unknown or malformed standard pragma';
|
157: msg := @'unknown or malformed standard pragma';
|
||||||
|
158: msg := @'_Generic expression includes two compatible types';
|
||||||
|
159: msg := @'_Generic expression includes multiple default cases';
|
||||||
|
160: msg := @'no matching association in _Generic expression';
|
||||||
|
161: msg := @'complete object type expected';
|
||||||
otherwise: Error(57);
|
otherwise: Error(57);
|
||||||
end; {case}
|
end; {case}
|
||||||
writeln(msg^);
|
writeln(msg^);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user