Merge branch 'designated-initializers'

This implements designated initializers as specified by C99 and later.

It also fixes a few initialization-related bugs.
This commit is contained in:
Stephen Heumann 2022-12-04 21:28:15 -06:00
commit 935bb6c04e
14 changed files with 1171 additions and 584 deletions

View File

@ -321,14 +321,17 @@ type
initializerPtr = ^initializerRecord; {initializers}
initializerRecord = record
next: initializerPtr; {next record in the chain}
count: integer; {# of duplicate records}
disp: longint; {disp within overall object being initialized}
count: integer; {# of duplicate records (>1 for bytes only)}
bitdisp: integer; {disp in byte (field lists only)}
bitsize: integer; {width in bits; 0 for byte sizes}
isStructOrUnion: boolean; {is this a struct or union initializer?}
case isConstant: boolean of {is this a constant initializer?}
false: (iTree: tokenPtr);
false: (
iType: typePtr; {type being initialized}
iTree: tokenPtr; {initializer expression}
);
true : ( {Note: qVal.lo must overlap iVal}
case itype: baseTypeEnum of
case basetype: baseTypeEnum of
cgByte,
cgUByte,
cgWord,

40
CGI.pas
View File

@ -279,7 +279,11 @@ type
cgDouble,
cgComp,
cgExtended : (rval: extended);
cgString : (str: longStringPtr);
cgString : (
case isByteSeq: boolean of
false : (str: longStringPtr);
true : (data: ptr; len: longint);
);
cgVoid,
ccPointer : (pval: longint; pstr: longStringPtr);
end;
@ -574,6 +578,16 @@ procedure GenS (fop: pcodes; str: longstringPtr);
{ str - pointer to string }
procedure GenBS (fop: pcodes; data: ptr; len: longint);
{ generate an instruction that uses a byte sequence operand }
{ }
{ parameters: }
{ fop - operation code }
{ data - pointer to data }
{ data - length of data }
procedure GenL1 (fop: pcodes; lval: longint; fp1: integer);
{ generate an instruction that uses a longint and an int }
@ -1230,6 +1244,30 @@ if codeGeneration then begin
end; {GenS}
procedure GenBS {fop: pcodes; data: ptr; len: longint};
{ generate an instruction that uses a byte sequence operand }
{ }
{ parameters: }
{ fop - operation code }
{ data - pointer to data }
{ len - length of data }
var
lcode: icptr; {local copy of code}
begin {GenBS}
if codeGeneration then begin
lcode := code;
lcode^.optype := cgString;
lcode^.isByteSeq := true;
lcode^.data := data;
lcode^.len := len;
Gen0(fop);
end; {if}
end; {GenBS}
procedure GenL1 {fop: pcodes; lval: longint; fp1: integer};
{ generate an instruction that uses a longint and an int }

View File

@ -202,7 +202,8 @@ else if (op1 <> nil) and (op2 <> nil) then
or fastMath then
CodesMatch := true;
cgString:
CodesMatch := LongStrCmp(op1^.str, op2^.str);
if not (op1^.isByteSeq or op1^.isByteSeq) then
CodesMatch := LongStrCmp(op1^.str, op2^.str);
cgVoid, ccPointer:
if op1^.pval = op2^.pval then
CodesMatch := LongStrCmp(op1^.str, op2^.str);

28
MM.pas
View File

@ -23,6 +23,7 @@
{ GCalloc - allocate & clear memory from the global pool }
{ GInit - initialize a global pool }
{ GMalloc - allocate memory from the global pool }
{ GLongMalloc - allocate global memory }
{ LInit - initialize a local pool }
{ LMalloc - allocate memory from the local pool }
{ Malloc - allocate memory }
@ -73,6 +74,15 @@ procedure GInit;
{ Initialize a global pool }
function GLongMalloc (bytes: longint): ptr;
{ Allocate a potentially large amount of global memory. }
{ }
{ Parameters: }
{ bytes - number of bytes to allocate }
{ ptr - points to the first byte of the allocated memory }
function GMalloc (bytes: integer): ptr;
{ Allocate memory from the global pool. }
@ -182,6 +192,24 @@ globalPtr := pointer(ord4(globalPtr) + bytes);
end; {GMalloc}
function GLongMalloc {bytes: longint): ptr};
{ Allocate a potentially large amount of global memory. }
{ }
{ Parameters: }
{ bytes - number of bytes to allocate }
{ ptr - points to the first byte of the allocated memory }
var
myhandle: handle; {for dereferencing the block}
begin {GLongMalloc}
myhandle := NewHandle(bytes, globalID, $C000, nil);
if ToolError <> 0 then TermError(5);
GLongMalloc := myhandle^;
end; {GLongMalloc}
procedure LInit;
{ Initialize a local pool }

View File

@ -361,6 +361,7 @@ type
rkind = (k1,k2,k3,k4); {cnv record types}
var
bp: ^byte; {byte pointer}
ch: char; {temp storage for string constants}
cns: realRec; {for converting reals to bytes}
cnv: record {for converting double, real to bytes}
@ -672,9 +673,20 @@ case mode of
CnOut(cns.inSANE[j]);
end;
cgString : begin
sptr := icptr(name)^.str;
for j := 1 to sptr^.length do
CnOut(ord(sPtr^.str[j]));
if not icptr(name)^.isByteSeq then begin
sptr := icptr(name)^.str;
for j := 1 to sptr^.length do
CnOut(ord(sPtr^.str[j]));
end {if}
else begin
lval := 0;
while lval < icptr(name)^.len do begin
bp := pointer(
ord4(icptr(name)^.data) + lval);
CnOut(bp^);
lval := lval + 1;
end;
end; {else}
end;
ccPointer : begin
if icptr(name)^.lab <> nil then begin

1043
Parser.pas

File diff suppressed because it is too large Load Diff

View File

@ -49,6 +49,7 @@ type
next: tokenListRecordPtr; {next element in list}
token: tokenType; {token}
expandEnabled: boolean; {can this token be macro expanded?}
suppressPrint: boolean; {suppress printing with #pragma expand?}
tokenStart,tokenEnd: ptr; {token start/end markers}
end;
macroRecordPtr = ^macroRecord;
@ -153,13 +154,15 @@ procedure NextToken;
{ Read the next token from the file. }
procedure PutBackToken (var token: tokenType; expandEnabled: boolean);
procedure PutBackToken (var token: tokenType; expandEnabled: boolean;
suppressPrint: boolean);
{ place a token into the token stream }
{ }
{ parameters: }
{ token - token to put back into the token stream }
{ expandEnabled - can macro expansion be performed? }
{ suppressPrint - suppress printing with #pragma expand? }
procedure TermScanner;
@ -510,13 +513,15 @@ macroFound := mPtr;
end; {IsDefined}
procedure PutBackToken {var token: tokenType; expandEnabled: boolean};
procedure PutBackToken {var token: tokenType; expandEnabled: boolean;
suppressPrint: boolean};
{ place a token into the token stream }
{ }
{ parameters: }
{ token - token to put back into the token stream }
{ expandEnabled - can macro expansion be performed? }
{ suppressPrint - suppress printing with #pragma expand? }
var
tPtr: tokenListRecordPtr; {work pointer}
@ -527,6 +532,7 @@ tPtr^.next := tokenList;
tokenList := tPtr;
tPtr^.token := token;
tPtr^.expandEnabled := expandEnabled;
tPtr^.suppressPrint := suppressPrint;
tPtr^.tokenStart := tokenStart;
tPtr^.tokenEnd := tokenEnd;
end; {PutBackToken}
@ -777,6 +783,8 @@ if list or (numErr <> 0) then begin
179: msg := @'_Pragma requires one string literal argument';
180: msg := @'decimal digit sequence expected';
181: msg := @'''main'' may not have any function specifiers';
182: msg := @'''='' expected';
183: msg := @'array index out of bounds';
otherwise: Error(57);
end; {case}
writeln(msg^);
@ -1626,7 +1634,7 @@ else
end; {for}
token.sval^.str[len+1] := chr(0);
token.sval^.length := len+1;
PutBackToken(token, true);
PutBackToken(token, true, false);
end; {BuildStringToken}
@ -1915,7 +1923,7 @@ if macro^.parameters >= 0 then begin {find the values of the parameters}
Error(14);
if token.kind <> rparench then begin {insist on a closing ')'}
if not gettingFileName then {put back the source stream token}
PutBackToken(token, true);
PutBackToken(token, true, false);
Error(12);
end; {if}
preprocessing := lPreprocessing;
@ -1923,7 +1931,7 @@ if macro^.parameters >= 0 then begin {find the values of the parameters}
else begin
Error(13);
if not gettingFileName then {put back the source stream token}
PutBackToken(token, true);
PutBackToken(token, true, false);
end; {else}
end; {if}
if macro^.readOnly then begin {handle special macros}
@ -2038,7 +2046,7 @@ if macro^.readOnly then begin {handle special macros}
end; {case}
if macro^.algorithm <> 8 then {if not _Pragma}
PutBackToken(token, true);
PutBackToken(token, true, false);
end {if}
else begin
@ -2126,11 +2134,11 @@ else begin
if expandEnabled then
if tcPtr^.token.name^ = macro^.name^ then
expandEnabled := false;
PutBackToken(tcPtr^.token, expandEnabled);
PutBackToken(tcPtr^.token, expandEnabled, false);
end; {else}
end {if}
else
PutBackToken(tcPtr^.token, true);
PutBackToken(tcPtr^.token, true, false);
tcPtr := tcPtr^.next;
end; {while}
end; {else}
@ -2145,7 +2153,7 @@ else begin
expandEnabled := false;
tokenStart := tlPtr^.tokenStart;
tokenEnd := tlPtr^.tokenEnd;
PutBackToken(tlPtr^.token, expandEnabled);
PutBackToken(tlPtr^.token, expandEnabled, false);
end; {else}
lastPtr := tlPtr;
tlPtr := tlPtr^.next;
@ -3436,7 +3444,7 @@ if ch in ['a','d','e','i','l','p','u','w'] then begin
end; {if}
if token.name^ <> 'STDC' then begin
{Allow macro expansion, other than for STDC }
PutBackToken(token, true);
PutBackToken(token, true, false);
NextToken;
end; {if}
if token.name^ = 'keep' then
@ -4901,6 +4909,7 @@ var
tPtr: tokenListRecordPtr; {for removing tokens from putback buffer}
tToken: tokenType; {for merging tokens}
sPtr,tsPtr: gstringPtr; {for forming string constants}
suppressPrint: boolean; {suppress printing the token?}
lLastWasReturn: boolean; {local copy of lastWasReturn}
codePoint: longint; {Unicode character value}
chFromUCN: integer; {character given by UCN (converted)}
@ -5164,6 +5173,7 @@ if tokenList <> nil then begin {get a token put back by a macro}
tokenList := tPtr^.next;
expandEnabled := tPtr^.expandEnabled;
tokenExpandEnabled := expandEnabled;
suppressPrint := tPtr^.suppressPrint;
token := tPtr^.token;
tokenStart := tPtr^.tokenStart;
tokenEnd := tPtr^.tokenEnd;
@ -5224,7 +5234,9 @@ if tokenList <> nil then begin {get a token put back by a macro}
expandMacros := lExpandMacros;
end; {if}
goto 2;
end; {if}
end {if}
else
suppressPrint := false;
5: {skip white space}
while charKinds[ord(ch)] in [illegal,ch_white,ch_eol,ch_pound] do begin
if charKinds[ord(ch)] = ch_pound then begin
@ -5738,7 +5750,7 @@ if (token.kind = stringconst) and not mergingStrings {handle adjacent strings}
done := false;
end {if}
else begin
PutBackToken(token, tokenExpandEnabled);
PutBackToken(token, tokenExpandEnabled, false);
done := true;
end; {else}
token := tToken;
@ -5753,8 +5765,10 @@ if doingPPExpression then begin
if token.kind = typedef then
token.kind := ident;
end; {if}
if printMacroExpansions and not suppressMacroExpansions then
PrintToken(token); {print the token stream}
if printMacroExpansions then
if not suppressMacroExpansions then
if not suppressPrint then
PrintToken(token); {print the token stream}
if token.kind = otherch then
if not (skipping or preprocessing or suppressMacroExpansions)
or doingPPExpression then

View File

@ -22,3 +22,19 @@ lb1 sta [table],Y
return
end
****************************************************************
*
* SaveBF - save a value to a bit-field
*
* Inputs:
* addr - address to copy to
* bitdisp - displacement past the address
* bitsize - number of bits
* val - value to copy
*
****************************************************************
*
SaveBF private cc
jml ~SaveBF call ~SaveBF in ORCALib
end

View File

@ -295,6 +295,14 @@ function StringType(prefix: charStrPrefixEnum): typePtr;
implementation
type
{From CGC.pas}
realrec = record {used to convert from real to in-SANE}
itsReal: extended;
inSANE: packed array[1..10] of byte;
inCOMP: packed array[1..8] of byte;
end;
var
staticNum: packed array[1..6] of char; {static variable number}
@ -325,6 +333,17 @@ function UsualUnaryConversions: baseTypeEnum; extern;
{ outputs: }
{ expressionType - set to result type }
{- Imported from CGC.pas ---------------------------------------}
procedure CnvSC (rec: realrec); extern;
{ convert a real number to SANE comp format }
{ }
{ parameters: }
{ rec - record containing the value to convert; also }
{ has space for the result }
{---------------------------------------------------------------}
procedure CnOut (i: integer); extern;
@ -396,6 +415,16 @@ procedure ClearTable (table: symbolTable); extern;
{ clear the symbol table to all zeros }
procedure SaveBF (addr: ptr; bitdisp, bitsize: integer; val: longint); extern;
{ save a value to a bit-field }
{ }
{ parameters: }
{ addr - address to copy to }
{ bitdisp - displacement past the address }
{ bitsize - number of bits }
{ val - value to copy }
{---------------------------------------------------------------}
@ -663,6 +692,218 @@ procedure DoGlobals;
{ declare the ~globals and ~arrays segments }
procedure StaticInit (variable: identPtr);
{ statically initialize a variable }
type
{record of pointer initializers}
relocPtr = ^relocationRecord;
relocationRecord = record
next: relocPtr; {next record}
initializer: initializerPtr; {the initializer}
disp: longint; {disp in overall data structure}
end;
{pointers to each type}
bytePtr = ^byte;
wordPtr = ^integer;
longPtr = ^longint;
quadPtr = ^longlong;
realPtr = ^real;
doublePtr = ^double;
extendedPtr = ^extended;
var
buffPtr: ptr; {pointer to data buffer}
count: integer; {# of duplicate records}
disp: longint; {disp into buffer (for output)}
endDisp: longint; {ending disp for current chunk}
i: integer; {loop counter}
ip: initializerPtr; {used to trace initializer lists}
lastReloc, nextReloc: relocPtr; {for reversing relocs list}
realVal: realRec; {used for extended-to-comp conversion}
relocs: relocPtr; {list of records needing relocation}
{pointers used to write data}
bp: bytePtr;
wp: wordPtr;
lp: longPtr;
qp: quadPtr;
rp: realPtr;
dp: doublePtr;
ep: extendedPtr;
procedure UpdateRelocs;
{ update relocation records to account for an initializer }
var
disp: longint; {disp of current initializer}
done: boolean; {done with loop?}
endDisp: longint; {disp at end of current initializer}
last: ^relocPtr; {the pointer referring to rp}
rp: relocPtr; {reloc record being processed}
begin {UpdateRelocs}
disp := ip^.disp;
if ip^.bitsize <> 0 then begin
endDisp := disp + (ip^.bitdisp + ip^.bitsize + 7) div 8;
disp := disp + ip^.bitdisp div 8;
end {if}
else if ip^.basetype = cgString then
endDisp := disp + ip^.sVal^.length
else
endDisp := disp + TypeSize(ip^.baseType);
last := @relocs;
rp := relocs;
done := false;
while (rp <> nil) and not done do begin
if rp^.disp + cgPointerSize <= disp then begin
{initializer is entirely after this reloc: no conflicts}
done := true;
end {if}
else if endDisp <= rp^.disp then begin
{initializer is entirely before this reloc}
last := @rp^.next;
rp := rp^.next;
end {else if}
else begin
{conflict: remove the conflicting reloc record}
last^ := rp^.next;
lp := pointer(ord4(buffPtr) + rp^.disp);
lp^ := 0;
dispose(rp);
rp := last^;
end; {else}
end; {while}
if ip^.basetype = ccPointer then begin
new(rp);
rp^.next := last^;
last^ := rp;
rp^.disp := ip^.disp;
rp^.initializer := ip;
end; {if}
end; {UpdateRelocs}
begin {StaticInit}
{allocate buffer}
{(+3 for possible bitfield overhang)}
buffPtr := GLongMalloc(variable^.itype^.size+3);
relocs := nil; {evaluate initializers}
ip := variable^.iPtr;
while ip <> nil do begin
count := 0;
while count < ip^.count do begin
UpdateRelocs;
if ip^.bitsize <> 0 then begin
bp := pointer(ord4(buffPtr) + ip^.disp + count);
SaveBF(bp, ip^.bitdisp, ip^.bitsize, ip^.iVal);
end {if}
else
case ip^.basetype of
cgByte,cgUByte: begin
bp := pointer(ord4(buffPtr) + ip^.disp + count);
bp^ := ord(ip^.iVal) & $ff;
end;
cgWord,cgUWord: begin
wp := pointer(ord4(buffPtr) + ip^.disp + count);
wp^ := ord(ip^.iVal);
end;
cgLong,cgULong: begin
lp := pointer(ord4(buffPtr) + ip^.disp + count);
lp^ := ip^.iVal;
end;
cgQuad,cgUQuad: begin
qp := pointer(ord4(buffPtr) + ip^.disp + count);
qp^ := ip^.qVal;
end;
cgReal: begin
rp := pointer(ord4(buffPtr) + ip^.disp + count);
rp^ := ip^.rVal;
end;
cgDouble: begin
dp := pointer(ord4(buffPtr) + ip^.disp + count);
dp^ := ip^.rVal;
end;
cgExtended: begin
ep := pointer(ord4(buffPtr) + ip^.disp + count);
ep^ := ip^.rVal;
end;
cgComp: begin
realVal.itsReal := ip^.rVal;
CnvSC(realVal);
for i := 1 to 8 do begin
bp := pointer(ord4(buffPtr) + ip^.disp + count + i-1);
bp^ := realVal.inCOMP[i];
end; {for}
end;
cgString: begin
for i := 1 to ip^.sVal^.length do begin
bp := pointer(ord4(buffPtr) + ip^.disp + count + i-1);
bp^ := ord(ip^.sVal^.str[i]);
end; {for}
end;
ccPointer: ; {handled by UpdateRelocs}
cgVoid: Error(57);
end; {case}
count := count + 1; {assumes count > 1 only for bytes}
end; {while}
ip := ip^.next;
end; {while}
lastReloc := nil; {reverse the relocs list}
while relocs <> nil do begin
nextReloc := relocs^.next;
relocs^.next := lastReloc;
lastReloc := relocs;
relocs := nextReloc;
end; {while}
relocs := lastReloc;
disp := 0; {generate the initialization data}
while disp < variable^.itype^.size do begin
if relocs = nil then
endDisp := variable^.itype^.size
else
endDisp := relocs^.disp;
if disp <> endDisp then begin
GenBS(dc_cns, pointer(ord4(buffPtr) + disp), endDisp - disp);
disp := endDisp;
end; {if}
if relocs <> nil then begin
code^.optype := ccPointer;
code^.r := ord(relocs^.initializer^.pPlus);
code^.q := 1;
code^.pVal := relocs^.initializer^.pVal;
if relocs^.initializer^.isName then begin
code^.lab := relocs^.initializer^.pName;
code^.pstr := nil;
end {if}
else
code^.pstr := relocs^.initializer^.pstr;
Gen0(dc_cns);
lastReloc := relocs;
relocs := relocs^.next;
dispose(lastReloc);
disp := disp + cgPointerSize;
end; {if}
end; {while}
end; {StaticInit}
procedure GenArrays;
{ define global arrays }
@ -697,38 +938,7 @@ procedure DoGlobals;
end; {if}
if sp^.state = initialized then begin
Gen2Name(dc_glb, 0, ord(sp^.storage = private), sp^.name);
ip := sp^.iPtr;
while ip <> nil do begin
case ip^.itype of
cgByte,cgUByte,cgWord,cgUWord: begin
lval := ip^.ival;
Gen2t(dc_cns, long(lval).lsw, ip^.count, ip^.itype);
end;
cgLong,cgULong:
GenL1(dc_cns, ip^.ival, ip^.count);
cgQuad,cgUQuad:
GenQ1(dc_cns, ip^.qval, ip^.count);
cgReal,cgDouble,cgComp,cgExtended:
GenR1t(dc_cns, ip^.rval, ip^.count, ip^.itype);
cgString:
GenS(dc_cns, ip^.sval);
ccPointer: begin
code^.optype := ccPointer;
code^.r := ord(ip^.pPlus);
code^.q := ip^.count;
code^.pVal := ip^.pVal;
if ip^.isName then begin
code^.lab := ip^.pName;
code^.pstr := nil;
end {if}
else
code^.pstr := ip^.pstr;
Gen0(dc_cns);
end;
otherwise: Error(57);
end; {case}
ip := ip^.next;
end; {while}
StaticInit(sp);
end {if}
else begin
size := sp^.itype^.size;
@ -790,17 +1000,17 @@ procedure DoGlobals;
if sp^.state = initialized then begin
Gen2Name(dc_glb, 0, ord(sp^.storage = private), sp^.name);
ip := sp^.iPtr;
case ip^.itype of
case ip^.basetype of
cgByte,cgUByte,cgWord,cgUWord: begin
lval := ip^.ival;
Gen2t(dc_cns, long(lval).lsw, 1, ip^.itype);
Gen2t(dc_cns, long(lval).lsw, 1, ip^.basetype);
end;
cgLong,cgULong:
GenL1(dc_cns, ip^.ival, 1);
cgQuad,cgUQuad:
GenQ1(dc_cns, ip^.qval, 1);
cgReal,cgDouble,cgComp,cgExtended:
GenR1t(dc_cns, ip^.rval, 1, ip^.itype);
GenR1t(dc_cns, ip^.rval, 1, ip^.basetype);
cgString:
GenS(dc_cns, ip^.sval);
ccPointer: begin
@ -1287,7 +1497,7 @@ var
if ip = nil then ip := defaultStruct^.fieldList;
while ip <> nil do begin
if ip^.name^ <> '~anonymous' then
if ip^.name^[1] <> '~' then
GenSymbol(ip, none);
ip := ip^.next;
end; {while}

View File

@ -24,6 +24,7 @@
{1} c99tgmath.c
{1} c99pragma.c
{1} c99inline.c
{1} c99desinit.c
{1} c11generic.c
{1} c11align.c
{1} c11noret.c

View File

@ -55,6 +55,22 @@ int main(void) {
if (s2p->d != 123.5)
goto Fail;
struct S s3 = {.b = 10, 20, .a=30};
if (s3.a != 30)
goto Fail;
if (s3.b != 10)
goto Fail;
if (s3.c != 20)
goto Fail;
struct S s4 = {.a=30, 10, 20.5, .d = 123.5};
if (s4.a != 30)
goto Fail;
if (s4.d != 123.5)
goto Fail;
if (sizeof(struct S) != sizeof(struct T))
goto Fail;

View File

@ -85,6 +85,16 @@ int main(void) {
if (s.a || !s.b)
goto Fail;
_Bool b1 = 123;
_Bool b2 = -123.5;
_Bool b3 = 0.0;
static _Bool b4 = 0x100000000;
static _Bool b5 = 0.0001;
static _Bool b6 = -0.0;
if (b1 != 1 || b2 != 1 || b3 != 0 || b4 != 1 || b5 != 1 || b6 != 0)
goto Fail;
printf ("Passed Conformance Test c99bool\n");
return 0;

View File

@ -0,0 +1,208 @@
/*
* Test of designated initializers (C99).
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifndef __ORCAC__
typedef long long comp;
#endif
struct S1 {
int i;
union {
long x;
char y;
} u;
short a[3];
} s1 = {8, .a[0] = 9, .u.y = 'F', .i = 50, .a = {[1]=1,2}, .a[1] = 10};
struct S2 {
char c;
unsigned char uc;
signed char sc;
short s;
unsigned short us;
int i;
unsigned int ui;
long l;
unsigned long ul;
long long ll;
unsigned long long ull;
_Bool b;
float f;
double d;
long double ld;
comp cp;
void *p;
} s2 = {.p = &s2, .i = 123.4, .ui = 70, -123456, 123456, .c = 'd', 'e', 'f',
.us = 78, .s = 40.1, .ll = 1234567890, 0x800000001, 123, 123.5,
.cp = 9876543210, .d = -456.5, -789.5,
};
struct S3 {
float f;
double d;
long double ld;
} s3 = {-123456LL, 3000000000U, 12345678900ULL};
char s4[] = {{123}, [3] = {'x'}};
struct S5 {
int :16;
signed int a:4;
signed int b:6;
signed int c:6;
int :0;
unsigned d:9;
int :12;
unsigned e:4;
unsigned f:16;
long g;
int :15;
} s5 = {-4, -5, 3, .g = 123456789, .d = 455, 8, 42345};
char *s6[4] = {s4, s4+1, [0]=0, [1]=s4+2, &s4[3], s4+4};
union U9 {
union U9 *p;
char s[6];
} s9 = {&s9, .s = {"abcde"}, .s[1] = 'x'};
union U9 s10 = {&s9, .s = {"abcde"}, .s[1] = 'x', .p = &s10};
union U9 s11 = {&s9, .s[1] = 'x'};
struct S13 {
struct S13a {
struct S13b {
struct S13c {
int a;
int b;
} z;
} y;
} x;
} s13 = {13, .x.y.z = {.b = 14}};
int f1(int i) {return i * 2 + 1;}
int main(void) {
struct S1 a1 =
{8, .a[0] = 9, .u.y = 'F', .i = 50, .a = {[1]=1,2}, .a[1] = 10};
struct S2 a2 =
{.p = &s2, .i = 123.4, .ui = 70, -123456, 123456, .c = 'd', 'e', 'f',
.us = 78, .s = 40.1, .ll = 1234567890, 0x800000001, 123, 123.5,
.cp = 9876543210, .d = -456.5, -789.5,
};
struct S3 a3 = {-123456LL, 3000000000U, 12345678900ULL};
char a4[] = {{123}, [3] = {'x'}};
struct S5 a5 = {-4, -5, 3, .g = 123456789, .d = 455, 8, 42345};
char *a6[4] = {s4, s4+1, [0]=0, [1]=s4+2, &s4[3], s4+4};
char a7[] = {"foo"[0], [1] = "foo"[2], "foo"[3]};
char a8[] = {"foo" != 0, [1] = "foo" == 0};
union U9 a9 = {&s9, .s = {"abcde"}, .s[1] = 'x'};
union U9 a10 = {&s9, .s = {"abcde"}, .s[1] = 'x', .p = &s10};
union U9 a11 = {&s9, .s[1] = 'x'};
struct S3 a12 = {.ld = f1(1)-8, .f = f1(2)*7, f1(3)+10};
struct S13 a13 = {s13.x.y};
if (s1.i!=50 || s1.u.y!='F' || s1.a[0]!=0 || s1.a[1]!=10 || s1.a[2]!=2)
goto Fail;
if (a1.i!=50 || a1.u.y!='F' || a1.a[0]!=0 || a1.a[1]!=10 || a1.a[2]!=2)
goto Fail;
if (s2.c != 'd' || s2.uc != 'e' || s2.sc != 'f' || s2.s != 40
|| s2.us != 78 || s2.i != 123 || s2.ui != 70 || s2.l != -123456
|| s2.ul != 123456 || s2.ll != 1234567890
|| s2.ull != 0x800000001 || s2.b != 1 || s2.f != 123.5
|| s2.d != -456.5 || s2.ld != -789.5 || s2.cp != 9876543210
|| s2.p != &s2)
goto Fail;
if (a2.c != 'd' || a2.uc != 'e' || a2.sc != 'f' || a2.s != 40
|| a2.us != 78 || a2.i != 123 || a2.ui != 70 || a2.l != -123456
|| a2.ul != 123456 || a2.ll != 1234567890
|| a2.ull != 0x800000001 || a2.b != 1 || a2.f != 123.5
|| a2.d != -456.5 || a2.ld != -789.5 || a2.cp != 9876543210
|| a2.p != &s2)
goto Fail;
if (s3.f != -123456.0 || s3.d != 3000000000.0 || s3.ld != 12345678900.0)
goto Fail;
if (a3.f != -123456.0 || a3.d != 3000000000.0 || a3.ld != 12345678900.0)
goto Fail;
if (sizeof(s4) != 4 || s4[0] != 123 || s4[1] != 0 || s4[2] != 0
|| s4[3] != 'x')
goto Fail;
if (sizeof(a4) != 4 || a4[0] != 123 || a4[1] != 0 || a4[2] != 0
|| a4[3] != 'x')
goto Fail;
if (s5.a != -4 || s5.b != -5 || s5.c != 3 || s5.d != 455 || s5.e != 8
|| s5.f != 42345 || s5.g != 123456789)
goto Fail;
if (a5.a != -4 || a5.b != -5 || a5.c != 3 || a5.d != 455 || a5.e != 8
|| a5.f != 42345 || a5.g != 123456789)
goto Fail;
if (s6[0] != 0 || s6[1] != &s4[2] || s6[2] != &s4[3] || s6[3] != s4+4)
goto Fail;
if (a6[0] != 0 || a6[1] != &s4[2] || a6[2] != &s4[3] || a6[3] != s4+4)
goto Fail;
if (sizeof(a7) != 3 || a7[0] != 'f' || a7[1] != 'o' || a7[2] != 0)
goto Fail;
if (sizeof(a8) != 2 || a8[0] != 1 || a8[1] != 0)
goto Fail;
if (strcmp(s9.s, "axcde") != 0)
goto Fail;
if (strcmp(a9.s, "axcde") != 0)
goto Fail;
if (s10.p != &s10)
goto Fail;
if (a10.p != &s10)
goto Fail;
if (s11.s[1] != 'x')
goto Fail;
if (a11.s[1] != 'x')
goto Fail;
if (a12.f != 35 || a12.d != 17 || a12.ld != -5)
goto Fail;
if (a13.x.y.z.a != 0 || a13.x.y.z.b != 14)
goto Fail;
printf ("Passed Conformance Test c99desinit\n");
return 0;
Fail:
printf ("Failed Conformance Test c99desinit\n");
}

View File

@ -603,6 +603,37 @@ is equivalent to the directive
The _Pragma("...") token sequence may be formed using preprocessor macros.
30. (C99) ORCA/C now supports designated initializers, which let you explicitly specify the array element or struct/union member that should be initialized by an expression within a braced initializer list. They have the form:
designator-list = expression
Designators may be of the form
[ constant-expression ]
to designate an element of an array, or
. identifier
to designate a specific field of a structure or union. A designator list may consist of one or more designators; successive designators correspond to successive levels of a nested data structure.
Designated and non-designated initializers may be mixed within an initializer list. If a non-designated initializer follows a designated one, it applies to the next subobject after the designated one, and initialization continues forward in the usual order until it is complete or another designator is encountered. If a braced initializer list does not include initializers for all the elements of an array or all the named members of a structure, the other ones are initialized to 0 (the same as when not using designated initializers).
Designated initializers make it possible to initialize subobjects in any order, and to initialize later subobjects without having to write an explicit initializer for earlier ones. Designated initializers also allow union members other than the first one to be initialized. It is also possible to initialize the same subobject multiple times, but in that case the initializer appearing latest in the initializer list will override any earlier ones.
As an example, the declaration
struct {
int i;
union {
long x;
char y;
} u;
short a[3];
} s = {20, .a[0] = 9, .u.y = 'F', .i = 50, .a = {[1]=1,2}, .a[1] = 10};
sets s.i to 50, s.u.y to 'F', s.a[0] to 0, s.a[1] to 10, and s.a[2] to 2.
Multi-Character Character Constants
-----------------------------------
@ -1976,6 +2007,12 @@ int foo(int[42]);
220. In certain cases where a header starts or ends in the middle of a declaration, it would not be represented correctly in the .sym file. This could cause errors or misbehavior on subsequent compiles.
221. Structures with unnamed bit-fields were sometimes initialized incorrectly.
222. If an expression of type unsigned long and value greater than LONG_MAX was used in the initializer for a floating-point variable with static storage duration, the wrong value would be produced.
223. Expressions of floating-point type could not be used in initializers for integer variables with static storage duration. This should be allowed, with a conversion performed as in the case of assignment.
-- Bugs from C 2.1.0 that have been fixed -----------------------------------
1. In some situations, fread() reread the first 1K or so of the file.