ORCA-C/Symbol.Print
Stephen Heumann b16210a50b Record volatile and restrict qualifiers in types.
These are needed to correctly distinguish pointer types in _Generic. They should also be used for type compatibility checks in other contexts, but currently are not.

This also fixes a couple small problems related to type qualifiers:
*restrict was not allowed to appear after * in type-names
*volatile status was not properly recorded in sym files

Here is an example of using _Generic to distinguish pointer types based on the qualifiers of the pointed-to type:

#include <stdio.h>

#define f(e) _Generic((e),\
        int * restrict *: 1,\
        int * volatile const *: 2,\
        int **: 3,\
        default: 0)

#define g(e) _Generic((e),\
        int *: 1,\
        const int *: 2,\
        volatile int *: 3,\
        default: 0)

int main(void) {
        int * restrict * p1;
        int * volatile const * p2;
        int * const * p3;

        // should print "1 2 0 1"
        printf("%i %i %i %i\n", f(p1), f(p2), f(p3), f((int * restrict *)0));

        int *q1;
        const int *q2;
        volatile int *q3;
        const volatile int *q4;

        // should print "1 2 3 0"
        printf("%i %i %i %i\n", g(q1), g(q2), g(q3), g(q4));
}

Here is an example of a problem resulting from volatile not being recorded in sym files (if a sym file was present, the read of x was lifted out of the loop):

#pragma optimize -1
static volatile int x;
#include <stdio.h>
int main(void) {
        int y;
        for (unsigned i = 0; i < 100; i++) {
                y = x*2 + 7;
        }
}
2021-08-30 18:19:58 -05:00

108 lines
3.0 KiB
Plaintext

procedure PrintOneSymbol {ip: identPtr};
{ Print a symbol }
{ }
{ Parameters: }
{ ip - identifier to print }
procedure PrintClass (class: tokenEnum);
{ Print the class of a symbol }
{ }
{ Parameters: }
{ class - class of the symbol }
begin {PrintClass}
case class of
autosy: write('auto');
externsy: write('extern');
ident: write('ident');
otherwise: write(ord(class):1);
end; {case}
end; {PrintClass}
procedure PrintType (tp: typePtr);
{ Print a type }
{ }
{ Parameters: }
{ tp - type pointer }
begin {PrintType}
with tp^ do begin
write(' ', size:1, ' byte ');
if tqConst in qualifiers then
write('constant ');
if tqVolatile in qualifiers then
write('volatile ');
if tqRestrict in qualifiers then
write('restricted ');
case kind of
scalarType : writeln('scalar');
arrayType : begin
writeln(elements: 1, ' element array of');
PrintType(aType);
end;
pointerType : begin
writeln(' pointer to');
PrintType(pType);
end;
functionType: begin
writeln(' function returning');
PrintType(fType);
end;
enumConst : writeln('enumeration (', eval: 1, ')');
enumType : writeln('enum type');
definedType : begin
writeln('defined type of');
PrintType(dType);
end;
structType : writeln('struct: ', ord4(tp):1);
unionType : writeln('union');
end; {case}
end; {with}
end; {PrintType}
begin {PrintOneSymbol}
with ip^ do begin
writeln; {start with a blank line}
write(name^, {write id info}
': isForwardDeclared = ', isForwardDeclared,
'; class = ');
PrintClass(class);
writeln;
PrintType(iType); {print type info}
end; {with}
end; {PrintOneSymbol}
procedure PrintTable {sym: symbolTablePtr};
{ print a symbol table }
{ }
{ parameters: }
{ sym - symbol table to print }
var
i: integer; {loop variable}
ip: identPtr; {current symbol}
begin {PrintTable}
if sym <> nil then begin
writeln; {write header}
writeln('Symbols:');
writeln('========');
for i := 0 to hashSize do begin {loop over all hash buckets}
ip := sym^.buckets[i]; {trace through all symbols in this bucket}
while ip <> nil do begin
PrintOneSymbol(ip); {print a symbol}
ip := ip^.next; {next symbol}
end; {while}
end; {for}
end; {if}
end; {PrintTable}