Commit Graph

73 Commits

Author SHA1 Message Date
Stephen Heumann
7f3ba768cd Allow pointer arithmetic using long long values.
This converts them to 32-bit values before doing computations, which is (more than) sufficient for address calculations on the 65816. Trying to compute an address outside the legal range is undefined behavior, and does not necessarily "wrap around" in a predictable way.
2021-02-04 22:05:02 -06:00
Stephen Heumann
fc3bd32e65 Add long long support for a couple lint checks. 2021-02-04 17:53:37 -06:00
Stephen Heumann
d2fb8cc27e Add long long support for the ! operator. 2021-02-04 17:53:10 -06:00
Stephen Heumann
5e5434987b Give an error when trying to evaluate constant expressions with long long operands. 2021-02-04 14:56:15 -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
10cf6e446d Enable automatic comparison with 0 for long longs.
This allows them to be used in if statements and as controlling expressions for loops.
2021-02-04 12:39:27 -06:00
Stephen Heumann
a59a2427fd Add some support for ++/-- on long long values.
Some more complex cases require pc_ind, which is not implemented yet.
2021-02-04 12:35:28 -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
807a143e51 Implement 64-bit addition and subtraction. 2021-01-30 23:31:18 -06:00
Stephen Heumann
2e44c36c59 Implement unary negation and bitwise complement for 64-bit types. 2021-01-30 13:49:06 -06:00
Stephen Heumann
abb0fa0fc1 Implement bitwise and/or/xor for 64-bit types.
This introduces three new intermediate codes for these operations.
2021-01-30 00:25:15 -06:00
Stephen Heumann
8b12b7b734 Handle (unsigned) long long in the front-end code for binary conversions.
There is not yet code generation support for the conversion opcodes (pc_cnv/pc_cnn).
2021-01-29 23:25:21 -06:00
Stephen Heumann
b1d4d8d668 Give errors for certain invalid compound assignment expressions.
The following example shows cases that were erroneously permitted before:

int main(void) {
        int i, *p;
        i *= p;
        i <<= 5.0;
        i <<= (void)1;
}
2021-01-29 12:49:28 -06:00
Stephen Heumann
f2a66a524a Fix several issues with evaluation of the ++ and -- operators.
These would generally not work correctly on bit-fields, or on floating-point values that were in a structure or were accessed via a pointer.

The below program is an example that would demonstrate problems:

#include <stdio.h>

int main(void) {
        struct {
                signed int i:7;
                unsigned long int j:6;
                _Bool b:1;
                double d;
        } s = {-10, -20, 0, 5.0};

        double d = 70.0, *dp = &d;

        printf("%i\n", (int)s.i++);
        printf("%i\n", (int)s.i--);
        printf("%i\n", (int)++s.i);
        printf("%i\n", (int)--s.i);
        printf("%i\n", (int)s.i);

        printf("%i\n", (int)s.j++);
        printf("%i\n", (int)s.j--);
        printf("%i\n", (int)++s.j);
        printf("%i\n", (int)--s.j);
        printf("%i\n", (int)s.j);

        printf("%i\n", s.b++);
        printf("%i\n", s.b--);
        printf("%i\n", ++s.b);
        printf("%i\n", --s.b);
        printf("%i\n", s.b);

        printf("%f\n", s.d++);
        printf("%f\n", s.d--);
        printf("%f\n", ++s.d);
        printf("%f\n", --s.d);
        printf("%f\n", s.d);

        printf("%f\n", (*dp)++);
        printf("%f\n", (*dp)--);
        printf("%f\n", ++*dp);
        printf("%f\n", --*dp);
        printf("%f\n", *dp);
}
2021-01-26 12:31:54 -06:00
Stephen Heumann
52132db18a Implement the _Bool type from C99. 2021-01-25 21:22:58 -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
41cb879936 In preprocessor expressions, always replace identifiers with constant 0.
This was not happening for declared identifiers (variables and functions) or for enum constants, as demonstrated in the following example:

enum {a,b,c};
#if b
#error "bad b"
#endif

int x = 0;
#if x
#error "bad x"
#endif
2020-02-05 18:23:45 -06:00
Stephen Heumann
3676e685b9 Disallow dereferencing of non-pointer types in l-values.
This fixes #67.
2020-01-29 22:52:10 -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
6e89dc5883 Give a basic error message for use of _Generic. 2020-01-19 18:03:21 -06:00
Stephen Heumann
8341f71ffc Initial phase of support for new C99/C11 type syntax.
_Bool, _Complex, _Imaginary, _Atomic, restrict, and _Alignas are now recognized in types, but all except restrict and _Alignas will give an error saying they are not supported.

This also introduces uniform definitions of the syntactic classes of tokens that can be used in declaration specifiers and related constructs (currently used in some places but not yet in others).
2020-01-12 15:43:30 -06:00
Stephen Heumann
a9fb1ba482 Move TypeName to be a top-level method in Parser.pas.
As of C11, type names are now used as part of the declaration syntax (in _Alignas and _Atomic specifiers), in addition to their uses in expressions. Moving the TypeName method will allow it to be called when processing declarations.
2020-01-06 20:18:58 -06:00
Stephen Heumann
3121a465f1 Implement the _Alignof operator (from C11).
In ORCA/C, the alignment of all object types is 1.
2020-01-06 20:17:29 -06:00
Stephen Heumann
cb063afa47 Set expressionType to a default value when LoadAddress encounters an error.
This can occur in cases such as trying to assign to a non-l-value.

This patch ensures consistent handling of errors and prevents null pointer dereferences.
2019-12-23 20:36:27 -06:00
Stephen Heumann
91094e9292 Correctly increment/decrement pointers to large (>=64KiB) types.
Previously, the logic for this was incorrect and would lead to a null pointer dereference in the compiler. In most cases the generated code would not actually change the pointer.

The following program demonstrates the issue:

#include <stdio.h>
#pragma memorymodel 1
typedef char bigarray[0x20000];
bigarray big[5];
int main(void) {
        bigarray *p = big;
        p++;
        printf("%p %p\n", (void*)big, (void*)p);
}
2019-12-23 19:59:18 -06:00
Stephen Heumann
13a14d9389 When an operand is missing, synthesize a "0" operand for post-error processing.
This ensures consistent behavior and avoids null-pointer dereferences in some cases.
2019-12-23 18:57:17 -06:00
Stephen Heumann
7f79b49c3a Set expressionType to a default value when an expression parsing error is encountered.
This ensures consistent handling of errors and prevents possible null pointer dereferences.
2019-12-23 14:03:46 -06:00
Stephen Heumann
17de3914ad Fix problem with using values of enum constants in integer constant expressions.
This could cause spurious errors, or in some cases bad code generation.

The following example illustrates the problem:

#include <stdio.h>

enum {A,B,C};

/* arr was treated as having a size of 1, rather than 3 */
char arr[(int)C+1] = {1,2,3}; /* incorrectly gave an error for initializer */

int main(void) {
        static int i = (int)C+1; /* incorrectly gave an error */

        printf("%zu\n", sizeof(arr));
        printf("%i\n", (int)C+1); /* OK */
        printf("%i\n", i);
}
2019-03-31 18:40:14 -05:00
Kelvin Sherlock
618188c6b2 floating point division by 0.0 is well defined and occasionally used to generate +/- infinite values. 2019-03-10 16:47:18 -04:00
Stephen Heumann
1a2e4772cd Don't generate scalar load operations with bogus types.
This could occur with some operations on function parameters declared with array types, in some cases leading to compiler errors.

Fixes #61.
2019-01-27 11:53:52 -06:00
Stephen Heumann
2d43074d5a Make % operator give proper remainders even if one or both operands are negative.
Per the C standards, the % operator should give a remainder after division, such that (a/b)*b + a%b equals a (provided that a/b is representable). As such, the operation of % is defined for cases where either or both of the operands are negative. Since division truncates toward 0, a%b should give a negative result (or 0) in cases where a is negative.

Previously, the % operator was essentially behaving like the "mod" operator in Pascal, which is equivalent for positive operands but not if either operand is negative. It would generally give incorrect results in those cases, or in some cases give compile-time or run-time errors.

This patch addresses both 16-bit and 32-bit signed computations at run time, and operations in constant expressions. The approach at run time is to call existing division routines, which return the correct remainder, except always as a positive number. The generated code checks the sign of the first operand, and if it is negative negates the remainder.

The code generated is somewhat large (especially for the 32-bit case), so it might be sensible to put it in a library function and call that, but for now it's just generated in-line. This avoids introducing a dependency on a new library function, so the generated code remains compatible with older versions of ORCALib (e.g. the GNO one).

Fixes #10.
2018-09-10 18:21:17 -05:00
Stephen Heumann
6f8546c964 Report errors for use of inappropriate types as operands to various operators.
Mainly, this detects errors in several cases where a pointer could inappropriately be used where an arithmetic type was expected. In some cases, other types (e.g. structs) could be used too.
2018-09-06 21:21:23 -05:00
Stephen Heumann
dc1b0aa29f Add lint flag to check for several forms of undefined behavior in computations.
This adds lint bit 5 (a value of 32), which currently enables checking for the following conditions:

*Integer overflow from arithmetic in constant expressions (currently only of type int).
*Invalid constant shift counts (negative, or >= the width of the type)
*Division by (constant) zero.

These (mainly the first two) can be indicative of code that was designed for larger type sizes and needs changes to support 16-bit int.
2018-09-05 23:48:35 -05:00
Stephen Heumann
b2785dfe0e Treat constant expressions cast to char as promoting to int, not unsigned int.
The following program demonstrates the problem:

#include <stdio.h>
int main(void) {
    long l = (char)1 - (char)5;
    printf("%li\n", l);  /* should print -4 */
}
2018-09-05 12:49:02 -05:00
Stephen Heumann
bfe4416623 Fix some cases where decay of array types to pointer types was not handled correctly.
Specifically:
*The result of pointer arithmetic (or equivalent operations like &a[i]) always has pointer type.
*Array types decay to integer types in the context of comparison operations, so it is legal to compare two differently-sized arrays with the same element type.

The following program (partially derived from a csmith-generated test case) illustrates the issues:

int main(void) {
    int a[2], b[10];
    if (a == b) ; /* legal */
    if (&a[1] != &b[0]) ; /* legal */
    return sizeof(&b[1]); /* Should be sizeof(int*), i.e. 4 on GS */
}
2018-03-29 19:41:32 -05:00
Stephen Heumann
7266b1d613 Properly support use of const structs and unions in assignments and as function arguments.
Here's an example that shows the issues (derived from a csmith-generated test case):

struct S {
   unsigned f;
};

void f1(struct S p) {
    printf("%u\n", p.f);
}

int main(void) {
    const struct S l = {123};
    struct S s;

    f1(l);

    s = l;
    printf("%u\n", s.f);
}
2018-03-25 20:56:15 -05:00
Kelvin Sherlock
6c1ccc5c0d Squashed commit of the following:
commit 4265329097538640e9e21202f1b141bcd42a44f3
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date:   Fri Mar 23 21:45:32 2018 -0400

    indent to match standard indent.

commit 783518fbeb01d2df43ef2083d3341004c05e4e2e
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date:   Fri Mar 23 20:21:15 2018 -0400

    clean up the typenames

commit 29b627ecf5ca9b8a143761f85a1807a6ca35ddd9
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date:   Fri Mar 23 20:18:04 2018 -0400

    enable feature_hh, warn about %n with non-int modifier.

commit fc4ac8129e3772c4eda36658e344ec475938369c
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date:   Fri Mar 23 15:13:47 2018 -0400

    warn thar %lc, %ls, etc are unsupported.

commit 7e6b433ba0552f7e52f0f034d398e9195c764326
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date:   Fri Mar 23 13:36:25 2018 -0400

    warn about hh/ll modifier (if not supported)

commit 1943c9979d0013f9f38045ec04a962fbf0269f31
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date:   Fri Mar 23 11:42:41 2018 -0400

    use error facilities for format errors.

commit 7811168f56dca1387055574ba8d32638da2fad96
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date:   Thu Mar 22 15:34:21 2018 -0400

    add feature flags to disable c99 enhancements until orca lib is updated.

commit c2149cc5953155cfc3c3b4d0483cd25fb946b055
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date:   Thu Mar 22 08:59:10 2018 -0400

    Add printf/scanf format checking [WIP]

    This parses out the xprintf / xscanf format string and compares it with the function arguments.

    enabled via #pragma lint 16.
2018-03-23 21:51:27 -04:00
Stephen Heumann
4a7644e0b5 Don't allocate stack space for varargs stack repair unless it's needed.
If there are no varargs calls (and nothing else that saves stack positions), then space doesn't need to be allocated for the saved stack position. This can also lead to more efficient prolog/epilog code for small functions.
2018-01-13 20:02:43 -06:00
Stephen Heumann
ba09d5ee6d Fix issues with addressing/pointer arithmetic using unsigned indexes that generate a displacement of 32K to 64K.
These cases should now always work when using an expression of type unsigned as the index. They will work in some cases but not others when using an int as the index: making those cases work consistently would require more extensive changes and/or a speed hit, so I haven't done it for now.

Note that this now uses an "unsigned multiply" operation for all 16-bit index computations. This should actually work even when the index is a negative signed value, because it will wind up producing (the low-order 16 bits of) the right answer. The signed multiply, on the other hand, generally does not produce the low-order 16 bits of the right answer in cases where it overflows.

The following program is an example that was miscompiled (both with and without optimization):

int c[20000] = {3};

int main(void) {
    int *p;
    unsigned i = 17000;

    p = c + 17000u;
    return *(p-i); /* should return 3 */
}
2017-11-12 17:21:05 -06:00
Stephen Heumann
e780043007 When doing arithmetic/indexing on pointers to one-byte types, don't generate code to multiply by one.
This could already be optimized out by the peephole optimizer, but it's bad enough code that it really shouldn't be generated even when not using that optimization.
2017-10-29 20:25:43 -05:00
Stephen Heumann
8d31481182 Report errors for illegal pointer arithmetic operations.
These include arithmetic on pointers to incomplete types or functions, as well as subtraction of pointers to incompatible types.
2017-10-29 20:21:36 -05:00
Stephen Heumann
afe3e9586b Fix bad code generation in some cases where compound assignment operators are used to update a value through a pointer.
This could occur because a temporary location might be used both in the l-value and r-value computations, but the final assignment code assumed it still had the value from the l-value computation.

The following function demonstrates this problem (*ip is not updated, and *p is trashed):

int badinc(char **p, int *ip)
{
    *ip += *(*p)++;
}
2017-10-21 20:36:21 -05:00
Stephen Heumann
4cff395745 Move some code from the blank segment to named load segments.
This frees up some space in the blank segment for more static data.
2017-10-21 20:36:21 -05:00
Stephen Heumann
280f67e846 Make || and && operators in constant expressions yield results of type int.
Previously the result type was based on the operand types (using the arithmetic conversions), which is incorrect. The following program illustrates the issue:

#include <stdio.h>
int main(void)
{
    /* should print "1 0 2 2" */
    printf("%i %i %lu %lu\n", 0L || 2, 0.0 && 2,
           sizeof(1L || 5), sizeof(1.0 && 2.5));
}
2017-10-21 20:36:21 -05:00
Stephen Heumann
40bed0a93e Allow application of the unary ! operator to floating constants.
The following is an example of a program that requires this:

#include <stdio.h>
int main(void)
{
    int true = !0.0;
    int false = !1.1;
    printf("%i %i\n", true, false);
}
2017-10-21 20:36:21 -05:00
Stephen Heumann
cd9a424499 Remove bogus code for applying unary &, ++, and -- operators to integer constants.
This is already precluded from executing by an earlier test, so there is no functional change.
2017-10-21 20:36:21 -05:00
Stephen Heumann
7ab1875b54 Evaluate preprocessor expressions using 32-bit long/unsigned long types.
This is as required by C90. C99 and later require (u)intmax_t, which must be 64-bit or greater.

The following example shows problems with the previous behavior:

#if (30000 + 30000 == 60000) && (1 << 16 == 0x10000)
int main(void) {}
#else
#error "preprocessor error"
#endif
2017-10-21 20:36:21 -05:00
Stephen Heumann
60df52c268 Disallow the application of the unary * operator to integer constants.
It must only be applied to pointer types.
2017-10-21 20:36:21 -05:00