Commit Graph

201 Commits

Author SHA1 Message Date
Stephen Heumann b6d3dfb075 Designated initializers for arrays, part 1.
This can parse designated initializers for arrays, but does not create proper initializer records for them.
2022-11-26 15:22:58 -06:00
Stephen Heumann 740468f75c Avoid generating invalid .sym files if header ends with a partial prototyped function decl.
This could happen because the nested calls to DoDeclaration for the parameters would set inhibitHeader to false.
2022-11-26 14:20:58 -06:00
Stephen Heumann 2bf3862e5d Avoid generating invalid .sym files if header ends with a partial declaration.
The part of the declaration within the header could be ignored on subsequent compilations using the .sym file, which could lead to errors or misbehavior.

(This also applies to headers that end in the middle of a _Static_assert(...) or segment directive.)
2022-11-26 00:18:57 -06:00
Stephen Heumann 5500833180 Record which anon struct/union an anonymous member field came from.
This is preparatory to supporting designated initializers.

Any struct/union type with an anonymous member now forces .sym file generation to end, since we do not have a scheme for serializing this information in a .sym file. It would be possible to do so, but for now we just avoid this situation for simplicity.
2022-11-25 22:32:59 -06:00
Stephen Heumann 3f450bdb80 Support "inline" function definitions without static or extern.
This is a minimal implementation that does not actually inline anything, but it is intended to implement the semantics defined by the C99 and later standards.

One complication is that a declaration that appears somewhere after the function body may create an external definition for a function that appeared to be an inline definition when it was defined. To support this while preserving ORCA/C's general one-pass compilation strategy, we generate code even for inline definitions, but treat them as private and add the prefix "~inline~" to the name. If they are "un-inlined" based on a later declaration, we generate a stub with external linkage that just jumps to the apparently-inline function.
2022-11-19 23:04:22 -06:00
Stephen Heumann d96a5f86f9 Do not force function type info to be in the global pool.
This should no longer be necessary, because functions are not forced to be in the global symbol table.
2022-11-07 21:41:30 -06:00
Stephen Heumann 202ed3b514 Require a declarator after comma in declarations.
This gives an error for code like "int x,;".
2022-11-07 20:00:23 -06:00
Stephen Heumann 82b2944eb8 Give an error if a function is defined multiple times. 2022-11-06 20:54:53 -06:00
Stephen Heumann d3ba8b5551 Rework handling of scopes created for function declarators.
This is preparatory to other changes.
2022-11-05 21:13:44 -05:00
Stephen Heumann 986a283540 Simplify some code in DoDeclaration and improve error detection.
This detects errors in the following cases that were previously missed:

* A function declaration and definition being part of the same overall declaration, e.g.:
void f(void), g(void) {}

* A function declaration (not definition) with no declaration specifiers, e.g.:
f(void);

(Function definitions with no declaration specifiers continue to be accepted by default, consistent with C90 rules.)
2022-11-05 20:20:04 -05:00
Stephen Heumann 7d6b732d23 Simplify some declaration-processing logic.
This should not cause any functional change.
2022-11-01 18:43:44 -05:00
Stephen Heumann f31b5ea1e6 Allow "extern inline" functions.
A function declared "inline" with an explicit "extern" storage class has the same semantics as if "inline" was omitted. (It is not an inline definition as defined in the C standards.) The "inline" specifier suggests that the function should be inlined, but it is legal to just ignore it, as we already do for "static inline" functions.

Also add a test for the inline function specifier.
2022-10-29 19:43:57 -05:00
Stephen Heumann f54d0e1854 Require that main have no function specifiers.
This enforces a constraint in the C standards (for a hosted environment).
2022-10-29 18:36:51 -05:00
Stephen Heumann 65ec29ee3e Use 32-bit representation for line numbers.
C99 and later specify that line numbers set via #line can be up to 2147483647, so they need to be represented as (at least) a 32-bit value.
2022-10-22 21:46:12 -05:00
Stephen Heumann bdf212ec6b Remove support for separate . . . as equivalent to a ... token.
The scanner has been updated so that ... should always get recognized as a single token, so this is no longer necessary as a workaround. Any code that actually uses separate . . .  is non-standard and will need to be changed.
2022-10-19 18:14:14 -05:00
Stephen Heumann 6d8ca42734 Parse the _Thread_local storage-class specifier.
This does not really do anything, because ORCA/C does not support multithreading, but the C11 and later standards indicate it should be allowed anyway.
2022-10-18 21:01:26 -05:00
Stephen Heumann afe40c0f67 Prevent spurious errors about structs containing function pointers.
If a struct contained a function pointer with a prototyped parameter list, processing the parameters could reset the declaredTagOrEnumConst flag, potentially leading to a spurious error, as in this example:

struct S {
	int (*f)(int);
};

This also gives a better error for structs declared as containing functions.
2022-10-16 19:57:14 -05:00
Stephen Heumann a864954353 Use "declarator expected" error messages when appropriate.
Previously, some of these cases would report "identifier expected."
2022-10-16 18:45:06 -05:00
Stephen Heumann 99e268e3b9 Implement support for anonymous structures and unions (C11).
Note that this implementation allows anonymous structures and unions to participate in initialization. That is, you can have a braced initializer list corresponding to an anonymous structure or union. Also, anonymous structures within unions follow the initialization rules for structures (and vice versa).

I think the better interpretation of the standard text is that anonymous structures and unions cannot participate in initialization as such, and instead their members are treated as members of the containing structure or union for purposes of initialization. However, all other compilers I am aware of allow anonymous structures and unions to participate in initialization, so I have implemented it that way too.
2022-10-16 18:44:19 -05:00
Stephen Heumann b8b7dc2c2b Remove code that treats # as an illegal character in most places.
C90 had constraints requiring # and ## tokens to only appear in preprocessing directives, but C99 and later removed those constraints, so this code is no longer necessary when targeting current languages versions. (It would be necessary in a "strict C90" mode, if that was ever implemented.)

The main practical effect of this is that # and ## tokens can be passed as parameters to macros, provided the macro either ignores or stringizes that parameter. # and ## tokens still have no role in the grammar of the C language after preprocessing, so they will be an unexpected token and produce some kind of error if they appear anywhere.

This also contains a change to ensure that a line containing one or more illegal characters (e.g. $) and then a # is not treated as a preprocessing directive.
2022-10-13 18:35:26 -05:00
Stephen Heumann 4fe9c90942 Parse ... as a single punctuator token.
This accords with its definition in the C standards. For the time being, the old form of three separate tokens is still accepted too, because the ... token may not be scanned correctly in the obscure case where there is a line continuation between the second and third dots.

One observable effect of this is that there are no longer spaces between the dots in #pragma expand output.
2022-10-10 18:06:01 -05:00
Stephen Heumann f263066f61 Give an error for declarations that do not declare anything.
This enforces the constraint from C17 section 6.7 p2 that declarations "shall declare at least a declarator (other than the parameters of a function or the members of a structure or union), a tag, or the members of an enumeration."

Somewhat relaxed rules are used for enums in the default loose type checking mode, similar to what GCC and Clang do.
2022-10-09 22:03:06 -05:00
Stephen Heumann 995ded07a5 Always treat "struct T;" as declaring the tag within the current scope.
A declaration of this exact form always declares the tag T within the current scope, and as such makes this "struct T" a distinct type from any other "struct T" type in an outer scope. (Similarly for unions.)

See C17 section 6.7.2.3 p7 (and corresponding places in all other C standards).

Here is an example of a program affected by this:

struct S {char a;};
int main(void) {
        struct S;
        struct S *sp;
        struct S {long b;} s;
        sp = &s;
        sp->b = sizeof(*sp);
        return s.b;
}
2022-10-04 18:45:11 -05:00
Stephen Heumann 3cea478e5e Clarify a comment. 2022-10-02 22:05:05 -05:00
Stephen Heumann 53baef0fb3 Make isPascal variable local to DoDeclaration.
This avoids the need to save/restore it elsewhere.
2022-10-02 22:04:46 -05:00
Stephen Heumann 1fa3ec8fdd Eliminate global variables for declaration specifiers.
They are now represented in local structures instead. This keeps the representation of declaration specifiers together and eliminates the need for awkward and error-prone code to save and restore the global variables.
2022-10-01 21:28:16 -05:00
Stephen Heumann 05ecf5eef3 Add option to use the declared type for float/double/comp params.
This differs from the usual ORCA/C behavior of treating all floating-point parameters as extended. With the option enabled, they will still be passed in the extended format, but will be converted to their declared type at the start of the function. This is needed for strict standards conformance, because you should be able to take the address of a parameter and get a usable pointer to its declared type. The difference in types can also affect the behavior of _Generic expressions.

The implementation of this is based on ORCA/Pascal, which already did the same thing (unconditionally) with real/double/comp parameters.
2022-09-18 21:16:46 -05:00
Stephen Heumann 6e3fca8b82 Implement strict type checking for enum types.
If strict type checking is enabled, this will prohibit redefinition of enums, like:

enum E {a,b,c};
enum E {x,y,z};

It also prohibits use of an "enum E" type specifier if the enum has not been previously declared (with its constants).

These things were historically supported by ORCA/C, but they are prohibited by constraints in section 6.7.2.3 of C99 and later. (The C90 wording was different and less clear, but I think they were not intended to be valid there either.)
2022-07-19 20:35:44 -05:00
Stephen Heumann 6d07043783 Do not treat uses of enum types from outer scopes as redeclarations.
This affects code like the following:

enum E {a,b,c};
int main(void) {
        enum E e;
        struct E {int x;}; /* or: enum E {x,y,z}; */
}

The line "enum E e;" should refer to the enum type declared in the outer scope, but not redeclare it in the inner scope. Therefore, a subsequent struct, union, or enum declaration using the same tag in the same scope is acceptable.
2022-07-18 21:34:29 -05:00
Stephen Heumann fd54fd70d0 Remove some unnecessary/duplicate code.
This mainly comments out statements that zero out data that was already set to zero by a preceding Calloc call.
2022-07-18 21:19:44 -05:00
Stephen Heumann c36bf9bf0a Ignore storage class when creating enum tag symbols.
This avoids strangeness where an enum tag declared within a typedef declaration would act like a typedef. For example, the following would compile without error:

typedef enum E {a,b,c} T;
E e;
2022-07-18 18:37:26 -05:00
Stephen Heumann 2cbcdc736c Allow the same identifier to be used as a typedef and an enum tag.
This should be allowed (because they are in separate name spaces), but was not.

This affected code like the following:

typedef int T;
enum T {a,b,c};
2022-07-18 18:33:54 -05:00
Stephen Heumann 5e20e02d06 Add a function to make a pointer type.
This allows us to refactor out code that was doing this in several places.
2022-06-19 17:55:08 -05:00
Stephen Heumann 58849607a1 Use cgPointerSize for size of pointers in various places.
This makes no practical difference when targeting the GS, but it better documents what the relevant size is.
2022-06-18 19:30:20 -05:00
Stephen Heumann 3c2b492618 Add support for compound literals within functions.
The basic approach is to generate a single expression tree containing the code for the initialization plus the reference to the compound literal (or its address). The various subexpressions are joined together with pc_bno pcodes, similar to the code generated for the comma operator. The initializer expressions are placed in a balanced binary tree, so that it is not excessively deep.

Note: Common subexpression elimination has poor performance for very large trees. This is not specific to compound literals, but compound literals for relatively large arrays can run into this issue. It will eventually complete and generate a correct program, but it may be quite slow. To avoid this, turn off CSE.
2022-06-08 21:34:12 -05:00
Stephen Heumann 2a9ec8fc43 Explicitly terminate PCH generation if there is an initialized variable.
Initialized variables have always been one of the things that stops PCH generation, but previously this was only detected when trying to write out the symbol records at the point of a later #include. On a subsequent compile using the sym file, nothing would recognize that PCH generation had stopped for this reason, so the PCH code would recognize the later #include as a potential opportunity to extend the sym file, and therefore would delete it to force regeneration next time. This led to the sym file being deleted and regenerated on alternate compiles, so its full benefit was not realized.

There is code in Header.pas to abort PCH generation if an initialized symbol is found. That is probably superfluous after this change, but it has been left in place for now.
2022-02-19 14:22:25 -06:00
Stephen Heumann 3893db1346 Make sure #pragma expand is properly applied in all cases.
There were various places where the flag for macro expansions was saved, set to false, and then later restored. If #pragma expand was used within those areas, it would not be properly applied. Here is an example showing that problem:

void f(void
#pragma expand 1
) {}

This could also affect some uses of #pragma expand within precompiled headers, e.g.:

#pragma expand 1
#include "a.h"
#undef foobar
#include "b.h"
...

Also, add a note saying that code in precompiled headers will not be expanded. (This has always been the case, but was not clearly documented.)
2022-02-15 20:50:02 -06:00
Stephen Heumann 785a6997de Record source file changes within a function as part of debug info.
This affects functions whose body spans multiple files due to includes, or is treated as doing so due to #line directives. ORCA/C will now generate a COP 6 instruction to record each source file change, allowing debuggers to properly track the flow of execution across files.
2022-02-05 18:32:11 -06:00
Stephen Heumann e36503508a Allow more forms of address expressions in static initializers.
There were several forms that should be permitted but were not, such as &"str"[1], &*"str", &*a (where a is an array), and &*f (where f is a function).

This fixes #15 and also certain other cases illustrated in the following example:

char a[10];
int main(void);
static char *s1 = &"string"[1];
static char *s2 = &*"string";
static char *s3 = &*a;
static int (*f2)(void)=&*main;
2022-01-29 21:59:25 -06:00
Stephen Heumann 8eda03436a Preserve qualifiers when changing float/double/comp parameters to extended.
Changing the type is still non-standard, but at least this allows us to detect and report write-to-const errors.
2022-01-17 18:26:28 -06:00
Stephen Heumann 6f0b94bb7c Allow the pascal qualifier to appear anywhere types are used.
This is necessary to allow declarations of pascal-qualified function pointers as members of a structure, among other things.

Note that the behavior for "pascal" now differs from that for the standard function specifiers, which have more restrictive rules for where they can be used. This is justified by the fact that the "pascal" qualifier is allowed and meaningful for function pointer types, so it should be able to appear anywhere they can.

This fixes #28.
2022-01-13 20:11:43 -06:00
Stephen Heumann b1bc840ec8 Reverse order of parameters for pascal function pointer types.
The parameters of the underlying function type were not being reversed when applying the "pascal" qualifier to a function pointer type. This resulted in the parameters not being in the expected order when a call was made using such a function pointer. This could result in spurious errors in some cases or inappropriate parameter conversions in others.

This fixes #75.
2022-01-13 19:38:22 -06:00
Stephen Heumann 3acf5844c2 Save and restore type spec when evaluating expressions in a type name.
Failing to do this could allow the type spec to be overwritten if the expression contained another type name within it (e.g. a cast). This could cause the wrong type to be computed, which could lead to incorrect behavior for constructs that use type names, e.g. sizeof.

Here is an example program that demonstrated the problem:

int main(void) {
        return sizeof(short[(long)50]);
}
2022-01-12 21:53:23 -06:00
Stephen Heumann 3b35a65b1d Give an error if a function pointer is redefined as a function.
This gives an error for code like the following, which was previously allowed:

void (*p)(int);
void p(int i) {}

Note that the opposite order still does not give a compiler error, but does give linker errors. Making sure we give a compiler error for all similar cases would require larger changes, but this patch at least catches some erroneous cases that were previously being allowed.
2022-01-12 18:31:32 -06:00
Stephen Heumann 61a382de0b Report parameter type errors the same way with and without strict type checks.
They were being reported as "type conflict" by default, but as "duplicate symbol" if strict checks were used.
2022-01-12 18:31:04 -06:00
Stephen Heumann b5b276d0f4 Do not give a spurious error for redeclarations of a pascal function.
This could occur with strict type checking on, because the parameter types were compared at a point where they had been reversed for the original declaration but not for the subsequent one.

Here is an example that would give an error:

#pragma ignore 24
extern pascal void func(int, long);
extern pascal void func(int, long);
2022-01-12 18:30:28 -06:00
Stephen Heumann 1fb1762458 Fix bug in initialization of auto arrays of strings.
When initializing (e.g.) an array of arrays of char, a string literal would be taken as an initializer for the outer array rather than for an inner array, so not all elements would be initialized properly. This was a bug introduced in commit 222c34a385.

This bug affected the C4.6.4.2.CC test case, and the following reduced version:

#include <stdio.h>
#include <string.h>
int main (void) {
   char ch2[][20] = {"for all good people", "to come to the aid "};
   if (strcmp(ch2[1], "to come to the aid "))
       puts("Failed");
}
2021-12-27 08:22:19 -06:00
Stephen Heumann 7ac3fe6424 Allow string constants in initializers for arrays of char*.
For example, declarations like the following should be accepted:

char *p[] = {"abc", "def"};

This previously worked, but it was broken by commit 5871820e0c.
2021-11-12 21:17:37 -06:00
Stephen Heumann a6359f67e0 Adjust parameters with typedef'd array types to have pointer types.
Parameters declared directly with array types were already adjusted to pointer types in commit 5b953e2db0, but this code is needed for the remaining case where a typedef'd array type is used.

With these changes, 'array' parameters are treated for all purposes as really having pointer types, which is what the standards call for. This affects at least their size as reported by sizeof and the debugging information generated for them.
2021-11-07 18:54:27 -06:00
Stephen Heumann 906f9f6312 Get rid of a variable that was not really used for anything. 2021-11-05 22:40:27 -05:00
Stephen Heumann 5b953e2db0 Allow 'static' and type qualifiers in parameter array declarators (C99).
This has the side effect of treating most parameters declared as arrays as actually having pointer types. This affects the value returned by sizeof, among other things. The new behavior is correct under the C standards; however, it does not yet apply when using a typedef'd array type.
2021-11-02 22:17:55 -05:00
Stephen Heumann a20d69a211 Revise variable argument handling to better comply with standards.
In the new implementation, variable arguments are not removed until the end of the function. This allows variable argument processing to be restarted, and it prevents the addresses of local variables from changing in the middle of the function. The requirement to turn off stack repair code around varargs functions is also removed.

This fixes #58.
2021-10-23 22:36:34 -05:00
Stephen Heumann 772043241c Force stack checking and repair off for internal calls to ~ZERO.
This can make unoptimized initialization code a bit smaller and faster.
2021-10-19 22:17:09 -05:00
Stephen Heumann daede21819 Fix bug with assembly-language functions that return structs/unions. 2021-10-19 18:12:46 -05:00
Stephen Heumann f567d60429 Allow bit-fields in unions.
All versions of standard C allow this, but ORCA/C previously did not.
2021-10-18 21:48:18 -05:00
Stephen Heumann 692ebaba85 Structs or arrays may not contain structs with a flexible array member.
We previously ignored this, but it is a constraint violation under the C standards, so it should be reported as an error.

GCC and Clang allow this as an extension, as we were effectively doing previously. We will follow the standards for now, but if there was demand for such an extension in ORCA/C, it could be re-introduced subject to a #pragma ignore flag.
2021-10-17 22:22:42 -05:00
Stephen Heumann a888206111 Simplify address calculation for auto initializers.
This simplifies the code in the compiler, and also generates better code when not using optimization.
2021-10-11 22:10:38 -05:00
Stephen Heumann 5871820e0c Support UTF-8/16/32 string literals and character constants (C11).
These have u8, u, or U prefixes, respectively. The types char16_t and char32_t (defined in <uchar.h>) are used for UTF-16 and UTF-32 code points.
2021-10-11 20:54:37 -05:00
Stephen Heumann 222c34a385 Fix bug in initialization using string literals with embedded nulls.
When using such a string literal to initialize an array with automatic storage duration, the bytes after the first null would be set to 0, rather than the values from the string literal.

Here is an example program showing the problem:

#include <stdio.h>
int main(void) {
        char s[] = "a\0b";
        puts(s+2);
}
2021-10-11 19:55:09 -05:00
Stephen Heumann 7ae830ae7e Initial support for compound literals.
Compound literals outside of functions should work at this point.

Compound literals inside of functions are not fully implemented, so they are disabled for now. (There is some code to support them, but the code to actually initialize them at the appropriate time is not written yet.)
2021-09-16 18:34:55 -05:00
Stephen Heumann 894baac94f Give an error if assigning to a whole struct or union that has a const member.
Such structs or unions are not modifiable lvalues, so they cannot be assigned to as a whole. Any non-const fields can be assigned to individually.
2021-09-11 18:12:58 -05:00
Stephen Heumann 2614f10ced Make the actual return type of a function be the unqualified version of the type specified.
This is a change that was introduced in C17. However, it actually keeps things closer to ORCA/C's historical behavior, which generally ignored qualifiers in return types.
2021-09-10 18:09:50 -05:00
Stephen Heumann 2f7e71cd24 Treat the fields of const structs as const-qualified.
This causes an error to be produced when trying to assign to these fields, which was being allowed before. It is also necessary for correct behavior of _Generic in some cases.
2021-09-09 18:39:19 -05:00
Stephen Heumann 00cc05a6a1 Move type qualifiers from array types to their element types.
This behavior is specified by the C standards. It can come up when declaring an array using a typedef'd array type and a qualifier.

This is necessary for correct behavior of _Generic, as well as to give an error if code tries to write to const arrays declared in this way.

Here is an example showing these issues:

#define f(e) _Generic((e), int *: 1, const int *:2, default: 0)
int main(void) {
        typedef int A[2][3];
        const A a = {{4, 5, 6}, {7, 8, 9}};
        _Static_assert(f(&a[0][0]) == 2, "qualifier error"); // OK
        a[1][1] = 42; // error
}
2021-08-30 18:30:05 -05:00
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
Stephen Heumann fbdbad1f45 Report an error for certain large unsigned enumeration constants.
Enumeration constants must have values representable as an int (i.e. 16-bit signed values, in ORCA/C), but errors were not being reported if code tried to use the values 0xFFFF8000 to 0xFFFFFFFF. This problem could also affect certain larger values of type unsigned long long. The issue stemmed from not properly accounting for whether the constant expression had a signed or unsigned type.

This sample code demonstrated the problem:

enum E {
        a = 0xFFFFFFFF,
        b = 0xFFFF8000,
        y = 0x7FFFFFFFFFFFFFFFull,
        z = 0x8000000000000000
};
2021-07-07 20:06:05 -05:00
Stephen Heumann 979852be3c Use the right types for constants cast to character types.
These were previously treated as having type int. This resulted in incorrect results from sizeof, and would also be a problem for _Generic if it was implemented.

Note that this creates a token kind of "charconst", but this is not the kind for character constants in the source code. Those have type int, so their kind is intconst. The new kinds of "tokens" are created only through casts of constant expressions.
2021-03-07 13:38:21 -06:00
Stephen Heumann f9f79983f8 Implement the standard pragmas, in particular FENV_ACCESS.
The FENV_ACCESS pragma is now implemented. It causes floating-point operations to be evaluated at run time to the maximum extent possible, so that they can affect and be affected by the floating-point environment. It also disables optimizations that might evaluate floating-point operations at compile time or move them around calls to the <fenv.h> functions.

The FP_CONTRACT and CX_LIMITED_RANGE pragmas are also recognized, but they have no effect. (FP_CONTRACT relates to "contracting" floating-point expressions in a way that ORCA/C does not do, and CX_LIMITED_RANGE relates to complex arithmetic, which ORCA/C does not support.)
2021-03-06 00:57:13 -06:00
Stephen Heumann 77d66ab699 Support the predefined identifier __func__ (from C99).
This gives the name of the current function, as if the following definition appeared at the beginning of the function body:

static const char __func__[] = "function-name";
2021-03-02 22:28:28 -06:00
Stephen Heumann cf463ff155 Support switch statements using long long expressions. 2021-02-17 19:41:46 -06:00
Stephen Heumann 32ae4c2e17 Allow unsigned constants in "address+constant" constant expressions.
This affected initializers like the following:

static int a[50];
static int *ip = &a[0] + 2U;

Also, introduce some basic range checks for calculations that are obviously outside the 65816's address space.
2021-02-13 15:36:54 -06:00
Stephen Heumann 47fdd9e370 Implement support for functions returning (unsigned) long long.
These use a new calling convention specific to functions returning these types. When such functions are called, the caller must set the X register to the address within bank 0 that the return value is to be saved to. The function is then responsible for saving it there before returning to the caller.

Currently, the calling code always makes space for the return value on the stack and sets X to point to that. (As an optimization, it would be possible to have the return value written directly to a local variable on the direct page, with no change needed to the function being called, but that has not yet been implemented.)
2021-02-05 23:25:46 -06:00
Stephen Heumann 2408c9602c Make expressionValue a saturating approximation of the true value for long long expressions.
This gives sensible behavior for several things in the parser, e.g. where all negative values or all very large values should be disallowed.
2021-02-04 12:44:44 -06:00
Stephen Heumann 168a06b7bf Add support for emitting 64-bit constants in statically-initialized data. 2021-02-04 02:17:10 -06:00
Stephen Heumann 793f0a57cc Initial support for constants with long long types.
Currently, the actual values they can have are still constrained to the 32-bit range. Also, there are some bits of functionality (e.g. for initializers) that are not implemented yet.
2021-02-03 23:11:23 -06:00
Stephen Heumann 085cd7eb1b Initial code to recognize 'long long' as a type. 2021-01-29 22:27:11 -06:00
Stephen Heumann 52132db18a Implement the _Bool type from C99. 2021-01-25 21:22:58 -06:00
Stephen Heumann 5014fb97f9 Make 32-bit int (with #pragma unix 1) a distinct type from long. 2021-01-24 13:31:12 -06:00
Stephen Heumann c0b2b44cad Add a new representation of C basic types and use it for type checking.
This allows us to distinguish int from short, etc.
2020-03-01 15:00:02 -06:00
Stephen Heumann c84c4d9c5c Check for non-void functions that execute to the end without returning a value.
This generalizes the heuristic approach for checking whether _Noreturn functions could execute to the end of the function, extending it to apply to any function with a non-void return type. These checks use the same #pragma lint bit but give different messages depending on the situation.
2020-02-02 13:50:15 -06:00
Stephen Heumann bc951b6735 Make lint report some more cases where noreturn functions may return.
This uses a heuristic that may produce both false positives and false negatives, but any false positives should reflect extraneous code at the end of the function that is not actually reachable.
2020-01-30 17:35:15 -06:00
Stephen Heumann a4abc5e421 Recognize enum type specifiers as such.
They were erroneously triggering the "type specifier missing" lint warning.
2020-01-29 21:15:33 -06:00
Stephen Heumann 80c513bbf2 Add a lint flag for checking if _Noreturn functions may return.
Currently, this only flags return statements, not cases where they may execute to the end of the function. (Whether the function will actually return is not decidable in general, although it may be in special cases).
2020-01-29 19:26:45 -06:00
Stephen Heumann 4fd642abb4 Add lint check for return with no value in a non-void function.
This is disallowed in C99 and later.
2020-01-29 18:50:45 -06:00
Stephen Heumann a9f5fb13d8 Introduce a new #pragma lint bit for syntax that C99 disallows.
This currently checks for:
*Calls to undefined functions (same as bit 0)
*Parameters not declared in K&R-style function definitions
*Declarations or type names with no type specifiers (includes but is broader than the condition checked by bit 1)
2020-01-29 18:33:19 -06:00
Stephen Heumann ffe6c4e924 Spellcheck comments throughout the code.
There are no non-comment changes.
2020-01-29 17:09:52 -06:00
Stephen Heumann a72b611272 Make unnamed bit-fields take up space.
They should take up the same space as a named bit-field of the same width.

This fixes #60.
2020-01-28 22:54:40 -06:00
Stephen Heumann f5cd1e3e3a Recognize designated initializers enough to give an error and skip them.
Previously, the designated initializer syntax could confuse the parser enough to cause null pointer dereferences. This avoids that, and also gives a more meaningful error message to the user.
2020-01-28 12:48:09 -06:00
Stephen Heumann 9862500dee Give an error if a parameter in a function definition has an incomplete type.
In combination with earlier patches, this fixes #53.

Also, if the lint flag requiring explicit function types is set, then also require that K&R-style parameters be explicitly declared with types, rather than not being declared and defaulting to int. (This is a requirement in C99 and later.)
2020-01-20 12:43:01 -06:00
Stephen Heumann dd92585116 Give errors for most illegal uses of "restrict". 2020-01-19 17:31:20 -06:00
Stephen Heumann 49dea49cb8 Detect and give errors for various illegal uses of _Alignas. 2020-01-19 17:06:01 -06:00
Stephen Heumann a130e79929 Prohibit _Noreturn specifier on non-functions. 2020-01-19 14:57:28 -06:00
Stephen Heumann d10478967f Allow "restrict" in pointer declarators.
Valid uses of "restrict" should now be permitted, but invalid uses do not necessarily give errors (and it is not used for any kind of optimization).
2020-01-19 07:15:35 -06:00
Stephen Heumann b4232fd4ea Flag more appropriate errors about unexpected tokens in type names.
Previously, these would report "identifier expected"; now they correctly say "')' expected".

This introduces a new UnexpectedTokenError procedure that can be used more generally for cases where the expected token may differ based on context.
2020-01-18 16:43:25 -06:00
Stephen Heumann dbe330a7b1 Use centrally-defined token sets to recognize the beginning of declarations. 2020-01-18 15:21:27 -06:00
Stephen Heumann 0f3bb11d22 Remove special-case code for declarations with no declaration specifiers.
This can now be folded into the regular code path.
2020-01-18 15:21:24 -06:00
Stephen Heumann 08b4f8da3e Remove some unnecessary parameters and code.
These are not needed after the refactoring of declaration specifier processing.
2020-01-18 15:20:56 -06:00
Stephen Heumann df029ce06f Handle storage class specifiers in DeclarationSpecifiers.
_Thread_local is recognized but gives a "not supported" error. It could arguably be 'supported' trivially by saying the execution of an ORCA/C program is just one thread and so no special handling is needed, but that likely isn't what someone using it would expect.

There would be a possible issue if a "static" or "typedef" storage class specifier occurred after a type specifier that required memory to be allocated for it, because that memory conceptually might be in the local pool, but static objects are processed at the end of the translation unit, so their types need to stick around. In practice, this should not occur, because the local pool isn't currently used for much (in particular, not for statements or declarations in the body of a function). We give an error in case this somehow might occur.

In combination with preceding commits, this fixes #14. Declaration specifiers can now appear in any order, as required by the C standards.
2020-01-18 14:52:27 -06:00
Stephen Heumann fbe44e1852 Process function specifiers in DeclarationSpecifiers.
This includes both the standard ones (inline and _Noreturn) and the ORCA/C-specific ones (asm and pascal). They can now be freely mixed with other declaration specifiers.

Some errors related to function specifiers are not yet detected.
2020-01-15 07:28:44 -06:00
Stephen Heumann 84767f3340 Prevent output values of DeclarationSpecifiers from being corrupted by a recursive call to it.
This could happen in a declaration like "char _Alignas(long) c;", where typeSpec wound up specifying long rather than char.

Also, tweak error checks for _Alignas and _Atomic.
2020-01-12 17:15:25 -06:00