diff --git a/CCommon.pas b/CCommon.pas index 8e20e63..102d4a0 100644 --- a/CCommon.pas +++ b/CCommon.pas @@ -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, diff --git a/CGI.pas b/CGI.pas index 6cb3227..0e0803b 100644 --- a/CGI.pas +++ b/CGI.pas @@ -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 } diff --git a/DAG.pas b/DAG.pas index 3bb3981..13d6cca 100644 --- a/DAG.pas +++ b/DAG.pas @@ -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); diff --git a/MM.pas b/MM.pas index d8ff341..d4e44fd 100644 --- a/MM.pas +++ b/MM.pas @@ -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 } diff --git a/Native.pas b/Native.pas index e4b231e..8cd5156 100644 --- a/Native.pas +++ b/Native.pas @@ -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 diff --git a/Parser.pas b/Parser.pas index d1dc492..4e7e388 100644 --- a/Parser.pas +++ b/Parser.pas @@ -182,6 +182,7 @@ type 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} @@ -219,6 +220,16 @@ 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}; @@ -987,7 +998,7 @@ case token.kind of lToken := token; NextToken; tToken := token; - PutBackToken(token, true); + PutBackToken(token, true, false); token := lToken; suppressMacroExpansions := lSuppressMacroExpansions; if tToken.kind = colonch then begin @@ -1109,12 +1120,12 @@ Gen1(dc_lab, stPtr^.continueLab); {define the continue label} tl := stPtr^.e3List; {place the expression back in the list} if tl <> nil then begin - PutBackToken(token, false); + PutBackToken(token, false, false); ltoken.kind := semicolonch; ltoken.class := reservedSymbol; - PutBackToken(ltoken, false); + PutBackToken(ltoken, false, false); while tl <> nil do begin - PutBackToken(tl^.token, false); + PutBackToken(tl^.token, false, false); tk := tl; tl := tl^.next; dispose(tk); @@ -1462,12 +1473,12 @@ var NextToken; suppressMacroExpansions := lSuppressMacroExpansions; if token.kind = rparench then begin - PutBackToken(token, false); + PutBackToken(token, false, false); NextToken; tPtr2^.prototyped := true; end else begin - PutBackToken(token, false); + PutBackToken(token, false, false); token.kind := voidsy; token.class := reservedSymbol; end; {else} @@ -1854,57 +1865,45 @@ procedure Initializer (var variable: identPtr); { variable - ptr to the identifier begin initialized } var - bitcount: integer; {# if bits initialized} - bitvalue: longint; {bit field initializer value} + 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 InitializeBitField; + procedure InsertInitializerRecord (iPtr: initializerPtr; size: longint); - { If bit fields have been initialized, fill them in } + { Insert an initializer record in the initializer list } { } - { Inputs: } - { bitcount - # of bits initialized } - { bitvalue - value of initializer } + { 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} - var - iPtr: initializerPtr; {for creating an initializer entry} - - begin {InitializeBitField} - if bitcount <> 0 then begin {skip if there has been no initializer} -{ writeln('InitializeBitField; bitcount = ', bitcount:1); {debug} - {create the initializer entry} - iPtr := pointer(Malloc(sizeof(initializerRecord))); - iPtr^.next := variable^.iPtr; - variable^.iPtr := iPtr; - iPtr^.isConstant := isConstant; - iPtr^.count := 1; - iPtr^.bitdisp := 0; - iPtr^.bitsize := 0; - iPtr^.isStructOrUnion := false; - iPtr^.iVal := bitvalue; - if bitcount <= 8 then - iPtr^.itype := cgUByte - else if bitcount <= 16 then - iPtr^.itype := cgUWord - else if bitcount > 24 then - iPtr^.itype := cgULong - else begin {3-byte bitfield: split into two parts} - iPtr^.itype := cgUWord; - iPtr^.iVal := bitvalue & $0000FFFF; - bitcount := bitcount - 16; - bitvalue := bitvalue >> 16; - InitializeBitField; - end; - bitcount := 0; {reset the bit field values} - bitvalue := 0; - end; {if} - end; {InitializeBitField} + 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); @@ -1915,10 +1914,9 @@ var { bitsize - size of bit field (0 for non-bit fields) } { bitdisp - disp of bit field; unused if bitsize = 0 } - label 1,2,3; + label 1,2; var - bitmask: longint; {used to add a value to a bit field} bKind: baseTypeEnum; {type of constant} etype: typePtr; {expression type} i: integer; {loop variable} @@ -1927,6 +1925,7 @@ var 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} @@ -2036,56 +2035,36 @@ var begin {GetInitializerValue} - if token.kind in [dotch,lbrackch] then begin - {designated initializer: give error and skip over it} - Error(150); - while token.kind in [dotch,lbrackch] do begin - if token.kind = lbrackch then begin - NextToken; - Expression(arrayExpression, [rbrackch]); - if token.kind = rbrackch then - NextToken; - end {if} - else {if token.kind = dotch then} begin - NextToken; - if token.kind in [ident,typedef] then - NextToken; - end {if} - end; {while} - if token.kind = eqch then - NextToken; - end; {if} - if variable^.storage = stackFrame then - Expression(autoInitializerExpression, [commach,rparench,rbracech]) + 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 - Expression(initializerExpression, [commach,rparench,rbracech]); - if bitsize = 0 then begin - iPtr := pointer(Malloc(sizeof(initializerRecord))); - iPtr^.next := variable^.iPtr; - variable^.iPtr := iPtr; - iPtr^.isConstant := isConstant; - iPtr^.count := 1; - iPtr^.bitdisp := 0; - iPtr^.bitsize := 0; - iPtr^.isStructOrUnion := false; - end; {if} + 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 (variable^.storage in [external,global,private]) then begin - if bitsize = 0 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^.itype := tp^.baseType; - InitializeBitField; - end; {if} + 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 @@ -2104,34 +2083,38 @@ var iPtr^.qVal.hi := -1 else iPtr^.qVal.hi := 0; - goto 3; + 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 - iPtr^.rVal := expressionValue + 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; - goto 3; + 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; - goto 2; - -3: if bitsize <> 0 then begin - - {set up a bit field value} - if bitdisp < bitcount then - InitializeBitField; - bitmask := 0; - for i := 1 to bitsize do - bitmask := (bitmask << 1) | 1; - bitmask := bitmask & expressionValue; - for i := 1 to bitdisp do - bitmask := bitmask << 1; - bitvalue := bitvalue | bitmask; - bitcount := bitcount + bitsize; - end; {if} end; arrayType: begin @@ -2147,7 +2130,7 @@ var if (etype = stringTypePtr) or (etype = utf16StringTypePtr) or (etype = utf32StringTypePtr) then begin iPtr^.isConstant := true; - iPtr^.iType := ccPointer; + iPtr^.basetype := ccPointer; iPtr^.pval := 0; iPtr^.pPlus := false; iPtr^.isName := false; @@ -2156,7 +2139,7 @@ var else if etype^.kind = scalarType then if etype^.baseType in [cgByte..cgULong] then if expressionValue = 0 then - iPtr^.iType := cgULong + iPtr^.basetype := cgULong else begin Error(47); errorFound := true; @@ -2164,7 +2147,7 @@ var else if etype^.baseType in [cgQuad,cgUQuad] then if (llExpressionValue.hi = 0) and (llExpressionValue.lo = 0) then - iPtr^.iType := cgULong + iPtr^.basetype := cgULong else begin Error(47); errorFound := true; @@ -2174,7 +2157,7 @@ var errorFound := true; end {else} else if etype^.kind = pointerType then begin - iPtr^.iType := cgULong; + iPtr^.basetype := cgULong; iPtr^.pval := expressionValue; end {else if} else begin @@ -2198,8 +2181,8 @@ var or ((tp^.kind = scalarType) and (tp^.baseType in [cgLong,cgULong]))) and (bitsize = 0) then begin - iPtr^.iType := ccPointer; - if variable^.storage in [external,global,private] then begin + iPtr^.basetype := ccPointer; + if isStatic then begin {do pointer constants with + or -} iPtr^.isConstant := true; @@ -2332,36 +2315,67 @@ var DisposeTree(initializerTree); goto 1; end; {if} - end {if} - else if tp^.kind in [structType,unionType] then - iPtr^.isStructOrUnion := true; + end; {if} {handle auto variables} - if bitsize <> 0 then begin - iPtr := pointer(Malloc(sizeof(initializerRecord))); - iPtr^.next := variable^.iPtr; - variable^.iPtr := iPtr; - iPtr^.isConstant := isConstant; - iPtr^.count := 1; - iPtr^.bitdisp := bitdisp; - iPtr^.bitsize := bitsize; - iPtr^.isStructOrUnion := false; - end; {if} - if variable^.storage in [external,global,private] then begin + if isStatic then begin Error(41); errorFound := true; end; {else} iPtr^.isConstant := false; iPtr^.iTree := initializerTree; - iPtr^.bitdisp := bitdisp; - iPtr^.bitsize := bitsize; + 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: boolean); + main, nestedDesignator: boolean); { initialize one level of the type } { } @@ -2370,113 +2384,30 @@ var { 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 - bitCount: integer; {# of bits in a union} + 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 Fill (count: longint; tp: typePtr); - - { fill in unspecified space in an initialized array with 0 } - { } - { parameters: } - { count - ^ elements of this type to create } - { tp - ptr to type of elements to create } - - var - i: longint; {loop variable} - iPtr: initializerPtr; {for creating an initializer entry} - tk: tokenPtr; {expression record} - ip: identPtr; {pointer to next field in a structure} - - begin {Fill} -{ writeln('Fill tp^.kind = ', ord(tp^.kind):1, '; count = ', count:1); {debug} - InitializeBitField; {if needed, do the bit field} - if tp^.kind = arrayType then - - {fill an array} - Fill(count*tp^.elements ,tp^.aType) - else if tp^.kind = structType then begin - - {fill a structure} - if variable^.storage in [external,global,private] then - Fill(count * tp^.size, sCharPtr) - else begin - i := count; - while i <> 0 do begin - ip := tp^.fieldList; - while ip <> nil do begin - if not ip^.anonMemberField then - Fill(1, ip^.iType); - ip := ip^.next; - end; {while} - i := i-1; - end; {while} - end; {else} - end {else if} - else if tp^.kind = unionType then begin - - {fill a union} - if variable^.storage in [external,global,private] then - Fill(count * tp^.size, sCharPtr) - else - Fill(count, tp^.fieldList^.iType); - end {else if} - else - - {fill a single value} - while count <> 0 do begin - iPtr := pointer(Calloc(sizeof(initializerRecord))); - iPtr^.next := variable^.iPtr; - variable^.iPtr := iPtr; - iPtr^.isConstant := variable^.storage in [external,global,private]; - {iPtr^.bitdisp := 0;} - {iPtr^.bitsize := 0;} - {iPtr^.isStructOrUnion := false;} - if iPtr^.isConstant then begin - if tp^.kind = scalarType then - iPtr^.itype := tp^.baseType - else if tp^.kind = pointertype then begin - iPtr^.itype := cgULong; - {iPtr^.iVal := 0;} - end {else if} - else begin - iPtr^.itype := cgWord; - Error(47); - errorFound := true; - end; {else} - end {if} - 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; - end; {else} - if count < 16384 then begin - iPtr^.count := long(count).lsw; - count := 0; - end {if} - else begin - iPtr^.count := 16384; - count := count-16384; - end; {else} - end; {while} - end; {Fill} procedure RecomputeSizes (tp: typePtr); @@ -2501,98 +2432,173 @@ var braces := true; end; {if} - {handle arrays} 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 string constants} - if token.kind = stringConst then + {handle arrays initialized with a string constant} + if (token.kind = stringConst) and (kind = scalarType) then begin stringElementType := StringType(token.prefix)^.aType; - if (token.kind = stringConst) and (kind = scalarType) and - (((ktp^.baseType in [cgByte,cgUByte]) - and (stringElementType = charPtr)) - or CompTypes(ktp,stringElementType)) 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^.next := variable^.iPtr; - variable^.iPtr := iPtr; - iPtr^.count := 1; - iPtr^.bitdisp := 0; - iPtr^.bitsize := 0; - iPtr^.isStructOrUnion := false; - if (variable^.storage in [external,global,private]) then begin - iPtr^.isConstant := true; - iPtr^.itype := cgString; - iPtr^.sval := token.sval; - count := tp^.elements - stringLength; - if count > 0 then - Fill(count, stringElementType) - 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); + 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} - end {if} - else begin - iPtr^.isConstant := false; - new(ep); - iPtr^.iTree := ep; - ep^.next := nil; - ep^.left := nil; - ep^.middle := nil; - ep^.right := nil; - ep^.token := token; - end; {else} - end; {with} - NextToken; - end {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} - else if kind in + 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 - InitializeTerm(ktp, 0, 0, false); - count := count+1; - if count <> maxCount then begin - if token.kind = commach then begin - NextToken; - done := token.kind = rbracech; + 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 - done := true; - end {if} + 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) or (count = maxCount); - if maxCount <> 0 then begin - count := maxCount-count; - if count <> 0 then {if there weren't enough initializers...} - Fill(count,ktp); { fill in the blank spots} - end {if} - else begin - tp^.elements := count; {set the array size} - RecomputeSizes(variable^.itype); - end; {else} + 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 @@ -2603,44 +2609,115 @@ var {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 - count := tp^.size; ip := tp^.fieldList; - bitCount := 0; + maxDisp := disp; lSuppressMacroExpansions := suppressMacroExpansions; - while (ip <> nil) and (ip^.itype^.size > 0) do begin + 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); - if token.kind = rbracech then begin {initialize this field to 0} - suppressMacroExpansions := true; {inhibit token echo} - PutBackToken(token, false); - PutBackToken(token, false); - token.kind := intconst; - token.class := intConstant; - token.ival := 0; - PutBackToken(token, false); - token.kind := lbracech; - token.class := reservedSymbol; + 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} - if ip^.bitSize = 0 then - if bitCount > 0 then begin - InitializeBitField; - bitCount := (bitCount+7) div 8; - count := count-bitCount; - bitCount := 0; - end; {if} - InitializeTerm(ip^.itype, ip^.bitsize, ip^.bitdisp, false); - if ip^.bitSize <> 0 then begin - bitCount := bitCount + ip^.bitSize; - if bitCount > maxBitField then begin - count := count - (maxBitField div 8); - bitCount := ip^.bitSize; - end; {if} - end {if} - else begin - count := count-ip^.itype^.size; - end; {else} -{ writeln('Initializer: ', ip^.bitsize:10, ip^.bitdisp:10, bitCount:10); {debug} + InitializeTerm(ip^.itype, ip^.bitsize, ip^.bitdisp, false, + hasNestedDesignator); + if disp > maxDisp then + maxDisp := disp; if kind = unionType then ip := nil else begin @@ -2648,26 +2725,34 @@ var 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 - if ip <> nil then - NextToken; + 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} - if bitCount > 0 then begin - InitializeBitField; - bitCount := (bitCount+7) div 8; - count := count-bitCount; - bitCount := 0; +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} - if count > 0 then - if variable^.storage in [external,global,private] then - Fill(count, sCharPtr); suppressMacroExpansions := lSuppressMacroExpansions; end {if} - else {struct/union assignment initializer} - GetInitializerValue(tp, bitsize, bitdisp); + else begin {struct/union assignment initializer} + Error(47); + errorFound := true; + end; {else} end {else if} {handle single-valued types} @@ -2678,7 +2763,7 @@ var 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; @@ -2695,19 +2780,20 @@ var end; {InitializeTerm} begin {Initializer} -bitcount := 0; {set up for bit fields} -bitvalue := 0; +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 := (variable^.storage in [external,global,private]) - or useGlobalPool; +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); {do the initialization} +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; @@ -2718,6 +2804,12 @@ while iPtr <> nil do begin 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} @@ -2797,7 +2889,11 @@ var 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} @@ -2827,16 +2923,14 @@ var tfl: identPtr; {for traversing field list} begin {AddField} - if variable^.name^ <> '~anonymous' then begin - 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} - end; {if} + 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; @@ -2878,7 +2972,10 @@ var and ((structsy in fieldDeclSpecifiers.declarationModifiers) or (unionsy in fieldDeclSpecifiers.declarationModifiers)) then begin - variable := NewSymbol(@'~anonymous', tPtr, ident, + 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} @@ -4314,7 +4411,7 @@ case statementList^.kind of NextToken; suppressMacroExpansions := lSuppressMacroExpansions; nToken := token; - PutBackToken(nToken, false); + PutBackToken(nToken, false, false); token := lToken; if nToken.kind <> colonch then DoDeclaration(false) @@ -4369,39 +4466,29 @@ procedure AutoInit {variable: identPtr; line: longint; { isCompoundLiteral - initializing a compound literal? } var - count: integer; {initializer counter} 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 Initialize (id: identPtr; disp: longint; itype: typePtr); + procedure InitializeOneElement; - { initialize a variable } - { } - { parameters: } - { id - pointer to the identifier } - { disp - disp past the identifier to initialize } - { itype - type of the variable to initialize } + { initialize (part of) a variable using the initializer iPtr } { } { variables: } + { variable - the variable to initialize } { count - number of times to re-use the initializer } - { ip - pointer to the initializer record to use } + { iPtr - pointer to the initializer record to use } - label 1,2; + label 1,2,3,4; var + count: integer; {initializer counter} + disp: longint; {displacement to initialize at} elements: longint; {# array elements} - fp: identPtr; {for tracing field lists} + itype: typePtr; {the type being initialized} size: integer; {fill size} - union: boolean; {are we doing a union?} - startDisp,endDisp: longint; {disp at start/end of struct/union} - - {bit field manipulation} - {----------------------} - bitcount: integer; {# if bits so far} - bitsize,bitdisp: integer; {defines size, location of a bit field} {assignment conversion} {---------------------} @@ -4415,38 +4502,13 @@ var { Load the address of the operand } begin {LoadAddress} - if id^.storage = stackFrame then - Gen2(pc_lda, id^.lln, ord(disp)) + if variable^.storage = stackFrame then + Gen2(pc_lda, variable^.lln, ord(disp)) else Error(57); end; {LoadAddress} - function ZeroFill (elements: longint; itype: typePtr; - count: integer; iPtr: initializerPtr): boolean; - - { See if an array can be zero filled } - { } - { parameters: } - { elements - elements in the array } - { itype - type of each array element } - { count - remaining initializer repetitions } - { iPtr - initializer record } - - begin {ZeroFill} - ZeroFill := false; - if not iPtr^.isConstant then - if itype^.kind in [scalarType,enumType] then - if count >= elements then - with iPtr^.itree^ do - if token.kind = intconst then - if token.ival = 0 then - {don't call ~ZERO for very small arrays} - if elements * itype^.size > 10 then - ZeroFill := true; - end; {ZeroFill} - - procedure AddOperation; { Deal with a new initializer expression in a compound } @@ -4468,7 +4530,10 @@ var end; {AddOperation} - begin {Initialize} + begin {InitializeOneElement} + disp := iPtr^.disp; + count := iPtr^.count; +3: itype := iPtr^.iType; while itype^.kind = definedType do itype := itype^.dType; case itype^.kind of @@ -4496,6 +4561,27 @@ var 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 @@ -4554,136 +4640,40 @@ var Gen0t(pc_stk, cgULong); Gen1t(pc_ldc, ord(elements), cgWord); Gen0t(pc_stk, cgWord); - Gen0t(pc_bno, cgULong); + Gen0t(pc_bno, cgWord); Gen1tName(pc_cup, -1, cgVoid, @'~ZERO'); if isCompoundLiteral then AddOperation; end; {if} - iPtr := iPtr^.next; - goto 1; end; {if} - itype := itype^.atype; - if ZeroFill(elements, itype, count, iPtr) then begin - if itype^.kind = enumType then - size := cgWordSize - else - size := TypeSize(itype^.baseType); - size := size * long(elements).lsw; - LoadAddress; - Gen0t(pc_stk, cgULong); - Gen1t(pc_ldc, size, cgWord); - Gen0t(pc_stk, cgWord); - Gen0t(pc_bno, cgULong); - Gen1tName(pc_cup, -1, cgVoid, @'~ZERO'); - if isCompoundLiteral then - AddOperation; - disp := disp + size; - count := count - long(elements).lsw; - if count = 0 then begin - iPtr := iPtr^.next; - if iPtr <> nil then - count := iPtr^.count; - end; {if} - end {if} - else begin - while elements <> 0 do begin - Initialize(id, disp, itype); - if itype^.kind in [scalarType,pointerType,enumType] then begin - count := count-1; - if count = 0 then begin - iPtr := iPtr^.next; - if iPtr <> nil then - count := iPtr^.count; - end; {if} - end; {if} - disp := disp+itype^.size; - elements := elements-1; - end; {while} - end; {else} 1: end; structType,unionType: begin - startDisp := disp; - endDisp := disp + itype^.size; - if iPtr^.isStructOrUnion then begin - LoadAddress; {load the destination address} - GenerateCode(iptr^.iTree); {load the struct address} + 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} - else begin - union := itype^.kind = unionType; - fp := itype^.fieldList; - while fp <> nil do begin - itype := fp^.itype; - disp := startDisp + fp^.disp; - bitdisp := fp^.bitdisp; - bitsize := fp^.bitsize; -{ writeln('Initialize: disp = ', disp:3, '; fp^. Disp = ', fp^.disp:3, 'itype^.size = ', itype^.size:1); {debug} -{ writeln(' bitDisp = ', bitDisp:3, '; fp^.bitDisp = ', fp^.bitDisp:3); {debug} -{ writeln(' bitSize = ', bitSize:3, '; fp^.bitSize = ', fp^.bitSize:3); {debug} - Initialize(id, disp, itype); - if bitsize = 0 then begin - if bitcount <> 0 then begin - bitcount := 0; - end {if} - else if fp^.bitSize <> 0 then begin - bitcount := 8; - while (fp <> nil) and (bitcount > 0) do begin - bitcount := bitcount - fp^.bitSize; - if bitcount > 0 then - if fp^.next <> nil then - if fp^.next^.bitSize <> 0 then - fp := fp^.next - else - bitcount := 0; - end; {while} - bitcount := 0; - end; {else if} - end {if} - else if fp^.bitSize = 0 then begin - bitsize := 0; - end {else if} - else begin - bitcount := bitsize + bitdisp; - end; {else} - if itype^.kind in [scalarType,pointerType,enumType] then begin - count := count-1; - if count = 0 then begin - iPtr := iPtr^.next; - if iPtr <> nil then begin - count := iPtr^.count; - bitsize := iPtr^.bitsize; - bitdisp := iPtr^.bitdisp; - end; {if} - end; {if} - end; {if} - if union then - fp := nil - else begin - fp := fp^.next; - while (fp <> nil) and fp^.anonMemberField do - fp := fp^.next; - end; {else} - end; {while} - end; {else} - disp := endDisp; - end; + 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} - end; {Initialize} + if count <> 1 then begin + count := count - 1; + disp := disp + itype^.size; + goto 3; + end; {if} +4: + end; {InitializeOneElement} begin {AutoInit} iPtr := variable^.iPtr; -count := iPtr^.count; if isCompoundLiteral then begin treeCount := 0; codeCount := 0; @@ -4697,7 +4687,10 @@ if variable^.class <> staticsy then begin if (statementList <> nil) and not statementList^.doingDeclaration then if lineNumber <> 0 then RecordLineNumber(line); - Initialize(variable, 0, variable^.itype); + while iPtr <> nil do begin + InitializeOneElement; + iPtr := iPtr^.next; + end; {while} end; {if} if isCompoundLiteral then begin while treeCount > 1 do begin @@ -4753,9 +4746,8 @@ iPtr := pointer(GCalloc(sizeof(initializerRecord))); iPtr^.count := 1; {iPtr^.bitdisp := 0;} {iPtr^.bitsize := 0;} -{iPtr^.isStructOrUnion := false;} iPtr^.isConstant := true; -iPtr^.itype := cgString; +iPtr^.basetype := cgString; iPtr^.sval := sval; id^.iPtr := iPtr; @@ -4822,6 +4814,7 @@ 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.} diff --git a/Scanner.pas b/Scanner.pas index 00176c6..951c107 100644 --- a/Scanner.pas +++ b/Scanner.pas @@ -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 diff --git a/Symbol.asm b/Symbol.asm index d01c3cf..03c5317 100644 --- a/Symbol.asm +++ b/Symbol.asm @@ -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 diff --git a/Symbol.pas b/Symbol.pas index 6197519..ab69c14 100644 --- a/Symbol.pas +++ b/Symbol.pas @@ -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} diff --git a/Tests/Conformance/DOIT3 b/Tests/Conformance/DOIT3 index aab0864..7bd9246 100644 --- a/Tests/Conformance/DOIT3 +++ b/Tests/Conformance/DOIT3 @@ -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 diff --git a/Tests/Conformance/c11anonsu.c b/Tests/Conformance/c11anonsu.c index 9ba786d..42df0ca 100644 --- a/Tests/Conformance/c11anonsu.c +++ b/Tests/Conformance/c11anonsu.c @@ -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; diff --git a/Tests/Conformance/c99bool.c b/Tests/Conformance/c99bool.c index 78d6e76..8492cfd 100644 --- a/Tests/Conformance/c99bool.c +++ b/Tests/Conformance/c99bool.c @@ -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; diff --git a/Tests/Conformance/c99desinit.c b/Tests/Conformance/c99desinit.c new file mode 100644 index 0000000..4033b6b --- /dev/null +++ b/Tests/Conformance/c99desinit.c @@ -0,0 +1,208 @@ +/* + * Test of designated initializers (C99). + */ + +#include +#include +#include + +#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"); +} diff --git a/cc.notes b/cc.notes index 4ec4255..225f627 100644 --- a/cc.notes +++ b/cc.notes @@ -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.