Compare commits

...

252 Commits

Author SHA1 Message Date
Stephen Heumann 69320cd4d8 Detect some erroneous numeric constants that were being allowed.
These include tokens like 0x, 0b, and 1.2LL.
2024-04-23 22:07:19 -05:00
Stephen Heumann 8278f7865a Support unconvertible preprocessing numbers.
These are tokens that follow the syntax for a preprocessing number, but not for an integer or floating constant after preprocessing. They are now allowed within the preprocessing phases of the compiler. They are not legal after preprocessing, but they may be used as operands of the # and ## preprocessor operators to produce legal tokens.
2024-04-23 21:39:14 -05:00
Stephen Heumann 6b7414384f Fix code generation bug for indirect load/store of 64-bit values.
The issue was that if a 64-bit value was being loaded via one pointer and stored via another, the load and store parts could both be using y for their indexing, but they would clash with each other, potentially leading to loads coming from the wrong place.

Here are some examples that illustrate the problem:

/* example 1 */
int main(void) {
        struct {
                char c[16];
                long long x;
        } s = {.x = 0x1234567890abcdef}, *sp = &s;
        long long ll, *llp = ≪
        *llp = sp->x;
        return ll != s.x; // should return 0
}

/* example 2 */
int main(void) {
        struct {
                char c[16];
                long long x;
        } s = {.x = 0x1234567890abcdef}, *sp = &s;
        long long ll, *llp = ≪
        unsigned i = 0;
        *llp = sp[i].x;
        return ll != s.x; // should return 0
}

/* example 3 */
int main(void) {
        long long x[2] = {0, 0x1234567890abcdef}, *xp = x;
        long long ll, *llp = ≪
        unsigned i = 1;
        *llp = xp[i];
        return ll != x[1]; // should return 0
}
2024-04-10 20:49:17 -05:00
Stephen Heumann 77e0b8fc59 Fix codegen error for some indirect accesses to 64-bit values.
The code was not properly adding in the offset of the 64-bit value from the pointed-to location, so the wrong memory location would be accessed. This affected indirect accesses to non-initial structure members, when used as operands to certain operations.

Here is an example showing the problem:

#include <stdio.h>

long long x = 123456;

struct S {
        long long a;
        long long b;
} s = {0, 123456};

int main(void) {
        struct S *sp = &s;

        if (sp->b != x) {
                puts("error");
        }
}
2024-04-03 21:04:47 -05:00
Stephen Heumann 50636bd28b Fix code generation for qualified struct or union function parameters.
They were not being properly recognized as structs/unions, so they were being passed by address rather than by value as they should be.

Here is an example affected by this:

struct S {int a,b,c,d;};

int f(struct S s) {
    return s.a + s.b + s.c + s.d;
}

int main(void) {
    const struct S s = {1,2,3,4};
    return f(s);
}
2024-04-01 20:37:51 -05:00
Stephen Heumann 83537fd3c7 Disable a peephole optimization that can produce bad code.
The optimization applies to code sequences like:
	dec abs
	lda abs
	beq ...
where the dec and lda were supposed to refer to the same location.

There were two problems with this optimization as written:
-It considered the dec and lda to refer to the same location even if they were actually references to different elements of the same array.
-It did not work in the case where the A register value was needed in subsequent code.

The first of these was already an issue in previous ORCA/C releases, as in the following example:

#pragma optimize -1
int x[2] = {0,0};
int main(void) {
        --x[0];
        if (x[1] != 0)
                return 123;
        return 0; /* should return 0 */
}

I do not believe the second problem was triggered by any code sequences generated in previous releases of ORCA/C, but it can be triggered after commit 4c402fc88, e.g. by the following example:

#pragma optimize -1
int x = 1;
int main(void) {
        int y = 123;
        --x;
        return x == 0; /* should return 1 */
}

Since the circumstances where this peephole optimization was triggered validly are pretty obscure, just disabling it should have a minimal impact on the generated code.
2024-03-17 21:31:18 -05:00
Stephen Heumann 81934109fc Fix issues with type names in the third expression of a for loop.
There were a couple issues here:
*If the type name contained a semicolon (for struct/union member declarations), a spurious error would be reported.
*Tags or enumeration constants declared in the type name should be in scope within the loop, but were not.

These both stemmed from the way the parser handled the third expression, which was to save the tokens from it and re-inject them at the end of the loop. To get the scope issues right, the expression really needs to be evaluated at the point where it occurs, so we now do that. To enable that while still placing the code at the end of the loop, a mechanism to remove and re-insert sections of generated code is introduced.

Here is an example illustrating the issues:

int main(void) {
        int i, j, x;
        for (i = 0; i < 123; i += sizeof(struct {int a;}))
                for (j = 0; j < 123; j += sizeof(enum E {A,B,C}))
                        x = i + j + A;
}
2024-03-13 22:09:25 -05:00
Stephen Heumann 72234a4f2b Generate better code for most unsigned 32-bit comparisons. 2024-03-10 21:24:33 -05:00
Stephen Heumann 36f766a662 Generate better code for comparisons against constant 1 or 2. 2024-03-06 21:57:27 -06:00
Stephen Heumann 4c402fc883 Generate better code for certain equality/inequality comparisons. 2024-03-06 21:18:50 -06:00
Stephen Heumann ca0147507b Generate slightly better code for logical negation. 2024-03-06 17:04:51 -06:00
Stephen Heumann 24c6e72a83 Simplify some conditional branches.
This affects certain places where code like the following could be generated:

	bCC lab2
lab1	brl ...
lab2 ...

If lab1 is no longer referenced due to previous optimizations, it can be removed. This then allows the bCC+brl combination to be shortened to a single conditional branch, if the target is close enough.

This introduces a flag for tracking and potentially removing labels that are only used as the target of one branch. This could be used more widely, but currently it is only used for the specific code sequences shown above. Using it in other places could potentially open up possibilities for invalid native-code optimizations that were previously blocked due to the presence of the label.
2024-03-05 22:20:34 -06:00
Stephen Heumann 0f18fa63b5 Optimize some additional cases of a branch to a branch.
This covers patterns like

	bCC lab
	???
	???
lab:	bra/brl ...

These can come up in the new code for 32-bit ||, but also in cases like "if (i > 0) ...".
2024-03-05 17:16:17 -06:00
Stephen Heumann 8f07ca5d6c Generate better code for && and || with 32-bit operands. 2024-03-05 17:09:21 -06:00
Stephen Heumann 60b472a99e Optimize generated code for some indexing ops in large memory model.
This generates slightly better code for indexing a global/static char array with a signed 16-bit index and a positive offset, e.g. a[i+1].

Here is an example that is affected:

#pragma memorymodel 1
#pragma optimize -1
char a[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
int main(int argc, char *argv[]) {
        return a[argc+2];
}
2024-03-04 19:38:39 -06:00
Stephen Heumann 995885540b Correct a comment. 2024-03-04 19:03:13 -06:00
Stephen Heumann 34c5be5cab Update readme files for version 2.2.1. 2024-02-28 20:11:13 -06:00
Stephen Heumann 75a928e273 Change division-by-zero tests to cases requiring a constant expression. 2024-02-27 13:06:45 -06:00
Stephen Heumann a545685ab4 Use more correct logic for expanding macros in macro parameters.
Specifically, this affects the case where a macro argument ends with the name of a function-like macro that takes 0 parameters. When that argument is initially expanded, the macro should not be expanded, even if there are parentheses within the macro that it is being passed to or the subsequent program code. This is the case because the C standards specify that "The argument’s preprocessing tokens are completely macro replaced before being substituted as if they formed the rest of the preprocessing file with no other preprocessing tokens being available." (The macro may still be expanded at a later stage, but that depends on other rules that determine whether the expansion is suppressed.) The logic for this was already present for the case of macros taking one or more argument; this extends it to apply to function-like macros taking zero arguments as well.

I'm not sure that this makes any practical difference while cycles of mutually-referential macros still aren't handled correctly (issue #48), but if that were fixed then there would be some cases that depend on this behavior.
2024-02-26 22:31:46 -06:00
Stephen Heumann ce94f4e2b6 Do not pass negative sizes to strncat or strncmp in tests.
These parameters are of type size_t, which is unsigned.
2024-02-24 18:57:50 -06:00
Stephen Heumann 84fdb5c975 Fix handling of empty macro arguments as ## operands.
Previously, there were a couple problems:

*If the parameter that was passed an empty argument appeared directly after the ##, the ## would permanently be removed from the macro record, affecting subsequent uses of the macro even if the argument was not empty.
*If the parameter that was passed an empty argument appeared between two ## operators, both would effectively be skipped, so the tokens to the left of the first ## and to the right of the second would not be combined.

This example illustrates both issues (not expected to compile; just check preprocessor output):

#pragma expand 1
#define x(a,b,c) a##b##c
x(1, ,3)
x(a,b,c)
2024-02-22 21:55:46 -06:00
Stephen Heumann d1847d40be Set numString properly for numeric tokens generated by ##.
Previously, it was not necessarily set correctly for the newly-generated token. This would result in incorrect behavior if that token was an operand to another ## operator, as in the following example:

#define x(a,b,c) a##b##c
x(1,2,3)
2024-02-22 21:42:05 -06:00
Stephen Heumann c671bb71a5 Document recent library bug fixes. 2024-02-22 21:20:33 -06:00
Stephen Heumann a646a03b5e Avoid possible errors when using postfix ++/-- on pointer expressions.
There was code that would attempt to use the cType field of the type record, but this is only valid for scalar types, not pointer types. In the case of a pointer type, the upper two bytes of the pointer would be interpreted as a cType value, and if they happened to have one of the values being tested for, incorrect intermediate code would be generated. The lower two bytes of the pointer would be used as a baseType value; this would most likely result in "compiler error" messages from the code generator, but might cause incorrect code generation with no errors if that value happened to correspond to a real baseType.

Code like the following might cause this error, although it only occurs if pointers have certain values and therefore depends on the memory layout at compile time:

void f(const int **p) {
    (*p)++;
}

This bug was introduced in commit f2a66a524a.
2024-02-09 20:45:14 -06:00
Stephen Heumann 7ca30d7784 Do not give a compile error for division of any integer constant by 0.
Division by zero produces undefined behavior if it is evaluated, but in general we cannot tell whether a given expression will actually be evaluated at run time, so we should not report this as a compile-time error.

We still report an error for division by zero in constant expressions that need to be evaluated at compile time. We also still produce a lint message about division by zero if the appropriate flag is enabled.
2024-02-02 20:03:34 -06:00
Stephen Heumann c9dc566c10 Update release notes. 2024-02-02 18:31:48 -06:00
Stephen Heumann 2ca4aba5c4 Correct a misspelled error code in <gsos.h>. 2024-01-18 17:55:41 -06:00
ksherlock d7cc9b5909
update gsbug.h prototypes and errors based on gsbug and niftylist (#86)
* update gsbug.h prototypes and errors based on gsbug and niftylist

* updates

* remove gsbug 1.7 development error codes
2024-01-18 17:51:22 -06:00
Kelvin Sherlock 586229e6eb #define should always use the global pool....
if a #define is within a function, it could use the local memory pool for string allocation (via Malloc in NextToken, line 5785) which can lead to a dangling memory reference when the macro is expanded.

void function(void) {

#define TEXT "abc"

static struct {
	char text[sizeof(TEXT)];
} template = { TEXT };

}
2024-01-15 22:05:32 -06:00
Stephen Heumann 0aee669746 Update version number for ORCA/C 2.2.1 development. 2024-01-15 21:47:00 -06:00
Stephen Heumann 25085f5b81 Update script for setting filetypes.
It now covers all the files in the repository.
2023-08-06 17:50:26 -05:00
Stephen Heumann 6905d8dced Add const qualifiers in some non-standard function declarations.
This makes their headers and their specifications in the manual consistent with their actual behavior. The const qualifiers in the headers may prevent errors when using strict type checking.
2023-07-30 10:33:47 -05:00
Stephen Heumann f815c1bda6 Small manual updates for ORCA/C 2.2.0 release.
This includes some corrections suggested by Andrew Roughan.
2023-07-28 22:20:13 -05:00
Stephen Heumann 5316b438d5 Remove a debug print statement in a test. 2023-07-22 18:03:01 -05:00
Stephen Heumann 4d8eaf93bc Update documentation for ORCA/C 2.2.0 release. 2023-07-20 14:14:07 -05:00
Stephen Heumann 7e5023844a Fix a test to account for scanf changes.
The scanf functions no longer accept strings with no digits in the significand part, or an "e" but no digits in the exponent part.
2023-07-19 20:41:07 -05:00
Stephen Heumann 1aa654628a Update ORCA/C version number to 2.2.0 final. 2023-07-16 22:51:16 -05:00
Stephen Heumann 9a56a50f5f Support FPE card auto-detection.
The second parameter of #pragma float is now optional, and if it missing or invalid then the FPE slot is auto-detected by the start-up code. This is done by calling the new ~InitFloat function in the FPE version of SysFloat.
2023-06-26 18:33:54 -05:00
Stephen Heumann adcab004df Update manual.
This covers recent changes to strtod, fscanf, and #pragma float, plus miscellaneous small edits.
2023-06-22 18:55:11 -05:00
Stephen Heumann 7188b4f418 Fix another test to account for recent stdio changes in SysFloat. 2023-06-19 18:35:15 -05:00
Stephen Heumann af3c8e1eea Optimize double stores to just use integer operations.
This is equivalent to an optimization already done for float.
2023-06-17 19:24:50 -05:00
Stephen Heumann 0021fd81bc #pragma float: Generate code in the .root file to set the FPE slot.
This allows valid FPE-using programs to be compiled using only #pragma float, with no changes needed to the code itself.

The slot-setting code is only generated if the slot is 1..7, and even then it can be overridden by calling setfpeslot(), so this should not cause compatibility problems for existing code.
2023-06-17 18:13:31 -05:00
Stephen Heumann 966da239ee Update release notes and tests to reflect recent SysFloat changes. 2023-06-16 20:46:01 -05:00
Stephen Heumann 5b294721f2 Document recent bug fixes in libraries. 2023-06-11 18:57:42 -05:00
Stephen Heumann 914e5972bd Change tests to account for recent stdio changes in SysFloat. 2023-06-11 18:56:35 -05:00
Stephen Heumann 79e83c3092 Update format checker to reflect that L length modifier now works in scanf. 2023-06-10 21:27:00 -05:00
Stephen Heumann e5c69670cd Add documentation and tests for strtod changes. 2023-06-08 20:46:42 -05:00
Stephen Heumann 509f09253f Document recent bug fixes in SysLib and SysFloat. 2023-06-08 19:07:20 -05:00
Stephen Heumann 05c9ea16c8 Update manual.
This includes documentation for lgamma, plus miscellaneous small edits.
2023-05-22 18:30:08 -05:00
Stephen Heumann 661c9c440d Add tests, documentation, and headers for lgamma(). 2023-05-21 18:30:15 -05:00
Stephen Heumann c8517eff87 Give an error for sizeof(bitfield).
This violates a constraint in the standards (C17 6.5.3.4 p1).
2023-05-07 18:28:31 -05:00
Stephen Heumann c2262929e9 Fix handling of #pragma float.
This was not getting recognized properly, because float is a keyword rather than an identifier.
2023-04-30 21:47:19 -05:00
Stephen Heumann 9d5360e844 Comment out some unused error messages. 2023-04-30 21:38:34 -05:00
Stephen Heumann 338bfdd908 Add const qualifier in c2pstr/p2cstr declarations.
This reflects their actual behavior and may prevent some errors when using strict type checking.
2023-04-30 21:37:16 -05:00
Stephen Heumann 118e326ac9 Miscellaneous small updates to release notes. 2023-04-30 21:36:23 -05:00
Stephen Heumann 938fa96503 Update the manual.
It now covers pretty much all the new features, as well as addressing the errata from the release notes and some other miscellaneous issues. The early chapters still need to be updated to refer to a hard disk installation, rather than being based on running it from floppies (which is no longer supported). I'm sure more proofreading and editing would also be beneficial.
2023-04-30 21:35:32 -05:00
Stephen Heumann 986fe9a65b Address issues in samples detected by new lint checks.
The only actual behavior change is in Ackermann.cc, which previously reported incorrectly high recursion depths for some calculations.
2023-04-23 19:35:16 -05:00
Stephen Heumann ab975b611c Add C samples.
These are the samples from ORCA/C 2.1.0, converted to LF line endings.
2023-04-23 18:34:34 -05:00
Stephen Heumann e123339a45 Add the manual.
This is the ORCA/C 2.0 manual from Opus ][, re-saved in the modern Microsoft Word format and adjusted to fix some formatting issues. In particular, the embedded images needed to be converted to formats that current versions of Word support. The result is very close to the original version, although the pagination winds up slightly different in some places.
2023-04-22 19:02:12 -05:00
Stephen Heumann 0274b0ba83 Document octal formatting bug fix. 2023-04-17 22:00:29 -05:00
Stephen Heumann 84401b4e97 Fix a test case to account for printf '-' flag overriding '0'. 2023-04-16 21:44:05 -05:00
Stephen Heumann 3a298ec341 Add documentation and tests for 'a'/'A' printf conversions. 2023-04-16 20:25:15 -05:00
Stephen Heumann 2974c1b4bb Document fprintf bug fix. 2023-04-16 18:58:38 -05:00
Stephen Heumann 9dad2b6186 Update displayed version number to mark this as a development version. 2023-04-16 14:29:02 -05:00
Stephen Heumann 5c96042423 Update ORCA/C version number to 2.2.0 B7.
Also tweak documentation wording in a couple places.
2023-04-06 18:53:34 -05:00
Stephen Heumann e5c7aebb3f Avoid spurious undefined variable errors for functions returning structs/unions.
When the lint check for undefined variables was enabled, a "lint: unused variable: @struct" would be produced for any function returning a struct or union, due to the special static variable that is created to hold the return value. That spurious lint message is now suppressed.
2023-04-06 18:52:45 -05:00
Stephen Heumann 20f9170343 Give errors for certain illegal initializers.
This prohibits initializers in "extern" declarations within a function, and in the parameter declarations of non-prototyped functions.

Here are examples illustrating these cases:

int main(void) {
        extern int i = 50;
}

void f(i)
int i = 60;
{
}
2023-04-06 12:49:26 -05:00
Stephen Heumann 4c903a5331 Remove a few unused variables. 2023-04-04 18:11:41 -05:00
Stephen Heumann 0b3f48157e Simplify code for writing out extended constants.
This removes the need for the CnvSX function, so it is removed.
2023-04-04 18:11:04 -05:00
Stephen Heumann ba57d51500 Add a correction about the debug check box in Prizm. 2023-04-02 22:12:48 -05:00
Stephen Heumann 74cec68dac Generate better code for some floating-point and long long constants.
We now recognize cases where the same value needs to be pushed for several consecutive words, so it is more efficient to load it into a register and push that rather than just using PEA instructions.
2023-04-02 19:39:03 -05:00
Stephen Heumann 4e5e622903 Do not use FX2X to copy floating-point values.
This is gratuitously slow, and may also cause a loss of precision under Golden Gate (depending on the host platform).
2023-04-02 16:34:53 -05:00
Stephen Heumann c678151bde Add tests and documentation for fma(). 2023-04-02 16:31:28 -05:00
Stephen Heumann a988ef60bc Document bug fix for functions run at exit in large memory model. 2023-03-28 22:11:38 -05:00
Stephen Heumann ae89e77bbe Remove some unused or write-only variables. 2023-03-24 19:49:55 -05:00
Stephen Heumann 7e860e60df Generate better code for pc_ixa in large memory model.
This improves the code for certain array indexing operations.
2023-03-23 18:41:16 -05:00
Stephen Heumann 2412ae0661 Prohibit static initializers referring to a non-static array element.
This covers code like the following:

int main(void) {
        auto int a[20];
        static int *p = &a[5];
}

Previously, this would compile without error, and then either give a linker error or be linked to refer to the global symbol "a" (if there was one).
2023-03-21 09:10:37 -05:00
Stephen Heumann 3a64c5b977 Generate better code for stack array indexing in large memory model.
Any stack-allocated array must be < 32KB, so we can use the same approach as in the small memory model to compute indexes for it (which is considerably more efficient than the large-memory-model code).
2023-03-20 17:56:44 -05:00
Stephen Heumann be291b2423 Show "Including ..." lines for all headers when using a sym file.
Previously, only the last header from a group of headers represented together would be listed.
2023-03-20 17:22:13 -05:00
Stephen Heumann cc36e9929f Remove some unused variables. 2023-03-20 11:12:48 -05:00
Stephen Heumann 3b6f73c277 Prohibit "typedef" in function definitions. 2023-03-19 20:16:36 -05:00
Stephen Heumann cbf32e5b71 Comment out an unused peephole optimization involving BVS.
The code generator never generates this code sequence (and did not do so even prior to the last commit), so having a peephole optimization for it is pointless.
2023-03-18 20:09:49 -05:00
Stephen Heumann a5eafe56af Generate more efficient code for 16-bit signed comparisons.
The new code is smaller and (in the common case where the subtraction does not overflow) faster. It takes advantage of the fact that in overflow cases the carry flag always gets set to the opposite of the sign bit of the result.
2023-03-18 20:05:56 -05:00
Stephen Heumann 137188ff4f Comment out an obsolete error message. 2023-03-17 19:47:30 -05:00
Stephen Heumann 1b7b198039 Remove unneeded extern declarations. 2023-03-17 18:14:19 -05:00
Stephen Heumann ea056f1fbb Avoid listing the first line twice when a pre-include file is used. 2023-03-15 20:43:43 -05:00
Stephen Heumann 344bf6999f Do not give an error for files that end with an #endif with no newline.
This was a problem introduced by commit 30a04d42c5.
2023-03-15 20:11:39 -05:00
Stephen Heumann 49deff3c86 Generate more efficient code for certain conditionals.
This will change a "jump if true" to "jump if false" (or vice versa) and logically negate the condition in certain cases where that generates better code.

An assembly peephole optimization for certain "branch to branch" instructions is also added. (Certain conditionals could generate these.)
2023-03-14 21:32:20 -05:00
Stephen Heumann 7c8ec41148 Optimize some assembly code sequences that can occur for array access.
Here is an example that benefits from the new optimizations:

#pragma optimize 7
void f(char *a, unsigned i, unsigned n) {
        a[i] = (a[i] & 0xF0) | n;
}
2023-03-09 17:53:45 -06:00
Stephen Heumann 30a04d42c5 Require preprocessor conditionals to be balanced in each include file.
This is required by the standard syntax for a preprocessing file (C17 6.10), which must be a "group" (or empty).
2023-03-07 19:00:13 -06:00
Stephen Heumann 27c68b41d5 Do not inhibit sym file generation if there is a segment directive before an #include.
This affected code like the following, causing stdio.h not to be represented in the sym file:

segment "S";
#include <stdio.h>
int main(void) {}
2023-03-07 18:34:36 -06:00
Stephen Heumann c6ba1e1c1c Use bit operations rather than division in a few places.
This should produce faster code.
2023-03-06 22:52:52 -06:00
Stephen Heumann 3ac55a64bf Use an improved hash function for symbol tables.
The hash algorithm has been modified to include a rotate at each step. This should improve the quality of hashes and reduce the number of collisions. However, probably the more important change for performance is to do the modulo computation by repeated subtraction rather than by calling a slow library function.
2023-03-06 21:54:14 -06:00
Stephen Heumann 3406dbd3ae Prevent a tag declared in an inner scope from shadowing a typedef.
This could occur because when FindSymbol was called to look for symbols in all spaces, it would find a tag in an inner scope before a typedef in an outer scope. The processing order has been changed to look for regular symbols (including typedefs) in any scope, and only look for tags if no regular symbol is found.

Here is an example illustrating the problem:

typedef int T;
int main(void) {
        struct T;
        T x;
}
2023-03-06 21:38:05 -06:00
Stephen Heumann 645b210e7f Prevent tags from shadowing variable names within static initializers.
This occurred due to looking for the symbol in all namespaces rather than only variable space.

Here is an example affected by this:

int X;
int main(void) {
        struct X {int i;};
        static int *i = &X;
}
2023-03-05 22:29:09 -06:00
Stephen Heumann 1f6bc44b48 Fix handling of typedef names immediately after an inner scope where the identifier is redeclared.
If an identifier is used as a typedef in an outer scope but then declared as something else in an inner scope (e.g. a variable name or tag), and that same identifier is the next token after the end of the inner scope, it would not be recognized properly as a typedef name leading to spurious errors.\

Here is an example that triggered this:

typedef char Type;
void f(int Type);
Type t;

Here is another one:

int main(void) {
        typedef int S;
        if (1)
                (struct S {int a;} *)0;
        S x;
}
2023-03-05 21:40:59 -06:00
Stephen Heumann 85890e0b6b Give an error if assembly code tries to use direct page addressing for a local variable that is out of range.
This could previously cause bad code to be produced with no error reported.
2023-03-04 21:06:07 -06:00
Stephen Heumann a985a9ca7a Simplify code generation for function parameters.
The old approach would call GenerateCode twice for each parameter expression. Now, it is only called once. This is faster, and also avoids some oddities with error handling. With the previous approach, expressionType would not be set if there was an error in the expression, which could lead to additional spurious errors. Also, a lint message treated as a warning could appear twice.
2023-03-01 22:20:33 -06:00
Stephen Heumann ea623d38fc Avoid incorrectly setting lastwasconst.
This could happen in some cases where one subexpression of a larger expression was a constant. One effect of this was to cause spurious "lint: implicit conversion changes value of constant" messages in certain cases (when that lint check was enabled). It may also have caused certain errors to be missed in other situations.
2023-02-28 22:36:42 -06:00
Stephen Heumann bda54c0a79 Document qsort fixes. 2023-02-16 20:38:44 -06:00
Stephen Heumann cff8144c88 Do not do format checking on static functions.
It is legal for source files that do not include <stdio.h> to define static functions named printf, scanf, etc. These obviously are not the standard library functions and are not required to work the some way as them, so they should not be subject to format checking.
2023-02-12 19:19:28 -06:00
Stephen Heumann a6ef872513 Add debugging option to detect illegal use of null pointers.
This adds debugging code to detect null pointer dereferences, as well as pointer arithmetic on null pointers (which is also undefined behavior, and can lead to later dereferences of the resulting pointers).

Note that ORCA/Pascal can already detect null pointer dereferences as part of its more general range-checking code. This implementation for ORCA/C will report the same error as ORCA/Pascal ("Subrange exceeded"). However, it does not include any of the other forms of range checking that ORCA/Pascal does, and (unlike in ORCA/Pascal) it is controlled by a separate flag from stack overflow checking.
2023-02-12 18:56:02 -06:00
Stephen Heumann a32ddedc0c Add constants in tool headers for System 6.0.1 functionality.
These are all documented in Programmer's Reference for System 6.0.1.
2023-01-27 21:52:49 -06:00
Kelvin Sherlock 6b39cea80d Add missing SysBeep2 constants for System 6.0.1 (Programmer's Reference for System 6.0.1 page 13) 2023-01-27 17:07:33 -06:00
Stephen Heumann 4b9824d5d6 Remove an unused function. 2023-01-22 13:19:06 -06:00
Stephen Heumann 40260bb8a0 Remove an unnecessary instruction from stack check code.
The intention may have been to set the flags based on the return value, but that is not part of the calling convention and nothing should be relying on it.
2023-01-14 19:09:45 -06:00
Stephen Heumann 03fc7a43b9 Give an error for expressions with incomplete struct/union types.
These are erroneous, in situations where the expression is used for its value. For function return types, this violates a constraint (C17 6.5.2.2 p1), so a diagnostic is required. We also now diagnose this issue for identifier expressions or unary * (indirection) expressions. These cases cause undefined behavior per C17 6.3.2.1 p2, so a diagnostic is not required, but it is nice to give one.
2023-01-09 21:58:53 -06:00
Stephen Heumann 61a2cd1e5e Consistently report "compiler error" for unrecognized error codes.
The old approach of calling Error while in the middle of writing error messages did not work reliably.
2023-01-09 18:46:33 -06:00
Stephen Heumann 2958619726 Fix varargs stack repair.
Varargs-only stack repair (i.e. using #pragma optimize bit 3 but not bit 6) was broken by commit 32975b720f. It removed some code that was needed to allocate the direct page location used to hold the stack pointer value in that case. This would lead to invalid code being produced, which could cause a crash when run. The fix is to revert the erroneous parts of commit 32975b720f (which do not affect its core purpose of enabling intermediate code peephole optimization to be used when stack repair code is active).
2023-01-08 15:15:32 -06:00
Stephen Heumann 74b9885572 Fix and simplify handling of pascal qualifiers.
Redeclaration of a pascal function could cause spurious errors when using strict type checking. (This was similar to the issue fixed in commit b5b276d0f4, but this time occurring due to the CompTypes call in NewSymbol.) There may also have been subtle misbehavior in other corner cases.

Now the reversal of parameters for pascal functions is applied only once, in Declarator prior to calling NewSymbol. This ensures that symbols for pascal functions have the correct types whenever they are processed, and also simplifies the previous code, where the parameters could be reversed, un-reversed, and re-reversed in three separate places.
2023-01-07 19:52:11 -06:00
Stephen Heumann 4d1a8caf8a Do not check for functions not returning a value if pc_rev is used.
The pc_rev intermediate code always returns a value, so the check is not needed, and (since the generated code does not jump to a return label) it can yield false positives.
2023-01-06 22:44:40 -06:00
Stephen Heumann cb6173557e Add tests for <time.h> functions. 2023-01-05 20:46:59 -06:00
Stephen Heumann 34c1564dc4 Do not declare gets() in strict C11/C17 modes.
The declaration is still included in the default compatibility modes, where __KeepNamespacePure__ is not defined.
2023-01-05 17:25:25 -06:00
Stephen Heumann 245dd0a3f4 Add lint check for implicit conversions that change a constant's value.
This occurs when the constant value is out of range of the type being assigned to. This is likely indicative of an error, or of code that assumes types have larger ranges than they do in ORCA/C (e.g. 32-bit int).

This intentionally does not report cases where a value is assigned to a signed type but is within the range of the corresponding unsigned type, or vice versa. These may be done intentionally, e.g. setting an unsigned value to "-1" or setting a signed value using a hex constant with the high bit set. Also, only conversions to 8-bit or 16-bit integer types are currently checked.
2023-01-03 18:57:32 -06:00
Stephen Heumann 9f36e99194 Document __useTimeTool and add a declaration for it. 2023-01-02 18:10:41 -06:00
Stephen Heumann 5476118951 Add documentation and headers for timespec_get.
A macro is used to control whether struct timespec is declared, because GNO might want to declare it in other headers, and this would allow it to avoid duplicate declarations. (This will still require changes in the GNO headers. Currently, they declare struct timespec with different field names, although the layout is the same.)
2023-01-01 21:46:19 -06:00
Stephen Heumann 59664df9d9 Document <time.h> bug fixes. 2023-01-01 21:44:02 -06:00
Stephen Heumann f7a139b4b5 Document use of Time Tool Set by gmtime and strftime.
Also include some tests for strftime %z and %Z conversions (although just producing no output will satisfy them).
2022-12-28 19:57:19 -06:00
Stephen Heumann 7d3f1c8dd7 Add headers, documentation, and tests for tgamma(). 2022-12-24 20:21:31 -06:00
Stephen Heumann a87aeef25b Ensure native peephole opt uses a jump table.
In ORCA/Pascal's code generation, a case statement may use a jump table or a sequence of comparisons depending on whether it is considered sparse. This one was just a little too sparse to use a jump table, but changing it to use one makes it considerably faster. To force generation of a jump table, this commit adds several more explicit cases (even though they don't do anything).
2022-12-20 20:31:24 -06:00
Stephen Heumann cf9f19c93d Optimize LDA+TAY to LDY (when A is unused after).
This pattern comes up in the new return code when returning a local variable.
2022-12-20 20:21:25 -06:00
Stephen Heumann 854a6779a9 Generate even better code for constant returns.
If the return value is just a numeric constant or static address, it can simply be loaded right before the RTL instruction, avoiding any data movement.

This could actually be applied to a somewhat broader class of expressions, but for now it only applies to numeric or address constants, for which it is clearly correct.
2022-12-19 21:18:41 -06:00
Stephen Heumann e910eda623 Apply return optimization to struct/union return types. 2022-12-19 20:49:25 -06:00
Stephen Heumann 030f3ff9e1 Apply return optimization to enum and pointer return types. 2022-12-19 20:03:13 -06:00
Stephen Heumann d68e0b268f Generate more efficient code for a single return at end of function.
When a function has a single return statement at the end and meets certain other constraints, we now generate a different intermediate code instruction to evaluate the return value as part of the return operation, rather than assigning it to (effectively) a variable and then reading that value again to return it.

This approach could actually be used for all returns in C code, but for now we only use it for a single return at the end. Directly applying it in other cases could increase the code size by duplicating the function epilogue code.
2022-12-19 18:52:46 -06:00
Stephen Heumann 265a16d2f5 Add headers, documentation, and tests for erf() and erfc(). 2022-12-17 22:26:59 -06:00
Stephen Heumann 53fcb84352 Allocate staticNum prefixes only for scopes that have statics.
This is somewhat faster, and also reduces the theoretical chance of overflowing the available staticNum values for a large source file.
2022-12-13 22:17:25 -06:00
Stephen Heumann a7551d8c44 Optimize unused variable checks to only run on scopes with variables.
This reduces the overhead of them considerably.
2022-12-13 21:34:24 -06:00
Stephen Heumann 09fbfb1905 Maintain a pool of empty symbol tables that can be reused.
The motivation for this is that allocating and clearing symbol tables is a common operation, especially with C99+, where a construct like "if (...) { ... }" involves three levels of scope with their own symbol tables. In some tests, it could take an appreciable fraction of total execution time (sometimes ~10%).

This patch allows symbol tables that have already been allocated and cleared to be reused for a subsequent scope, as long as they are still empty. It does this by maintaining a pool of empty symbol tables and taking one from there rather than allocating a new one when possible.

We impose a somewhat arbitrary limit of MaxBlock/150000 on the number of symbol tables we keep, to avoid filling up memory with them. It would probably be better to use purgeable handles here, but that would be a little more work, and this should be good enough for now.
2022-12-13 21:14:23 -06:00
Stephen Heumann 705c9d36a2 Count variables referenced in assembly code as used. 2022-12-13 19:04:18 -06:00
Stephen Heumann 4bc486eade Do not require unused static functions to be defined.
This mostly implements the rule in C17 6.9 p3, which requires a definition to be provided only if the function is used in an expression. Per that rule, we should also exclude most sizeof or _Alignof operands, but we don't do that yet.
2022-12-12 22:10:36 -06:00
Stephen Heumann fe62f70d51 Add lint option to check for unused variables. 2022-12-12 21:47:32 -06:00
Stephen Heumann 44499bdddb Make root files jump to the shutdown code rather than calling it.
This better reflects that the shutdown code will never return.
2022-12-11 22:14:09 -06:00
Stephen Heumann 17936a14ed Rework root file code for CDevs to avoid leaking user IDs.
Formerly, the code would allocate user IDs but never free them. The result was that one user ID was leaked for each time a CDev was opened and closed.

The new root code calls new cleanup code in ORCALib, which detects if the CDev is going away and deallocates its user ID if so.
2022-12-11 22:01:29 -06:00
Stephen Heumann ecca7a7737 Never make the segment in the root file dynamic.
This would previously happen if a segment directive with "dynamic" appeared before the first function in the program. That would cause the resulting program not to work, because the root segment needs to be a static segment at the start of the program, but if it is dynamic it would come after a jump table and a static segment of library code.

The root segments are also configured to refer to main or the NDA/CDA entry points using LEXPR records, so that they can be in dynamic segments (not that they necessarily should be). That change is intentionally not done for CDEV/XCMD/NBA, because they use code resources, which do not support dynamic segments, so it is better to force a linker error in these cases.
2022-12-11 14:46:38 -06:00
Stephen Heumann 1754607908 Add native peephole opts for stack repair code.
These mainly affect cases of multiple successive or nested function calls.
2022-12-10 21:56:16 -06:00
Stephen Heumann 32975b720f Allow native code peephole opt to be used when stack repair is enabled.
I think the reason this was originally disallowed is that the old code sequence for stack repair code (in ORCA/C 2.1.0) ended with TYA. If this was followed by STA dp or STA abs, the native code peephole optimizer (prior to commit 7364e2d2d3) would have turned the combination into a STY instruction. That is invalid if the value in A is needed. This could come up, e.g., when assigning the return value from a function to two different variables.

This is no longer an issue, because the current code sequence for stack repair code no longer ends in TYA and is not susceptible to the same kind of invalid optimization. So it is no longer necessary to disable the native code peephole optimizer when using stack repair code (either for all calls or just varargs calls).
2022-12-10 20:34:00 -06:00
Stephen Heumann 7364e2d2d3 Fix issue with native code optimization of TYA+STA.
This would be changed to STY, but that is invalid if the A value is needed afterward. This could affect the code for certain division operations (after the optimizations in commit 4470626ade).

Here is an example that would be miscompiled:

#pragma optimize -1
#include <stdio.h>
int main(void) {
        unsigned i = 55555;
        unsigned a,b;
        a = b = i / 10000;
        printf("%u %u\n", a,b);
}

Also, remove MVN from the list of "ASafe" instructions since it really isn't, although I don't think this was affecting anything in practice.
2022-12-10 19:37:48 -06:00
Stephen Heumann e71fe5d785 Treat unary + as an actual operator, not a no-op.
This is necessary both to detect errors (using unary + on non-arithmetic types) and to correctly perform the integer promotions when unary + is used (which can be detected with sizeof or _Generic).
2022-12-09 19:03:38 -06:00
Stephen Heumann f027286b6a Do not generate varargs stack repair code if no variable args are passed.
This affects calls to a varargs function that do not actually supply any arguments beyond the fixed portion of the argument list, e.g. printf("foo"). Since these calls do not supply any variable arguments, they clearly do not include any extra variable arguments beyond those used by the function, so the standards-conformance issue that requires varargs stack repair code does not apply.

It is possible that the call may include too few variable arguments, but that is illegal behavior, and it will trash the stack even when varargs stack repair code is present (although in some cases programs may "get away" with it). If stack repair code around these calls is still desired, then general stack repair code can be enabled for all function calls.
2022-12-08 19:27:37 -06:00
Stephen Heumann 6ba6ad549f Change va_start to not depend on the last fixed argument.
This is necessary to work correctly if the last fixed argument is of type double and #pragma extensions bit 1 is clear. It will also be necessary for C23, where va_start does not require the LastFixedParm argument. (For now, however, we stick with the pre-C23 definition of va_start where that argument needs to be supplied, even though it is now ignored.)
2022-12-08 19:15:53 -06:00
Stephen Heumann fb5a2fcf33 Generate more efficient code for shifts by 13, 14, or 15 bits. 2022-12-07 21:54:53 -06:00
Stephen Heumann bb1bd176f4 Add a command-line option to select the C standard to use.
This provides a more straightforward way to place the compiler in a "strict conformance" mode. This could essentially be achieved by setting several pragma options, but having a single setting is simpler. "Compatibility modes" for older standards can also be selected, although these actually continue to enable most C17 features (since they are unlikely to cause compatibility problems for older code).
2022-12-07 21:35:15 -06:00
Stephen Heumann 6857913daa Make the object buffer dynamically resizable.
It will now grow as needed to accommodate large segments, subject to the constraints of available memory. In practice, this mostly affects the size of initialized static arrays that can be used.

This also removes any limit apart from memory size on how large the object representation produced by a "compile to memory" can be, and cleans up error reporting regarding size limits.
2022-12-06 21:49:20 -06:00
Stephen Heumann 389f60ed27 Remove segStart variable.
It is the same as objPtr in all meaningful cases, so there is no need for it to be a separate variable.
2022-12-06 19:39:10 -06:00
Stephen Heumann 8aedd42294 Optimize out TDC following TCD.
This can occur if the first code in the function (which could be an initializer) takes the address of a local variable.
2022-12-05 18:02:23 -06:00
Stephen Heumann a7d9d3039b Initialize arrays from strings with a pc_mov operation.
This is smaller and more efficient than the previous code that called memcpy(). It also avoids a theoretical issue if the user's code included an incompatible definition of memcpy.
2022-12-05 18:00:56 -06:00
Stephen Heumann 0c4660d5fc Generate better code for pc_mov in some cases.
This allows it to use MVN-based copying code in more cases, including when moving to/from local variables on the stack. This is slightly shorter and more efficient than calling a helper function.
2022-12-05 17:58:30 -06:00
Stephen Heumann 8e1db102eb Allow line continuations within // comments.
This is what the standards specify.
2022-12-04 23:16:06 -06:00
Stephen Heumann facd1bf992 Add parentheses around negative values in float.h. 2022-12-04 22:44:48 -06:00
Stephen Heumann c06d78bb5e Add __STDC_VERSION__ macro.
With the addition of designated initializers, ORCA/C now supports all the major mandatory language features added between C90 and C17, apart from those made optional by C11. There are still various small areas of nonconformance and a number of missing library functions, but at this point it is reasonable for ORCA/C to report itself as being a C17 implementation.
2022-12-04 22:25:02 -06:00
Stephen Heumann 2550081517 Fix bug with 4-byte comparisons against globals in large memory model.
Long addressing was not being used to access the values, which could lead to mis-evaluation of comparisons against values in global structs, unions, or arrays, depending on the memory layout.

This could sometimes affect the c99desinit.c test, when run with large memory model and at least intermediate code peephole optimization. It could also affect this simpler test (depending on memory layout):

#pragma memorymodel 1
#pragma optimize 1
struct S {
        void *p;
} s =  {&s};
int main(void) {
        return s.p != &s; /* should be 0 */
}
2022-12-04 21:54:29 -06:00
Stephen Heumann 935bb6c04e Merge branch 'designated-initializers'
This implements designated initializers as specified by C99 and later.

It also fixes a few initialization-related bugs.
2022-12-04 21:28:15 -06:00
Stephen Heumann f5f63563c6 Add tests for designated initializers. 2022-12-04 21:26:40 -06:00
Stephen Heumann 736e7575cf Fix issues with type conversions in static initialization.
*Initialization of floating-point variables from unsigned long expressions with value > LONG_MAX would give the wrong value.
*Initialization of floating-point variables from (unsigned) long long expressions would give the wrong value.
*Initialization of _Bool variables should give 0 or 1, as per the usual rules for conversion to _Bool.
*Initialization of integer variables from floating-point expressions should be allowed, applying the usual conversions.
2022-12-04 16:36:16 -06:00
Stephen Heumann 36c70f9107 Move ResolveForwardReference call to apply to the field being initialized. 2022-12-04 16:23:33 -06:00
Stephen Heumann 20770f388e Move memory allocation code to a new function in MM. 2022-12-03 18:50:26 -06:00
Stephen Heumann 7c0492cfa4 Document designated initializers in the release notes. 2022-12-03 18:04:50 -06:00
Stephen Heumann 945d5ce855 Generate calls to ~ZERO to initialize large numbers of zero bytes.
There is a tradeoff of code size vs. speed, since a sequence of STZ instructions is faster than a call to ~ZERO but could be quite large for a big array or struct. We now use ~ZERO for initializations of over 50 bytes to avoid excessive code bloat; the exact number chosen is somewhat arbitrary.
2022-12-03 15:30:31 -06:00
Stephen Heumann d56cf7e666 Pass constant data to backend as pointers into buffer.
This avoids needing to generate many intermediate code records representing the data at most 8 bytes at a time, which should reduce memory use and probably improve performance for large initialized arrays or structs.
2022-12-03 00:14:15 -06:00
Stephen Heumann 28e119afb1 Rework static initialization to support new-style initializer records.
Static initialization of arrays/structs/unions now essentially "executes" the initializer records to fill in a buffer (and keep track of relocations), then emits pcode to represent that initialized state. This supports overlapping and out-of-order initializer records, as can be produced by designated initialization.
2022-12-02 21:55:57 -06:00
Stephen Heumann 48efd462ef Allow designated initialization of fields named the same as typedefs.
They are in separate name spaces, so this should be permitted.
2022-12-01 14:09:03 -06:00
Stephen Heumann 8ad58b0de7 Report an error for dual commas at end of struct/union initializer.
This covers things like:

struct {int a,b;} u = {1,2,,};
2022-11-30 19:07:38 -06:00
Stephen Heumann c1a188aa95 Add some comments in initialization code. 2022-11-30 18:55:43 -06:00
Stephen Heumann 51951721c5 Simplify Fill procedure.
In the current design, it only needs to fill in a certain number of bytes, not a specific type.
2022-11-30 18:37:28 -06:00
Stephen Heumann 94584b0f05 Give error for arrays that are still 0 size after initialization.
This prohibits empty initializers ({}) for arrays of unknown size, consistent with C23 requirements. Previous versions of C did not allow empty initializers at all, but ORCA/C historically did in some cases, so this patch still allows them for structs/unions/arrays of known size.
2022-11-30 17:57:21 -06:00
Stephen Heumann e7940db4c8 Allow initializers where a string literal begins a longer expression.
This is needed to support cases like:

char s[5] = {"abc"[1]};
2022-11-29 21:15:42 -06:00
Stephen Heumann 1f468c437f Set errorFound to true for most errors during initialization. 2022-11-29 13:20:30 -06:00
Stephen Heumann ac741e26ab Allow nested auto structs/unions to be initialized with an expression of the same type.
When the expression is initially parsed, we do not necessarily know whether it is the initializer for the struct/union or for its first member. That needs to be determined based on the type. To support that, a new function is added to evaluate the expression separately from using it to initialize an object.
2022-11-29 13:19:59 -06:00
Stephen Heumann c58d84689a Explicitly set disp for every array element.
This is needed to properly deal with arrays of structures with unnamed bit-fields at the end.
2022-11-28 22:11:39 -06:00
Stephen Heumann 4a8b5b25c7 Use a variable to indicate storage duration for initialization. 2022-11-28 21:59:08 -06:00
Stephen Heumann 50e3a8ea30 Avoid dereferencing nil. 2022-11-28 21:44:30 -06:00
Stephen Heumann bde70e0885 Simplify fill-with-zeros logic.
It now just fills on levels with braces (or at the end of a string).
2022-11-28 21:41:05 -06:00
Stephen Heumann dc305a86b2 Add flag to suppress printing of put-back tokens with #pragma expand.
This is currently used in a couple places in the designated initializer code (solving the problem with #pragma expand in the last commit). It could probably be used elsewhere too, but for now it is not.
2022-11-28 21:22:56 -06:00
Stephen Heumann 39250629bd Support designated initialization of anonymous member fields.
As noted previously, there is some ambiguity in the standards about how anonymous structs/unions participate in initialization. ORCA/C follows the model that they do participate as structs or unions, and designated initialization of them is implemented accordingly.

This currently has a slight issue in that extra copies of the anonymous member field name will be printed in #pragma expand output.
2022-11-28 20:55:47 -06:00
Stephen Heumann 4621336c3b Give anonymous structs/unions unique internal names.
This will help deal with initialization of them.
2022-11-28 20:47:13 -06:00
Stephen Heumann a3c4eeb8f6 Rework bit-field initialization.
This generally simplifies things, and always generates individual initializer records for each explicit initialization of a bit-field (which was previously done for automatic initialization, but not static).

This should work correctly for automatic initialization, but needs corresponding code changes in GenSymbols for static initialization.
2022-11-28 18:49:49 -06:00
Stephen Heumann adfa7c04c1 Support for filling uninitialized data in structs/unions during initialization. 2022-11-28 18:46:40 -06:00
Stephen Heumann c261e14d56 Basic support for mixing array and struct designators. 2022-11-27 23:54:24 -06:00
Stephen Heumann 250a6361c1 Basic code to handle struct/union designators.
This does not deal with filling yet.
2022-11-27 23:37:22 -06:00
Stephen Heumann def9e56e8e Fill logic for when to fill uninitialized data with zeros.
This could maybe be simplified to just fill on levels with braces, but I want to consider that after implementing designated initializers for structs and unions.
2022-11-27 17:30:36 -06:00
Stephen Heumann 6260a27b11 Use 16-bit operations to zero out a range of bytes. 2022-11-27 16:49:43 -06:00
Stephen Heumann 58d8edf1ee Handle filling of array elements without explicit initializers.
At this point, designated initializers for arrays are at least largely working.
2022-11-27 16:48:58 -06:00
Stephen Heumann aa6b82a136 Ensure array designators are processed at the level with braces. 2022-11-26 23:03:20 -06:00
Stephen Heumann 5df94c953e Fix handling of initializer counts in AutoInit.
This was broken by the previous changes to it.
2022-11-26 21:09:53 -06:00
Stephen Heumann 335e8be75e Rename the procedure for initializing one element of an auto variable.
"InitializeOneElement" is more descriptive of what it does now. We also skip passing the variable, which is always the same.
2022-11-26 20:46:24 -06:00
Stephen Heumann 5f8a6baa94 Get rid of an unnecessary field in initializer records.
The "isStructOrUnion" information can now be determined simply by the type in the record.
2022-11-26 20:29:31 -06:00
Stephen Heumann 968844fb38 Make auto initialization use the type and disp in initializer record.
This simplifies the code a good bit, as well as enabling out-of-order initialization using designated initializers.
2022-11-26 20:24:33 -06:00
Stephen Heumann d1edc8821d Record the type being initialized in auto initializer records. 2022-11-26 19:58:01 -06:00
Stephen Heumann cd9931a60c Record displacement from start of object in initializer records.
The idea (not yet implemented) is to use this to support out-of-order initialization. For automatic variables, we can just initialize the subobjects in the order that initializers appear. For static variables, we will eventually need to reorder the initializers in order, but this can be done based on their recorded displacements.
2022-11-26 19:27:17 -06:00
Stephen Heumann 8cfc14b50a Rename itype field of initializerRecord to basetype. 2022-11-26 15:45:26 -06:00
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 92a3af1d5f Fix icp/isp tables to account for otherch.
Commit 9cc72c8845 introduced otherch tokens but did not properly update these tables to account for them. This would cause * not to be accepted as the first character in an expression, and might also cause other problems.
2022-11-25 23:25:58 -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 ab368d442a Allow \ as an "other character" preprocessing token.
This still has a few issues. A \ token may not be followed by u or U (because this triggers UCN processing). We should scan through the whole possible UCN until we can confirm whether it is actually a UCN, but that would require more lookahead. Also, \ is not handled correctly in stringization (it should form escape sequences).
2022-11-08 20:46:48 -06:00
Stephen Heumann 9cc72c8845 Support "other character" preprocessing tokens.
This implements the catch-all category for preprocessing tokens for "each non-white-space character that cannot be one of the above" (C17 section 6.4). These may appear in skipped code, or in macros or macro parameters if they are never expanded or are stringized during macro processing. The affected characters are $, @, `, and many extended characters.

It is still an error if these tokens are used in contexts where they remain present after preprocessing. If #pragma ignore bit 0 is clear, these characters are also reported as errors in skipped code or preprocessor constructs.
2022-11-08 18:58:50 -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 de57170ef8 Try to form composite types for extern declarations within blocks.
If the extern declaration refers to a global variable/function for which a declaration is already visible, the inner declaration should have the composite type (and it is an error if the types are incompatible).

This affects programs like the following:

static char a[60] = {5};
int main(void) {
        extern char a[];
        return sizeof(a)+a[0]; /* should return 65 */
}
2022-11-07 19:00:35 -06:00
Stephen Heumann fa166030fe Allow duplicate typedefs within block scopes (C11). 2022-11-06 21:39:58 -06:00
Stephen Heumann e168a4d6cb Treat static followed by extern declarations as specifying internal linkage.
See C17 section 6.2.2 p4-5.
2022-11-06 21:19:47 -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 83147655d2 Revise NewSymbol to more closely align with standards.
Function declarations within a block are now entered within its symbol table rather than moved to the global one. Several error checks are also added or tightened.

This fixes at least one bug: if a function declared within a block had the same name as a variable in an outer scope, the symbol table entry for that variable could be corrupted, leading to spurious errors or incorrect code generation. This example program illustrates the problem:

/* This should compile without errors and return 2 */
int f(void) {return 1;}
int g(void) {return 2;}
int main(void) {
        int (*f)(void) = g;
        {
                int f(void);
        }
        f = g;
        return f();
}

Errors now detected include:
*Duplicate declarations of a static variable within a block (with the second one initialized)
*Duplicate declarations of the same variable as static and non-static
*Declaration of the same identifier as a typedef and a variable (at file scope)
2022-11-06 20:50:25 -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 9a7dc23c5d When a symbol is multiply declared, form the composite type.
Previously, it generally just used the later type (except for function types where only the earlier one included a prototype). One effect of this is that if a global array is first declared with a size and then redeclared without one, the size information is lost, causing the proper space not to be allocated.

See C17 section 6.2.7 p4.

Here is an example affected by the array issue (dump the object file to see the size allocated):

int foo[50];
int foo[];
2022-10-30 18:54:40 -05:00
Stephen Heumann d4c4d18a55 Remove some unused code.
This seemed to be aimed at supporting lazy allocation of symbol tables. That could be a useful optimization, but the code that existed was incomplete and did not do anything useful. That or similar code could be reintroduced as part of a full implementation of lazy allocation, if it is ever done.
2022-10-30 15:06:28 -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 913052fe7c Add documentation and tests for _Pragma. 2022-10-29 16:02:38 -05:00
Stephen Heumann e5428b21d2 Do not skip over the character after _Pragma(...). 2022-10-29 15:55:44 -05:00
Stephen Heumann 4702df9aac Support Unicode strings and some escape sequences in _Pragma.
This still works by "reconstructing" the string literal text, rather than just using what was in the source code. This is not what the standards specify and can result in slightly different behavior in some corner cases, but for realistic cases it is probably fine.
2022-10-25 22:47:22 -05:00
Stephen Heumann e63d827049 Do not do macro expansion on preprocessor directive names.
According to the C standards (C17 section 6.10.3 p8), they should not be subject to macro replacement.

A similar change also applies to the "STDC" in #pragma STDC ... (but we still allow macros for other pragmas, which is allowed as part of the implementation-defined behavior of #pragma).

Here is an example affected by this issue:

#define ifdef ifndef
#ifdef foobar
#error "foobar defined?"
#else
int main(void) {}
#endif
2022-10-25 22:40:20 -05:00
Stephen Heumann e0b27db652 Do not try to interpret non-identifier tokens as pragma names.
This could access arbitrary memory locations, and could theoretically cause misbehavior including falsely recognizing the token as a pragma or accessing a softswitch/IO location.
2022-10-25 22:26:30 -05:00
Stephen Heumann 81353a9f8a Always interpret the digit sequence in #line as decimal.
This is what the standards call for.
2022-10-23 13:47:59 -05:00
Stephen Heumann e3a3548443 Fix line numbering via #line when using a .sym file.
The line numbering would be off by one in this case.
2022-10-22 21:56:16 -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 760c932fea Initial implementation of _Pragma (C99).
This works for typical cases, but does not yet handle Unicode strings, very long strings, or certain escape sequences.
2022-10-22 17:08:54 -05:00
Stephen Heumann 859aa4a20a Do not enter the editor with a negative file displacement.
This could happen due to errors on the command line, e.g.:

cmpl +T +E file.c cc=(invalid)
2022-10-22 12:54:59 -05:00
Stephen Heumann 946c6c1d55 Always end preprocessor expression processing at end of line.
In certain error cases, tokens from subsequent lines could get treated as part of a preprocessor expression, causing subsequent code to be essentially ignored and producing strange error messages.

Here is an example (with an error) affected by this:

#pragma optimize 0 0
int main(void) {}
2022-10-21 18:51:53 -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 cb5db95476 Do not print "\000" at end of printf/scanf format strings.
This happened due to the change to include the null terminator in the internal representation of strings.
2022-10-18 18:40:14 -05:00
Stephen Heumann 91d33b586d Fix various C99+ conformance issues and bugs in test cases.
The main changes made to most tests are:

*Declarations always include explicit types, not relying on implicit int. The declaration of main in most test programs is changed to be "int main (void) {...}", adding an explicit return type and a prototype. (There are still some non-prototyped functions, though.)

*Functions are always declared before use, either by including a header or by providing a declaration for the specific function. The latter approach is usually used for printf, to avoid requiring ORCA/C to process stdio.h when compiling every test case (which might make test runs noticeably slower).

*Make all return statements in non-void functions (e.g. main) return a value.

*Avoid some instances of undefined behavior and type errors in printf and scanf calls.

Several miscellaneous bugs are also fixed.

There are still a couple test cases that intentionally rely on the C89 behavior, to ensure it still works.
2022-10-17 20:17:24 -05:00
Stephen Heumann b3c30b05d8 Add a specific test for old C89 features that were removed from C99+. 2022-10-16 21:29:55 -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 44a1ba5205 Print floating constants with more precision in #pragma expand output.
Finite numbers should now be printed with sufficient precision to produce the same value as the original constant in the relevant type.
2022-10-15 22:20:22 -05:00
Stephen Heumann 83ac0ecebf Add a function to peek at the next character.
This is necessary to correctly handle line continuations in a few places:
* Between an initial . and the subsequent digit in a floating constant
* Between the third and fourth characters of a %:%: digraph
* Between the second and third dots of a ... token

Previously, these would not be tokenized correctly, leading to spurious errors in the first and second cases above.

Here is a sample program illustrating the problem:

int printf(const char * restrict, ..\
\
??/
.);
int main(void) {
        double d = .??/
\
??/
\
1234;
        printf("%f\n", d);
}
2022-10-15 21:42:02 -05:00
Stephen Heumann 6fadd52fc2 Update release notes to cover fixes to fgets() and gets(). 2022-10-15 19:11:11 -05:00
Stephen Heumann 5be888a2bd Make stdin/stdout/stderr into macros.
They are supposed to be macros, according to the C standards. This ordinarily doesn't matter, but it can be detected by #ifdef, as in the following program:

#include <stdio.h>
#ifdef stdin
int main(void) {
        puts("stdin is a macro");
}
#endif
2022-10-15 17:10:59 -05:00
Stephen Heumann 072f8be6bc Adjust test of missing declarators to cover only cases that are legal.
Previously, it included some instances that violate the standard constraint that a declaration must declare a declarator, a tag, or an enum constant. As of commit f263066f61, this constraint is now enforced, so those cases would (properly) give errors.
2022-10-13 18:52:18 -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 99a10590b1 Avoid out-of-range branches around asm code using dcl directives.
The branch range calculation treated dcl directives as taking 2 bytes rather than 4, which could result in out-of-range branches. These could result in linker errors (for forward branches) or silently generating wrong code (for backward branches).

This patch now treats dcb, dcw, and dcl as separate directives in the native-code layer, so the appropriate length can be calculated for each.

Here is an example of code affected by this:

int main(int argc, char **argv) {
top:
        if (!argc) { /* this caused a linker error */
                asm {
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                        dcl 0
                }
                goto top; /* this generated bad code with no error */
        }
}
2022-10-13 18:00:16 -05:00
Stephen Heumann 19683706cc Do not optimize code from asm statements.
Previously, the assembly-level optimizations applied to code in asm statements. In many cases, this was fine (and could even do useful optimizations), but occasionally the optimizations could be invalid. This was especially the case if the assembly involved tricky things like self-modifying code.

To avoid these problems, this patch makes the assembly optimizers ignore code from asm statements, so it is always emitted as-is, without any changes.

This fixes #34.
2022-10-12 22:03:37 -05:00
Stephen Heumann 12a2e14b6d Follow up peephole optimizations that may enable more optimizations.
If one step of peephole optimization produced code that can be further optimized with more peephole optimizations, that additional optimization was not always done. This makes sure the additional optimization is done in several such cases.

This was particularly likely to affect functions containing asm blocks (because CheckLabels would never trigger rescanning in them), but could also occur in other cases.

Here is an example affected by this (generating inefficient code to load a[1]):

#pragma optimize 1
int a[10];
void f(int x) {}
int main(int argc, char **argv) {
        if (argc) return 0;
        f(a[1]);
}
2022-10-12 19:14:13 -05:00
Stephen Heumann ca21e33ba7 Generate more efficient code for indirect function calls. 2022-10-11 21:14:40 -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 4e76f62b0e Allow additional letters in identifiers.
The added characters are accented roman letters that were added to the Mac OS Roman character set at some time after it was first defined. Some IIGS fonts include them, although others do not.
2022-08-01 19:59:49 -05:00
Stephen Heumann 95ad02f0b9 Detect various errors in macro definitions.
These changes detect violations of several constraints in C17 section 6.10.3 and subsections.
2022-07-28 20:49:22 -05:00
Stephen Heumann 711549392c Update displayed version number to mark this as a development version. 2022-07-25 18:33:32 -05:00
498 changed files with 12442 additions and 3409 deletions

22
Asm.pas
View File

@ -166,10 +166,8 @@ var
{ An error was found: skip to the end & quit }
begin {Skip}
charKinds[ord('#')] := ch_pound;
while not (token.kind in [rbracech,eofsy]) do
NextToken;
charKinds[ord('#')] := illegal;
goto 99;
end; {Skip}
@ -226,6 +224,7 @@ var
size := longAddress;
end {if}
else begin
id^.used := true;
operand.symbolPtr := id;
if id^.storage in [stackFrame,parameter] then begin
code^.slab := id^.lln;
@ -329,7 +328,6 @@ while not (token.kind in [rbracech,eofsy]) do begin
{find the label and op-code}
CheckForComment;
charKinds[ord('#')] := ch_pound; {allow # as a token}
if token.kind <> ident then begin {error if not an identifier}
Error(9);
Skip;
@ -345,7 +343,6 @@ while not (token.kind in [rbracech,eofsy]) do begin
opname := token;
NextToken;
end; {while}
charKinds[ord('#')] := illegal; {don't allow # as a token}
{identify the op-code}
if length(opname.name^) = 3 then begin
@ -568,13 +565,18 @@ while not (token.kind in [rbracech,eofsy]) do begin
{handle data declarations}
else if opc <= o_dcl then begin
Exp([semicolonch], true);
code^.s := d_add;
if opc = o_dcb then
code^.r := ord(direct)
else if opc = o_dcw then
code^.r := ord(absolute)
else
if opc = o_dcb then begin
code^.s := d_dcb;
code^.r := ord(direct);
end {if}
else if opc = o_dcw then begin
code^.s := d_dcw;
code^.r := ord(absolute);
end {else if}
else begin
code^.s := d_dcl;
code^.r := ord(longabsolute);
end; {else}
end {if opc <= o_dcl}
{handle the brk instruction}

44
C.Read.Me Normal file
View File

@ -0,0 +1,44 @@
Welcome to ORCA/C 2.2.1! This is a release containing updates from
community members (Stephen Heumann and Kelvin Sherlock).
ORCA/C 2.2 adds support for almost all of the new language and library
features required by the C17 standard. It also has several other new
features, such as additional lint checks to help identify bugs and
portability problems. In addition to these new features, ORCA/C 2.2
includes hundreds of bug fixes in the compiler and libraries.
ORCA/C 2.2.1 includes additional bug fixes to ORCA/C 2.2.0.
The ORCA/C manual has been fully updated to cover ORCA/C 2.2, so new
users should simply refer to that. Users familiar with older versions
of ORCA/C can refer to the cc.notes file in the Release.Notes directory
for a description of the changes between ORCA/C 2.0 and ORCA/C 2.2.1.
ORCA/C 2.2.1 requires a real or emulated Apple IIGS with at least the
following specifications:
* 2 MB of RAM (3 MB or more recommended)
* a hard drive or SSD
* System 6.0.1 or later
ORCA/C can also be run on modern Mac, Windows, or Linux systems as a
cross compiler by using Golden Gate, a specialized emulation tool by
Kelvin Sherlock. It is available separately from Juiced.GS:
https://juiced.gs/store/golden-gate/
If you have any questions, or if you want to get involved in ORCA/C
development, please get in touch. The ORCA/C development project is
hosted on GitHub, and bug reports or patches can be submitted there:
https://github.com/byteworksinc/ORCA-C
Thanks to:
* Mike Westerfield, for writing ORCA/C, releasing the source code,
and permitting it to be updated by the community.
* Kelvin Sherlock, for providing several patches and bug reports, and
for writing several useful tools for modern Apple II development.
* Soenke Behrens, for compiling a list of ORCA/C bug reports and test
cases, which has helped me to identify and fix a number of bugs.
* The developers of Csmith (http://embed.cs.utah.edu/csmith/), an
automated compiler testing tool that has helped to find several bugs.
--Stephen Heumann (stephenheumann@gmail.com)

View File

@ -0,0 +1,46 @@
/***************************************************************
*
* Fibonacci
*
* Recursively computes Fibonacci numbers to test the speed of
* function calls.
*
* To get the best performance from the desktop development
* environment, be sure and turn debugging off from the
* Compile Dialog. Use the Compile command from the Run menu
* to get the compile dialog.
*
****************************************************************/
#pragma keep "FIB"
#pragma optimize -1
#pragma lint -1
#include <stdio.h>
#define NTIMES 10 /* # iterations */
#define NUMBER 23 /* largest Fib # smaller than 32767 */
int Fibonacci(int x)
{
if (x > 2)
return Fibonacci(x-1)+Fibonacci(x-2);
else
return 1;
}
int main (void)
{
int value;
unsigned i;
printf("%d iterations:\n", NTIMES);
for (i = 0; i < NTIMES; ++i)
value = Fibonacci(NUMBER);
printf("Fibonacci(%d) = %d\n", NUMBER, value);
return 0;
}

View File

@ -0,0 +1,51 @@
/***************************************************************
*
* Float
*
* Test simple floating point operations.
*
* To get the best performance from the desktop development
* environment, be sure and turn debugging off from the
* Compile Dialog. Use the Compile command from the Run menu
* to get the compile dialog.
*
***************************************************************/
#pragma keep "Float"
#pragma optimize -1
#pragma lint -1
#include <stdio.h>
#define const1 3.141597
#define const2 1.7839032e4
#define count 1000
int main(void)
{
double a,b,c;
int i;
a = const1;
b = const2;
printf("%d iterations.\n", count);
for (i = 0; i < count; ++i) {
c = a*b;
c = c/a;
c = a*b;
c = c/a;
c = a*b;
c = c/a;
c = a*b;
c = c/a;
c = a*b;
c = c/a;
c = a*b;
c = c/a;
c = a*b;
c = c/a;
}
printf("Done. C is %e.\n", c);
return 0;
}

View File

@ -0,0 +1,114 @@
/***************************************************************
*
* Gamm
*
* Test the speed of floating point operations in a mix tha
* is typical of scientific and engineering applications.
*
* To get the best performance from the desktop development
* environment, be sure and turn debugging off from the
* Compile Dialog. Use the Compile command from the Run menu
* to get the compile dialog.
*
***************************************************************/
#pragma keep "Gamm"
#pragma optimize -1
#pragma lint -1
#include <stdio.h>
int main (void)
{
int five,i,j,n,rep,ten,thirty;
float acc,acc1,divn,rn,root,x,y;
float a[30], b[30], c[30];
printf("Start timing 15000 Gamm units\n");
n = 50;
five = 5;
ten = 10;
thirty = 30;
rn = n;
divn = 1.0/rn;
x = 0.1;
acc = 0.0;
/* initialize a and b */
y = 1.0;
for (i = 0; i < thirty; ++i) {
a[i] = i+1;
b[i] = -y;
y = -y;
};
/* one pass thru this loop corresponds to 300 gamm units */
for (rep = 0; rep < n; ++rep) {
/* first addition/subtraction loop */
i = 29;
for (j = 0; j < 30; ++j) {
c[i] = a[i]+b[i];
--i;
};
/* first polynomial loop */
y = 1.0;
for (i = 0; i < 10; ++i)
y = (y+c[i])*x;
acc1 = y*divn;
/* first maximum element loop */
y = c[10];
for (i = 10; i < 20; ++i)
if (c[i] > y)
y = c[i];
/* first square root loop */
root = 1.0;
for (i = 0; i < 5; ++i)
root = 0.5*(root+y/root);
acc1 = acc1+root*divn;
/* second addition/subtraction loop */
for (i = 0; i < 30; ++i)
a[i] = c[i]-b[i];
/* second polynomial loop */
y = 0.0;
for (i = 0; i < 10; ++i)
y = (y+a[i])*x;
/* second square root loop */
root = 1.0;
for (i = 1; i < 5; ++i)
root = 0.5*(root+y/root);
acc1 = acc1+root*divn;
/* first multiplication loop */
for (i = 0; i < thirty; ++i)
c[i] = c[i]*b[i];
/* second maximum element loop */
y = c[19];
for (i = 20; i < thirty; ++i)
if (c[i] > y)
y = c[i];
/* third square root loop */
root = 1.0;
for (i = 0; i < 5; ++i)
root = 0.5*(root+y/root);
acc1 = acc1+root*divn;
/* third polynomial loop */
y = 0.0;
for (i = 0; i < 10; ++i)
y = (y+c[i])*x;
acc1 = acc1+y*divn;
/* third maximum element loop */
y = c[0];
for (i = 1; i < 10; ++i);
if (c[i] > y)
y = c[i];
/* fourth square root loop */
root = 1.0;
for (i = 0; i < 5; ++i)
root = 0.5*(root+y/root);
acc1 = acc1+root*divn;
acc = acc+acc1;
}
printf("%12d %12.7e %12.7e\n", n, acc, acc1);
return 0;
}

View File

@ -0,0 +1,56 @@
/***************************************************************
*
* Integer Math
*
* Test the speed of the four basic integer math operations.
*
* To get the best performance from the desktop development
* environment, be sure and turn debugging off from the
* Compile Dialog. Use the Compile command from the Run menu
* to get the compile dialog.
*
****************************************************************/
#pragma keep "IMath"
#pragma optimize -1
#pragma lint -1
#include <stdio.h>
#define ITER 10000
int main (void)
{
int a,b,c,d,e,f;
unsigned i;
printf("Start timing...\n");
b = 1000;
c = 10;
d = 100;
e = 5;
f = 10;
for (i = 0; i < ITER; ++i) {
a = b+c-d*e/f;
a = b+c-d*e/f;
a = b+c-d*e/f;
a = b+c-d*e/f;
a = b+c-d*e/f;
a = b+c-d*e/f;
a = b+c-d*e/f;
a = b+c-d*e/f;
a = b+c-d*e/f;
a = b+c-d*e/f;
a = b+c-d*e/f;
}
if (a == 960) {
printf("Stop timing - correct result.\n");
return 0;
}
else {
printf("INCORRECT RESULT.\n");
return -1;
}
}

View File

@ -0,0 +1,50 @@
/***************************************************************
*
* This is probably the most famous benchmark in use today.
* It tests the speed that a compiler can do logic and looping
* operations. While there are things that you can do to make
* this benchmark run faster under ORCA/C, we have not
* doctored it in any way - this is the original benchmark
* in its original form.
*
* To get the best performance from the desktop development
* environment, be sure and turn debugging off from the
* Compile Dialog. Use the Compile command from the Run menu
* to get the compile dialog.
*
***************************************************************/
#pragma keep "Prime"
#pragma optimize -1
#pragma lint -1
#include <stdio.h>
#define true 1
#define false 0
#define size 8190
char flags[size+1];
void main (void)
{
int i,prime,k,count,iter;
printf("10 iterations\n");
for (iter = 1; iter <= 10; iter++) {
count = 0;
for (i = 0; i <= size; i++)
flags[i] = true;
for (i = 0; i <= size; i++) {
if (flags[i]) {
prime = i+i+3;
/* printf("\n%d", prime); */
for (k = i+prime; k <= size; k += prime)
flags[k] = false;
count++;
}
}
}
printf("\n%d primes.", count);
}

View File

@ -0,0 +1,96 @@
/***************************************************************
*
* QuickSort
*
* Creates an array of long integers, then sorts the array.
*
* To get the best performance from the desktop development
* environment, be sure and turn debugging off from the
* Compile Dialog. Use the Compile command from the Run menu
* to get the compile dialog.
*
***************************************************************/
#pragma keep "Quick"
#pragma optimize -1
#pragma lint -1
#include <stdio.h>
#include <stdlib.h>
#define maxNum 999 /* size of array to sort - 1 */
#define count 10 /* # of iterations */
#define modulus 0x00020000 /* for random number generator */
#define c 13849
#define a 25173
typedef long arrayType[maxNum];
arrayType buffer; /* array to sort */
long seed; /* seed for random number generator */
void Quick (int lo, int hi, arrayType base)
{
int i,j;
long pivot,temp;
if (hi > lo) {
pivot = base[hi];
i = lo-1;
j = hi;
do {
do ++i; while ((base[i] < pivot) && (j > i));
if (j > i)
do --j; while ((base[j] > pivot) && (j > i));
temp = base[i];
base[i] = base[j];
base[j] = temp;
}
while (j > i);
base[j] = base[i];
base[i] = base[hi];
base[hi] = temp;
Quick(lo, i-1, base);
Quick(i+1, hi, base);
}
}
long Random (long size)
{
seed = seed*a+c;
return seed % size;
}
int main (void)
{
int i,j; /* loop variables */
int pass; /* for checking the array */
seed = 7;
printf("Filling array and sorting %d times.\n", count);
for (i = 0; i < count; ++i) {
for (j = 0; j < maxNum; ++j)
buffer[j] = labs(Random(modulus));
Quick(0, maxNum-1, buffer);
}
printf("Done.\n");
pass = 1;
for (i = 0; i < maxNum-1; ++i)
if (buffer[i] > buffer[i+1])
pass = 0;
if (pass) {
printf("The last array is sorted properly.\n");
return 0;
}
else {
printf("The last array is NOT sorted properly!\n");
return -1;
}
}

View File

@ -0,0 +1,35 @@
/***************************************************************
*
* Savage
*
* Test the speed (and stability) of floating point functions.
*
* To get the best performance from the desktop development
* environment, be sure and turn debugging off from the
* Compile Dialog. Use the Compile command from the Run menu
* to get the compile dialog.
*
****************************************************************/
#pragma keep "Savage"
#pragma optimize -1
#pragma lint -1
#define loop 250
#include <stdio.h>
#include <math.h>
int main (void)
{
int i;
double sum;
printf("Start...\n");
sum = 1.0;
for (i = 1; i < loop; ++i)
sum = tan(atan(exp(log(sqrt(sum*sum)))))+1.0;
printf("sum = %e", sum);
return 0;
}

View File

@ -0,0 +1,288 @@
/***************************************************************
*
* Calendar
*
* This classic desk accessory shows the calendar for the
* current date. The arrow keys can be used to see calendars
* for previous or future months.
*
* Commands (each is a single keystroke)
*
* up-arrow Look at the same month in the previous
* year.
* down-arrow Look at the same month in the next
* year.
* left-arrow Look at the previous month.
* right-arrow Look at the next month.
* ? or / Display help screen.
* ESC Return to CDA main menu.
*
* Mike Westerfield
*
* Copyright 1987-1989
* Byte Works, Inc.
*
***************************************************************/
#pragma keep "Calendar"
#pragma cda "Calendar" Start ShutDown
#pragma lint -1
#include <stddef.h>
#include <stdio.h>
#include <time.h>
#include <misctool.h>
#define LEFT_ARROW 0x08 /* key codes for legal commands */
#define DOWN_ARROW 0x0A
#define UP_ARROW 0x0B
#define RIGHT_ARROW 0x15
#define ESC 0x1B
#define SLASH '/'
#define QUESTION '?'
int ch; /* ord of last character read */
int month, year; /* current month and year */
/****************************************************************
*
* Factor: Computes the 'factor' for the first day of the
* month. The factor is the number of days since
* 31 Dec 0000.
*
****************************************************************/
long Factor (long year, long month)
{
if (month < 2)
return 365 * year + 1 + 31 * month + (year - 1) / 4 -
((year - 1) / 100 + 1) * 3 / 4;
return 365 * year + 1 + 31 * month - ((month + 1) * 4 + 23) / 10 +
year / 4 - (year / 100 + 1) * 3 / 4;
}
/****************************************************************
*
* GetKey: Returns the ordinal value of the next key typed
* by the user.
*
****************************************************************/
int GetKey (void)
{
char ch, *cp;
cp = (char *) 0x00C000; /* wait for keypress */
while ((*cp & 0x80) == 0) ;
ch = *cp; /* save the key */
cp = (char *) 0x00C010; /* clear the strobe */
*cp = 0;
return ch & 0x7F; /* return the key read */
}
/****************************************************************
*
* GetThisMonth: Reads the clock to obtain today's month
*
****************************************************************/
void GetThisMonth (void)
{
time_t lt; /* encoded time */
struct tm *ct; /* current time */
lt = time(NULL); /* get the coded time */
ct = gmtime(&lt); /* convert to a decoded time */
year = ct->tm_year + 1900; /* set the month/year */
month = ct->tm_mon;
}
/****************************************************************
*
* GotoXY: Positions the cursor
*
****************************************************************/
void GotoXY (int x, int y)
{
putchar(0x1E);
putchar(0x20 + x);
putchar(0x20 + y);
}
/****************************************************************
*
* PrintCalendar: Prints the calendar for the current
* and year.
*
****************************************************************/
void PrintCalendar (void)
{
#define TAB 26 /* disp of calendar from left edge */
#define VTAB 5 /* disp of calendar from top */
int startDay, /* day of week for 1st day in month */
numDays, /* # days in the month */
nextMonth, nextYear, /* work variables */
i, /* loop variable */
vt, /* line # for next line of days */
pos; /* day position for next date */
/* Compute day of week for 1st day in month */
startDay = (int) ((Factor (year, month) - 1) % 7);
nextMonth = month+1; /* compute # days in month */
if (nextMonth == 12) {
nextMonth = 0;
nextYear = year+1;
}
else
nextYear = year;
numDays = (int) (Factor (nextYear, nextMonth) - Factor (year, month));
putchar(12); /* clear the screen */
GotoXY(TAB+7, VTAB); /* position cursor */
switch (month) { /* write the month */
case 0: printf(" January "); break;
case 1: printf("February "); break;
case 2: printf(" March "); break;
case 3: printf(" April "); break;
case 4: printf(" May "); break;
case 5: printf(" June "); break;
case 6: printf(" July "); break;
case 7: printf(" August "); break;
case 8: printf("September "); break;
case 9: printf(" October "); break;
case 10: printf("November "); break;
case 11: printf("December ");
}
printf("%d", year); /* write the year */
GotoXY(TAB, VTAB+2); /* write the day header line */
printf("Sun Mon Tue Wed Thu Fri Sat");
vt = VTAB+4; /* set current date line */
pos = 0; /* set day position */
GotoXY(TAB-1, vt); /* position cursor for 1st line */
for (i = 1; i <= startDay; i++) { /* skip over blank days */
pos++;
printf(" ");
}
/* Write the dates */
for (i = 1; i <= numDays; i++) {
printf("%4d", i);
pos++;
if (pos == 7) {
pos = 0;
vt += 2;
GotoXY(TAB-1, vt);
}
}
GotoXY(25, 23); /* write instructions */
printf("Hit ? for help, or ESC to quit");
}
/****************************************************************
*
* PrintHelp: Print the help screen.
*
****************************************************************/
void PrintHelp (void)
{
int ch; /* dummy variable for reading keyboard */
putchar(0x0C); /* clear screen */
printf( "This program recognizes the following single-keystroke commands:"
"\n\n"
" key action\n"
" --- ------\n"
" up-arrow Show the current month in the previous year.\n"
" down-arrow Show the current month in the next year.\n"
" left-arrow Show the previous month.\n"
" right-arrow Show the next month.\n"
" ESC exit the program.");
GotoXY(0, 23);
printf("Hit any key to return to the program.");
ch = GetKey();
}
/**************************************************************
*
* Start: Body of calendar program
*
**************************************************************/
void Start(void)
{
putchar('\006'); /* turn the cursor off */
GetThisMonth(); /* find out what month it is */
PrintCalendar(); /* print the calendar for this month */
do {
ch = GetKey(); /* get a command */
switch (ch) {
case LEFT_ARROW: {
month--;
if (month < 0) {
month = 11;
year--;
}
PrintCalendar();
break;
}
case RIGHT_ARROW: {
month++;
if (month > 11) {
month = 0;
year++;
}
PrintCalendar();
break;
}
case UP_ARROW: {
year--;
PrintCalendar();
break;
}
case DOWN_ARROW: {
year++;
PrintCalendar();
break;
}
case QUESTION:
case SLASH: {
PrintHelp();
PrintCalendar();
break;
}
case ESC: return;
default:
SysBeep();
}
}
while (1);
}
/*************************************************************
*
* ShutDown: Does nothing
*
*************************************************************/
void ShutDown(void)
{
}

View File

@ -0,0 +1,44 @@
/****************************************************************
*
* Echo
*
* This is about the simplest a classic desk accessory can be,
* providing a quick framework for developing your own. It
* simply reads strings typed from the keyboard and echos
* them back to the screen.
*
* Mike Westerfield
*
* Copyright 1989
* Byte Works, Inc.
*
****************************************************************/
#pragma keep "Echo"
#pragma cda "Echo from C" Start ShutDown
#pragma lint -1
#include <stdio.h>
#include <string.h>
char str[256];
void Start(void)
{
printf("This program echoes the strings you type from the keyboard. To\n");
printf("quit, hit the RETURN key at the beginning of a line.\n\n");
do {
fgets(str, 256, stdin); /* read a string */
printf("%s\n", str); /* write the same string */
}
while (strlen(str) > 1); /* quit if the string is empty */
}
void ShutDown(void)
{
}

View File

@ -0,0 +1,71 @@
/****************************************************************/
/* */
/* Hello World CDev */
/* */
/* Mike Westerfield */
/* October 1991 */
/* */
/* Copyright 1991 */
/* Byte Works, Inc. */
/* All Rights Reserved. */
/* */
/****************************************************************/
/* */
/* This CDev displays a text message. It can be used as a */
/* framework for developing your own CDevs. */
/* */
/* For detailed information about CDevs, see Apple II File */
/* Type Notes for file type $D8. Apple II File Type Notes */
/* are available from major online services, large users */
/* groups, or from APDA. */
/* */
/****************************************************************/
#pragma keep "worldobj"
#pragma cdev Driver
#pragma lint -1
#include <types.h>
#include <control.h>
#include <quickdraw.h>
GrafPortPtr wPtr; /* our window pointer */
/* DoAbout - Show the help info */
void DoAbout (void)
{
NewControl2(wPtr, 0x0009, 257L); /* draw the text (it's a stattext control) */
}
/* DoCreate - Create the controls */
void DoCreate (void)
{
NewControl2(wPtr, 0x0009, 256L); /* create the controls */
}
/* Driver - main entry point */
long Driver (long data2, long data1, int message)
#define createCDev 7 /* message numbers */
#define aboutCDev 8
{
wPtr = (void *) data1; /* get our window pointer (most calls) */
switch (message) {
case createCDev: DoCreate();
break;
case aboutCDev: DoAbout();
break;
}
return 1;
}

View File

@ -0,0 +1,3 @@
cmpl +t +e -x worldcdev.cc
compile +t +e worldcdev.rez keep=WorldCDev
filetype WorldCDev $C7

View File

@ -0,0 +1,110 @@
#include "types.rez"
/* This is the required resource to tell the control panel about the CDev */
resource rCDEVFlags (0x1) {
0x00C0,
1,
1,
1,
0,
{0, 0, 110, 200},
"Hello World",
"Mike Westerfield",
"1.0"
};
/* Code resource; the executable part of the CDev */
read rCDevCode (0x1,convert) "worldobj";
/* This is the icon displayed by the control panel */
resource rIcon (0x1) {
0x8000, /* color icon */
20, /* height in pixels */
28, /* width in pixels */
$"FFFFFFFFFFF1111111FFFFFFFFFF"
$"FFFFFFFF111111111111FFFFFFFF"
$"FFFFFF1111118881111881FFFFFF"
$"FFFFF111888888888818811FFFFF"
$"FFFF11118888888888118111FFFF"
$"FFF1111111888888811111111FFF"
$"FFF1111111888888111111111FFF"
$"FF111111111881181111111111FF"
$"FF111111111181111111111111FF"
$"FF111111111181111111111111FF"
$"FF111111118888881111111111FF"
$"FF111111118888888111111111FF"
$"FFF1111111888888811111111FFF"
$"FFF1111111188888111111111FFF"
$"FFFF11111111888811111111FFFF"
$"FFFFF111111118811111111FFFFF"
$"FFFFFF1111111181111111FFFFFF"
$"FFFFFFFF111111111111FFFFFFFF"
$"FFFFFFFFFF11111111FFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFF",
$"00000000000FFFFFFF0000000000"
$"00000000FFFFFFFFFFFF00000000"
$"000000FFFFFFFFFFFFFFFF000000"
$"00000FFFFFFFFFFFFFFFFFF00000"
$"0000FFFFFFFFFFFFFFFFFFFF0000"
$"000FFFFFFFFFFFFFFFFFFFFFF000"
$"000FFFFFFFFFFFFFFFFFFFFFF000"
$"00FFFFFFFFFFFFFFFFFFFFFFFF00"
$"00FFFFFFFFFFFFFFFFFFFFFFFF00"
$"00FFFFFFFFFFFFFFFFFFFFFFFF00"
$"00FFFFFFFFFFFFFFFFFFFFFFFF00"
$"00FFFFFFFFFFFFFFFFFFFFFFFF00"
$"000FFFFFFFFFFFFFFFFFFFFFF000"
$"000FFFFFFFFFFFFFFFFFFFFFF000"
$"0000FFFFFFFFFFFFFFFFFFFF0000"
$"00000FFFFFFFFFFFFFFFFFF00000"
$"000000FFFFFFFFFFFFFFFF000000"
$"00000000FFFFFFFFFFFF00000000"
$"0000000000FFFFFFFF0000000000"
$"0000000000000000000000000000"
};
/* The following resources define the various controls in the main display */
resource rControlList (256) {
{
256,
};
};
resource rControlTemplate (256) {
0x00000001, /* control id */
{38,5,49,205}, /* control rectangle */
statTextControl {{ /* control type */
0x0000, /* flags */
0x1002, /* more flags */
0, /* ref con */
256, /* text reference */
13 /* text length */
}};
};
resource rTextForLETextBox2 (256) {
"Hello, world."
};
/* The following resources define the controls for the help screen */
resource rControlList (257) {
{
257,
};
};
resource rControlTemplate (257) {
0x00000002, /* control id */
{38,5,49,205}, /* control rectangle */
statTextControl {{ /* control type */
0x0000, /* flags */
0x1002, /* more flags */
0, /* ref con */
257, /* text reference */
19 /* text length */
}};
};
resource rTextForLETextBox2 (257) {
"Put help info here."
};

View File

@ -0,0 +1,163 @@
/**************************************************************
*
* This desk accessory brings up a simple clock. It can be
* used as an outline when creating more complex desk accessories.
*
* Original Pascal version by Phil Montoya
* C Translation by Mike Westerfield
*
* Copyright 1987,1989
* Byte Works, Inc.
*
**************************************************************/
#pragma keep "Clock"
#pragma nda Open Close Action Init 60 0xFFFF "--Clock\\H**"
#pragma lint -1
#include <stddef.h>
#include <quickdraw.h>
#include <misctool.h>
#include <event.h>
#include <desk.h>
#include <window.h>
#define TRUE 1 /* boolean constants */
#define FALSE 0
int clockActive = 0; /* are we already active flag */
GrafPortPtr clockWinPtr; /* window pointer */
char title[] = "\pClock"; /* window title */
ParamList clockWin = { /* new window record */
78, /* paramLength */
0xC0A0, /* wFrameBits */
title, /* wTitle */
0L, /* wRefCon */
{0,0,0,0}, /* wZoom */
NULL, /* wColor */
0,0, /* wYOrigin,wXOrigin */
0,0, /* wDataH,wDataW */
0,0, /* wMaxH,wMaxW */
0,0, /* wScrollVer,wScrollHor */
0,0, /* wPageVer,wPageHor */
0, /* wInfoRefCon */
0, /* wInfoHeight */
NULL, /* wFrameDefProc */
NULL, /* wInfoDefProc */
NULL, /* wContDefProc */
{50,50,62,200}, /* wPosition */
(void *) -1L, /* wPlane */
NULL /* wStorage */
};
/***************************************************************
*
* DrawTime - Reads the time and draws it in the window
*
***************************************************************/
void DrawTime (void)
{
int i; /* index variable */
char timeString[21]; /* string to hold time */
ReadAsciiTime(timeString);
timeString[20] = 0;
for (i = 0; i < 20; i++)
timeString[i] &= 0x7F;
MoveTo(7, 10);
DrawCString(timeString);
}
/***************************************************************
*
* Open - opens the desk accessory if it is not already active
*
* Outputs:
* GrafPortPtr - pointer to desk accessory window
*
***************************************************************/
GrafPortPtr Open (void)
{
if (!clockActive) {
clockWinPtr = NewWindow(&clockWin); /* open a window */
SetSysWindow(clockWinPtr); /* set it to the system window */
clockActive = TRUE; /* we are now active */
return clockWinPtr; /* return our window pointer */
}
}
/***************************************************************
*
* Close - closes the desk accessory if it is active
*
***************************************************************/
void Close(void)
{
if (clockActive) {
CloseWindow(clockWinPtr);
clockActive = FALSE;
}
}
/***************************************************************
*
* Action - Handle an action call
*
***************************************************************/
void Action (long param, int code)
{
EventRecordPtr evPtr;
GrafPortPtr currPort;
switch (code) {
case eventAction: {
evPtr = (EventRecordPtr) param;
if (evPtr->what == updateEvt) {
BeginUpdate(clockWinPtr);
DrawTime();
EndUpdate(clockWinPtr);
}
return;
}
case runAction: {
currPort = GetPort();
SetPort(clockWinPtr);
DrawTime();
SetPort(currPort);
return;
}
default:
return;
}
}
/***************************************************************
*
* Initialization
*
***************************************************************/
void Init(int code)
{
if (code == 0) {
if (clockActive)
Close();
}
else
clockActive = FALSE;
}

View File

@ -0,0 +1,199 @@
/****************************************************************
*
* Frame
*
* This desktop program is about as simple as they get. It
* brings up the Apple menu, a file menu with Quit and Close,
* and an edit menu with Undo, Cut, Copy, Paste and Clear.
* This is the minimum configuration for supporting desk
* accessories. (All of these menus have pre-assigned numbers,
* assigned by Apple.)
*
* The purpose of this rather simple program is to show how
* easy a desktop program can be to write, and to give you a
* framework to use in developing your own programs.
*
* Mike Westerfield
*
* Copyright 1989
* Byte Works, Inc.
*
****************************************************************/
#pragma keep "Frame"
#pragma lint -1
#include <orca.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <types.h>
#include <quickdraw.h>
#include <misctool.h>
#include <event.h>
#include <control.h>
#include <window.h>
#include <menu.h>
#include <desk.h>
#include <lineedit.h>
#include <dialog.h>
#define apple_About 257 /* Menu ID numbers */
#define file_Quit 256
enum alertKind {norml, stop, note, caution}; /* kinds of alerts */
typedef int BOOL; /* simulate boolean types */
BOOL done; /* tells if the program should stop */
WmTaskRec lastEvent; /* last event returned in event loop */
/****************************************************************
*
* DoAlert - Create an alert box
*
* Input:
* kind - kind of alert
* msg - alert message
*
****************************************************************/
void DoAlert (enum alertKind kind, char *msg)
{
static ItemTemplate button = /* button item */
{ 1, 36, 15, 0, 0, buttonItem, "\pOK", 0, 0, NULL };
static ItemTemplate message = /* message item */
{ 100, 5, 100, 90, 280, itemDisable+statText, NULL, 0, 0, NULL };
static AlertTemplate alertRec = /* alert box */
{ 50, 180, 107, 460, 2, 0x80, 0x80, 0x80, 0x80, NULL, NULL, NULL };
SetForeColor (0); /* set text colors */
SetBackColor (15);
message.itemDescr = msg; /* init. non-constant */
alertRec.atItemList [0] = (ItemTempPtr) &button; /* template fields */
alertRec.atItemList [1] = (ItemTempPtr) &message;
switch (kind) {
case norml: Alert (&alertRec, NULL);
break;
case stop: StopAlert (&alertRec, NULL);
break;
case note: NoteAlert (&alertRec, NULL);
break;
case caution: CautionAlert (&alertRec, NULL);
break;
default: printf ("Error in DoAlert\n");
exit (-1);
break;
}
}
/****************************************************************
*
* MenuAbout - Create the About menu
*
****************************************************************/
void MenuAbout (void)
{
DoAlert (note, "\pFrame 1.0\r"
"Copyright 1989\r"
"Byte Works, Inc.\r\r"
"By Mike Westerfield");
}
/****************************************************************
*
* HandleMenu - Handle a menu selection
*
****************************************************************/
void HandleMenu (int menuNum)
{
switch (menuNum) {
case apple_About: MenuAbout ();
break;
case file_Quit: done = TRUE;
break;
default: break;
}
HiliteMenu (FALSE, (int) (lastEvent.wmTaskData >> 16));
}
/****************************************************************
*
* InitMenus - Initialize the menu bar
*
****************************************************************/
void InitMenus (void)
{
InsertMenu (NewMenu (">> Edit \\N3\r" /* create the edit menu */
"--Undo\\N250V*Zz\r"
"--Cut\\N251*Xx\r"
"--Copy\\N252*Cc\r"
"--Paste\\N253*Vv\r"
"--Clear\\N254\r"
".\r"), 0);
InsertMenu (NewMenu (">> File \\N2\r" /* create the file menu */
"--Close\\N255V\r"
"--Quit\\N256*Qq\r"
".\r"), 0);
InsertMenu (NewMenu (">>@\\XN1\r" /* create the Apple menu */
"--About Frame\\N257V\r"
".\r"), 0);
FixAppleMenu (1); /* add desk accessories */
FixMenuBar (); /* draw the completed menu bar */
DrawMenuBar ();
}
/****************************************************************
*
* Main Program
*
****************************************************************/
int main (void)
{
int event; /* event # returned by TaskMaster */
startdesk (640);
InitMenus (); /* set up the menu bar */
lastEvent.wmTaskMask = 0x1FFFL; /* let Task Master do most stuff */
ShowCursor (); /* show the cursor */
done = FALSE; /* main event loop */
do {
event = TaskMaster (0x076E, &lastEvent);
switch (event) { /* handle the events we need to */
case wInSpecial:
case wInMenuBar: HandleMenu ((int) lastEvent.wmTaskData);
default: break;
}
}
while (!done);
enddesk ();
}

View File

@ -0,0 +1,374 @@
/****************************************************************
*
* MiniCAD
*
* MiniCAD is a (very) simple CAD program based on the Frame
* program. With MiniCAD, you can open new windows, close
* windows that are on the desktop, and draw lines using the
* mouse. Multiple windows are supported.
*
* Mike Westerfield
*
* Copyright 1989
* Byte Works, Inc.
*
****************************************************************/
#pragma keep "MiniCAD"
#pragma lint -1
#include <orca.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <types.h>
#include <quickdraw.h>
#include <misctool.h>
#include <event.h>
#include <control.h>
#include <window.h>
#include <menu.h>
#include <desk.h>
#include <lineedit.h>
#include <dialog.h>
#define apple_About 257 /* Menu ID #s */
#define file_Quit 256
#define file_New 258
#define file_Close 255
#define maxWindows 4 /* max # of drawing windows */
#define maxLines 50 /* max # of lines in a window */
typedef int BOOL; /* simulate boolean types */
typedef struct { Point p1, p2; } lineRecord; /* line defined by its endpts */
/* holds info about 1 window */
struct windowRecord { GrafPortPtr wPtr; /* ptr to the window's port */
char *name; /* name of the window */
int numLines; /* # lines in this window */
lineRecord lines [maxLines]; /* lines in drawing */
};
enum alertKind {norml, stop, note, caution}; /* kinds of alerts */
BOOL done; /* tells if the program should stop */
WmTaskRec lastEvent; /* last event returned in event loop */
static struct windowRecord windows [maxWindows] = /* drawing windows */
{ { NULL, "\pPaint 1" }, { NULL, "\pPaint 2" },
{ NULL, "\pPaint 3" }, { NULL, "\pPaint 4" } };
static ParamList wParms = /* parameters for NewWindow */
{ 78, 0xDDA7, NULL, 0, 0, 615, 25, 188, NULL, 0, 0, 0, 0, 0, 0, 10, 10,
0, 0, 0, 0, NULL, NULL, NULL, 25, 0, 188, 615, NULL, NULL };
static ItemTemplate button = /* button item */
{ 1, 36, 15, 0, 0, buttonItem, "\pOK", 0, 0, NULL };
static ItemTemplate message = /* message item */
{ 100, 5, 100, 90, 280, itemDisable+statText, NULL, 0, 0, NULL };
static AlertTemplate alertRec = /* alert box */
{ 50, 180, 107, 460, 2, 0x80, 0x80, 0x80, 0x80, NULL, NULL, NULL };
/****************************************************************
*
* DoAlert - Create an alert box
*
* Input:
* kind - kind of alert
* msg - alert message
*
****************************************************************/
void DoAlert (enum alertKind kind, char *msg)
{
SetForeColor (0); /* set text colors */
SetBackColor (15);
message.itemDescr = msg; /* init. non-constant */
alertRec.atItemList [0] = (ItemTempPtr) &button; /* template fields */
alertRec.atItemList [1] = (ItemTempPtr) &message;
switch (kind) {
case norml: Alert (&alertRec, NULL);
break;
case stop: StopAlert (&alertRec, NULL);
break;
case note: NoteAlert (&alertRec, NULL);
break;
case caution: CautionAlert (&alertRec, NULL);
break;
default: printf ("Error in DoAlert\n");
exit (-1);
break;
}
}
#pragma databank 1
/****************************************************************
*
* DrawWindow - Draw the contents of the current window
*
****************************************************************/
void DrawWindow (void)
{
int i; /* window's index */
int j; /* loop variable */
struct windowRecord *wp; /* work pointers */
lineRecord *lp;
i = GetWRefCon (GetPort());
if (windows [i].numLines) { /* skip the work if there */
/* aren't any lines */
SetPenMode (modeCopy); /* set up to draw */
SetSolidPenPat (0);
SetPenSize (2, 1);
wp = &windows [i]; /* draw each of the lines */
for (j = 0; j < wp->numLines; ++j) {
lp = &(wp->lines [j]);
MoveTo (lp->p1.h, lp->p1.v);
LineTo (lp->p2.h, lp->p2.v);
}
}
}
#pragma databank 0
/****************************************************************
*
* DoClose - Close the front drawing window, if there is one
*
****************************************************************/
void DoClose (void)
{
int i;
if (FrontWindow () != NULL) {
i = GetWRefCon (FrontWindow ());
CloseWindow (windows [i].wPtr);
windows [i].wPtr = NULL;
EnableMItem (file_New);
}
}
/****************************************************************
*
* MenuAbout - Create the About alert box
*
****************************************************************/
void MenuAbout (void)
{
DoAlert (note, "\pMini-CAD 1.0\r"
"Copyright 1989\r"
"Byte Works, Inc.\r\r"
"By Mike Westerfield");
}
/****************************************************************
*
* DoNew - Open a new drawing window
*
****************************************************************/
void DoNew (void)
{
int i; /* index variable */
i = 0; /* find an empty record */
while (windows[i].wPtr != NULL)
++i;
windows[i].numLines = 0; /* no lines drawn yet */
wParms.wTitle = (Pointer) windows[i].name; /* init. non-constant */
wParms.wRefCon = i; /* wParms fields */
wParms.wContDefProc = (VoidProcPtr) DrawWindow;
wParms.wPlane = (GrafPortPtr) topMost;
windows[i].wPtr = NewWindow (&wParms); /* open the window */
if (toolerror()) {
DoAlert (stop, "\pError opening the window.");
windows [i].wPtr = NULL;
}
else if (i == 3) /* don't allow more than 4 open windows */
DisableMItem (file_New);
}
/****************************************************************
*
* HandleMenu - Handle a menu selection
*
****************************************************************/
void HandleMenu (int menuNum)
{
switch (menuNum) {
case apple_About: MenuAbout();
break;
case file_Quit: done = TRUE;
break;
case file_New: DoNew ();
break;
case file_Close: DoClose ();
}
HiliteMenu (FALSE, (int) (lastEvent.wmTaskData >> 16));
}
/****************************************************************
*
* InitMenus - Initialize the menu bar
*
****************************************************************/
void InitMenus (void)
{
InsertMenu (NewMenu (">> Edit \\N3\r" /* create the edit menu */
"--Undo\\N250V*Zz\r"
"--Cut\\N251*Xx\r"
"--Copy\\N252*Cc\r"
"--Paste\\N253*Vv\r"
"--Clear\\N254\r"
".\r"), 0);
InsertMenu (NewMenu (">> File \\N2\r" /* create the file menu */
"--New\\N258*Nn\r"
"--Close\\N255V\r"
"--Quit\\N256*Qq\r"
".\r"), 0);
InsertMenu (NewMenu (">>@\\XN1\r" /* create the Apple menu */
"--About...\\N257V\r"
".\r"), 0);
FixAppleMenu (1); /* add desk accessories */
FixMenuBar (); /* draw the completed menu bar */
DrawMenuBar ();
}
/****************************************************************
*
* Sketch - Track the mouse, drawing lines to connect the points
*
****************************************************************/
void Sketch (void)
{
Point endPoint; /* the end point of the line */
Point firstPoint; /* the initial point */
int i; /* window index */
int numLines; /* copy of windows [i].numLines */
EventRecord sEvent; /* last event returned in event loop */
/* get the window's index */
i = GetWRefCon (FrontWindow());
/* check for too many lines */
if (windows [i].numLines == maxLines)
DoAlert (stop, "\pThe window is full -\rmore lines cannot be\radded.");
else {
/* initialize the pen */
StartDrawing (FrontWindow());
SetSolidPenPat (15);
SetPenSize (2, 1);
SetPenMode (modeXOR);
/* record the initial pen location */
firstPoint = lastEvent.where;
GlobalToLocal (&firstPoint);
MoveTo (firstPoint.h, firstPoint.v);
LineTo (firstPoint.h, firstPoint.v);
endPoint = firstPoint;
/* follow the pen, rubber-banding the line */
while (!GetNextEvent (mUpMask, &sEvent)) {
GlobalToLocal (&sEvent.where);
if ((endPoint.h != sEvent.where.h) || (endPoint.v != sEvent.where.v)) {
MoveTo (firstPoint.h, firstPoint.v);
LineTo (endPoint.h, endPoint.v);
MoveTo (firstPoint.h, firstPoint.v);
LineTo (sEvent.where.h, sEvent.where.v);
endPoint.h = sEvent.where.h;
endPoint.v = sEvent.where.v;
}
}
/* erase the last XORed line */
MoveTo (firstPoint.h, firstPoint.v);
LineTo (endPoint.h, endPoint.v);
/* if we have a line (not a point), record it in window's line list */
if ((firstPoint.h != endPoint.h) || (firstPoint.v != endPoint.v)) {
numLines = windows[i].numLines++;
windows [i].lines [numLines].p1 = firstPoint;
windows [i].lines [numLines].p2 = endPoint;
SetPenMode (modeCopy);
SetSolidPenPat (0);
MoveTo (firstPoint.h, firstPoint.v);
LineTo (endPoint.h, endPoint.v);
}
}
}
/****************************************************************
*
* Program begins here
*
****************************************************************/
int main (void)
{
int event; /* event #; returned by TaskMaster */
startdesk (640);
InitMenus (); /* set up the menu bar */
lastEvent.wmTaskMask = 0x1FFFL; /* let task master do most stuff */
ShowCursor (); /* show the cursor */
done = FALSE; /* main event loop */
do {
event = TaskMaster (0x076E, &lastEvent);
switch (event) { /* handle the events we need to */
case wInSpecial:
case wInMenuBar: HandleMenu ((int) lastEvent.wmTaskData);
break;
case wInGoAway : DoClose ();
break;
case wInContent: Sketch ();
}
}
while (!done);
enddesk ();
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,167 @@
/****************************************************************
*
* A simple graphics demo.
*
* By Phil Montoya and Barbara Allred
*
* Copyright 1987-1989
* Byte Works, Inc.
*
****************************************************************/
#pragma keep "Bounce"
#pragma lint -1
#include <quickdraw.h>
#include <orca.h>
#define screenMode 640 /* 640x200 graphics Super HiRes display mode */
#define copyMode 0 /* pen copy mode */
#define size 6 /* number of points */
/* Global variables */
static int curColor = white; /* pen color */
static int curSize = 1; /* no. points-1 */
static int x[size]; /* initial points */
static int y[size];
static int xv[size], yv[size]; /* move and velocity arrays */
static int maxX, maxY; /* max X, Y coordinates */
static int minX, minY; /* min X, Y coordinates */
static Rect r; /* drawing rectangle */
/****************************************************************
*
* UpDate - Updates x and y by velocity factors and changes
* direction if necessary
*
* Inputs:
* px - X location
* pxv - X velocity
* py - Y location
* pyv - Y velocity
*
****************************************************************/
void UpDate (int *px, int *pxv, int *py, int *pyv)
{
*px += *pxv; /* move x by velocity factor */
if ((*px < minX) || (*px > maxX)) { /* if x is beyond border... */
*px -= *pxv; /* ...move back */
*pxv = -(*pxv); /* ...change directions */
}
*py += *pyv; /* move y by velocity factor */
if ((*py < minY) || (*py > maxY)) { /* if y is beyond border... */
*py -= *pyv; /* ...move back */
*pyv = -(*pyv); /* ...change directions */
}
}
/****************************************************************
*
* NextPenColor - Changes the pen color
*
****************************************************************/
void NextPenColor (void)
{
curColor++; /* get next color */
if (curColor > white) /* if out of colors then start over */
curColor = black;
SetSolidPenPat(curColor); /* set the pen to this color */
}
/****************************************************************
*
* Initialize - initialization for program
*
****************************************************************/
void Initialize (void)
{
int i, j;
SetPenSize(4, 2); /* use a fatter pen */
SetPenMode(copyMode); /* use the copy pen mode */
GetPortRect(&r);
maxX = r.h2; maxY = r.v2; /* don't go beyond screen edges */
minX = r.h1; minY = r.v1;
i = maxX - minX; /* set initial points */
j = maxX >> 1;
x[0] = minX + j + 20; x[1] = minX + j - 20;
x[2] = x[3] = x[4] = x[5] = minX + j;
i = maxY - minY;
j = maxY >> 1;
y[3] = minY + j + 10; y[4] = minY + j - 10;
y[0] = y[1] = y[2] = y[5] = minY + j;
for (i = 0, j = 6; i < size; i++) { /* set velocity factors */
if (i & 0x0001) /* if i is odd... */
j = -j;
yv [i] = j;
xv [i] = -j;
j -= 2;
}
}
/****************************************************************
*
* DrawShapes - This is the engine of the demo.
*
****************************************************************/
void DrawShapes (void)
{
int i, j, k;
for (k = white; k >= black; k--) { /* cycle thru 16 screens */
SetSolidPenPat(k); /* set the background color */
PaintRect(&r);
/* The number of shapes per screen depends on the size of the shape. */
/* The more points a shape has the less times it will be drawn and */
/* vice-versa. This keeps the time and density per screen approximately */
/* the same. */
for (i = 0; i < (((size-curSize) * 38) + 75); i++) {
/* draw this series of shapes */
NextPenColor (); /* change pen colors */
MoveTo (x[curSize], y[curSize]); /* initial from position */
UpDate (x+curSize, xv+curSize, y+curSize, yv+curSize);
for (j = 0; j < curSize; j++) { /* draw this shape */
LineTo (x[j], y[j]);
UpDate (x+j, xv+j, y+j, yv+j);
}
}
curSize++; /* next shape size */
if (curSize == size)
curSize = 1;
}
}
/****************************************************************
*
* Program Begins Here
*
****************************************************************/
int main (void)
{
startgraph(screenMode); /* set up graphics screen */
Initialize(); /* initialize global data */
DrawShapes(); /* draw the shapes */
endgraph(); /* shut down the graphics screen */
return 0;
}

View File

@ -0,0 +1,94 @@
/*****************************************************************
*
* Call GS/OS
*
* This program shows how to call GS/OS directly. You should
* compare it with callp16.cc, which shows how to call ProDOS 16
* (an older operating system that is now a subset of GS/OS).
*
* This program dumps the contents of a screen image file to the
* graphics screen. It is assumed that the program callp16 was
* executed prior to running this program, and that you have
* made a note of the filename containing the screen dump that
* was created by callp16.
*
* DO NOT EXECUTE THIS PROGRAM FROM THE DESKTOP. It uses non-
* standard mechanisms for accessing the graphics screen.
*
* By Barbara Allred and Mike Westerfield
*
* Copyright 1989
* Byte Works, Inc.
*
*******************************************************************/
#pragma keep "CallGSOS"
#pragma debug 1 /* check stack overflows */
#pragma lint -1
#include <types.h>
#include <stdlib.h>
#include <orca.h>
#include <quickdraw.h>
#include <gsos.h>
#include <stdio.h>
#include <string.h>
#define SCREENWIDTH 320 /* screen width in pixels */
static GSString255 filename; /* name of file having screen contents */
/* Data Control Blocks for GS/OS calls */
OpenRecGS openDCB = { 15, 0, NULL, 1, 0};
IORecGS readDCB = { 5, 0, (void *) 0x00E12000, 32768L, 0L, 0 };
RefNumRecGS closeDCB = { 1, 0 };
int main (void)
{
char *str;
int i;
/* Prompt user for the name of the file to load. */
printf ("Please enter the name of the file containing the screen image:\n");
scanf ("%s", filename.text);
filename.length = strlen(filename.text);
/* Initialize the pen and graphics screen. */
startgraph(SCREENWIDTH); /* start QuickDraw II */
SetPenSize(4, 2); /* use fatter pen */
/* Open the file and then write its contents to the graphics screen. */
openDCB.pathname = &filename; /* open the file */
OpenGS(&openDCB);
if (i = toolerror()) {
MoveTo(50, 100);
SetSolidPenPat(black);
sprintf(str, "Unable to open file for screen dump: err = %d\n", i);
DrawCString(str);
goto Fail;
}
readDCB.refNum = openDCB.refNum; /* read the file, sending */
ReadGS(&readDCB); /* contents to screen */
if (i = toolerror()) {
MoveTo(50, 100);
SetSolidPenPat(black);
sprintf(str, "Unable to read file for screen dump: err = %d\n", i);
DrawCString(str);
goto Fail;
}
closeDCB.refNum = openDCB.refNum; /* close the file */
CloseGS (&closeDCB);
/* Wrap up: Wait for user to signal end, then shut down tools started. */
Fail:
SetSolidPenPat(black); /* wait for user to signal end */
str = "Press RETURN when ready to quit program";
MoveTo(SCREENWIDTH-CStringWidth(str), 40);
DrawCString(str);
getchar(); getchar();
endgraph();
return 0;
}

View File

@ -0,0 +1,121 @@
/*****************************************************************
*
* Call ProDOS 16
*
* This program draws ovals on the 16 color screen. It then
* dumps the contents of the graphics screen to a file. If the
* file is loaded and then stored to the graphics screen, the
* image dumped is displayed.
*
* DO NOT EXECUTE THIS PROGRAM FROM THE DESKTOP. It uses non-
* standard mechanisms for accessing the graphics screen.
*
* By Barbara Allred and Mike Westerfield
*
* Copyright 1989
* Byte Works, Inc.
*
*******************************************************************/
#pragma keep "CallP16"
#pragma debug 1 /* check stack overflows */
#include <prodos.h>
#pragma lint -1
#include <quickdraw.h>
#include <stdio.h>
#include <string.h>
#include <orca.h>
Rect ovalRect, *ovalPtr = &ovalRect; /* bounds rectangle for ovals */
/* Data Control Blocks for ProDOS 16 calls */
FileRec createDCB = { NULL, 0x00E3, 0x06, 0, 0x01, 0, 0 };
OpenRec openDCB;
FileIORec writeDCB;
int main (void)
{
#define SCREENWIDTH 320 /* screen width in pixels */
int x = 40; /* horizontal location in global coords */
int y = 20; /* vertical location in global coords */
int color; /* initial pen color */
char *str; /* work pointer */
char filename [L_tmpnam+1] = ""; /* name of file receiving screen dump */
char *fn;
/* Start Quick Draw II */
startgraph(SCREENWIDTH);
SetPenSize(4, 2); /* use fatter pen */
/* Draw ovals in different colors on the screen. */
for (color = 0; color < 15; color++) {
ovalRect.v1 = x; ovalRect.h1 = y;
ovalRect.v2 = x + 15; ovalRect.h2 = y + 15;
SetSolidPenPat(color+1);
MoveTo(y, x);
PaintOval(ovalPtr);
SetSolidPenPat(color);
MoveTo(y, x);
FrameOval(ovalPtr);
if (toolerror()) {
DrawCString("Failure in drawing routine\n");
goto Fail;
}
y += 10; x += 10;
}
/* Dump contents of screen to a file. */
fn = tmpnam(&filename[1]); /* get unique filename for dump */
if (fn == NULL) {
MoveTo (100, 50);
SetSolidPenPat(black);
DrawCString("Unable to obtain unique filename for screen dump");
goto Fail;
}
filename[0] = strlen(&filename[1]); /* convert C-string to P-string */
createDCB.pathname = filename; /* create screen dump file */
CREATE(&createDCB);
if (toolerror()) {
MoveTo(50, 100);
SetSolidPenPat(black);
DrawCString("Unable to create file for screen dump");
goto Fail;
}
openDCB.openPathname = filename; /* open the screen dump file */
OPEN(&openDCB);
if (toolerror()) {
MoveTo(50, 100);
SetSolidPenPat(black);
DrawCString("Unable to open file for screen dump");
goto Fail;
}
writeDCB.fileRefNum = openDCB.openRefNum; /* write screen contents to file */
writeDCB.dataBuffer = (void *) 0x00E12000;
writeDCB.requestCount = 32768L;
WRITE(&writeDCB);
if (toolerror()) {
MoveTo(50, 100);
SetSolidPenPat(black);
DrawCString("Unable to write screen contents to file");
goto Fail;
}
CLOSE(&openDCB); /* close the screen dump file */
/* Wrap up: Wait for key press and then shut down QuickDraw II. */
Fail:
SetSolidPenPat(black); /* wait for user to signal end */
str = "Press return when ready to quit program";
MoveTo(SCREENWIDTH-CStringWidth(str), 40);
DrawCString(str);
getchar();
endgraph();
printf("The name of the file containing the screen dump is:\n%b", filename);
}

View File

@ -0,0 +1,73 @@
/****************************************************************
*
* Pipe
*
* A simple graphics demo.
*
* by Mike Westerfield
*
* Copyright 1987-1989
* Byte Works, Inc.
*
****************************************************************/
#pragma keep "Pipe"
#pragma lint -1
#include <quickdraw.h>
#define xWidth 20
#define yWidth 10
int main (void)
{
Rect r; /* drawing rectangle */
int x = xWidth; /* horizontal width of pipe */
int y = yWidth; /* vertical width of pipe */
int color = 1; /* pen color */
int maxX; /* maximum horizontal pixel */
int maxY; /* maximum vertical pixel */
int minX; /* minimum horizontal pixel */
int minY; /* minimum vertical pixel */
int deltaX = 6; /* pipe width increment */
int deltaY = 3; /* pipe depth increment */
int i;
GetPortRect(&r); /* initialize drawing rectangle */
maxX = r.h2 - xWidth; /* don't go beyond rect edges */
maxY = r.v2 - yWidth;
minX = r.v1;
minY = r.h1;
for (i = 0; i < 150; ++i) { /* main loop: draw pipe, a series of ovals */
r.h1 = x - xWidth;
r.h2 = x + xWidth;
r.v1 = y - yWidth;
r.v2 = y + yWidth;
color ^= 3;
SetSolidPenPat(color);
PaintOval(&r);
SetSolidPenPat(0);
FrameOval(&r);
x += deltaX; /* bend pipe as needed to fit within rectangle */
if (x < xWidth) {
x = xWidth;
deltaX = -deltaX;
}
else if (x > maxX) {
x = maxX;
deltaX = -deltaX;
}
y += deltaY;
if (y < yWidth) {
y = yWidth;
deltaY = -deltaY;
}
else if (y > maxY) {
y = maxY;
deltaY = -deltaY;
}
}
}

View File

@ -0,0 +1,45 @@
/****************************************************************
*
* Spiral
*
* A simple graphics demo. Uses the shell STOP command from the
* debug menu to stop the program early.
*
* by Mike Westerfield
*
* Copyright 1989
* Byte Works, Inc.
*
****************************************************************/
#pragma keep "Spiral"
#pragma lint -1
#include <quickdraw.h>
#include <math.h>
int main (void)
{
float r, theta, rot;
int color = 1;
Rect rect;
GetPortRect(&rect);
SetPenSize(3, 1);
for (rot = 0.0002; rot < 0.0005; rot += 0.0001) {
theta = 0.0;
r = 40.0;
MoveTo ((int) (cos (theta) * r * 3) + 160,
(int) (sin (theta) * r) + 40);
while (r > 0.0) {
SetSolidPenPat (color);
color ^= 3;
theta += 3.1415926535 / 21.0 + rot;
LineTo ((int) (cos (theta) * r * 3) + 160,
(int) (sin (theta) * r) + 40);
r -= 0.02;
}
}
Out: ;
}

View File

@ -0,0 +1,34 @@
/*****************************************************************
*
* HyperCard XCMD
*
* This sample is a framework program, showing the essential parts
* of a HyperCard XCMD.
*
* For complete details on the requirements for HyperCard XCMDs,
* see the HyperCard technical documentation on the System 6.0
* CD ROM.
*
* Build this program using the script xcmd.make. This script has
* quite a few comments about the build process, so it's worth
* loading the scrept and reading the comments.
*
* By Mike Westerfield
*
* Copyright 1993
* Byte Works, Inc.
*
*****************************************************************/
#pragma keep "xcmd"
#pragma lint -1
#pragma xcmd main
#include <HyperXCMD.h>
#include <misctool.h>
void main (XCMDPtr parm)
{
SysBeep();
}

View File

@ -0,0 +1,26 @@
*
* This file builds the sample xcmd.cc.
*
*
* There's nothing special about the compile -- just be sure the program
* itself uses the xcmd pragma, the small memory model, and does not use the
* segment directive.
*
compile xcmd.cc
*
* The -x flag is crutial! XCMDs must consist of a single segment, and
* without the -x flag on the link, the linker creates an expressload
* segment.
*
link -x xcmd keep=xcmd
*
* The Rez compiler packs the executable code and a name into a file for
* HyperCard.
*
compile xcmd.rez keep=Beep

View File

@ -0,0 +1,23 @@
/*****************************************************************
*
* HyperCard XCMD
*
* This is the resource file for xcmd.cc.
*
* By Mike Westerfield
*
* Copyright 1993
* Byte Works, Inc.
*
*****************************************************************/
#include "types.rez"
read $801E(1, convert) "xcmd";
resource rResName ($0001801E) {
1,
{
1, "Beep";
}
};

View File

@ -0,0 +1,35 @@
/*****************************************************************
*
* HyperStudio New Button Action (NBA)
*
* This sample is a framework program, showing the essential parts
* of a HyperStudio NBA.
*
* For complete details on the requirements for HyperStudio NBAs,
* contact Roger Wagner Publishing. When this sample was written,
* details for writing HyperStudio NDAs were available in disk form
* for $10.
*
* Build this program using the script xcmd.make. This script has
* quite a few comments about the build process, so it's worth
* loading the scrept and reading the comments.
*
* By Mike Westerfield
*
* Copyright 1993
* Byte Works, Inc.
*
*****************************************************************/
#pragma keep "nba"
#pragma lint -1
#pragma nba main
#include "HyperStudio.h"
#include <misctool.h>
void main (HSParamPtr parm)
{
SysBeep();
}

View File

@ -0,0 +1,27 @@
*
* This file builds the sample nba.cc.
*
*
* There's nothing special about the compile -- just be sure the program
* itself uses the nba pragma, the small memory model, and does not use the
* segment directive.
*
compile nba.cc
*
* The -x flag is crutial! NBAs must consist of a single segment, and
* without the -x flag on the link, the linker creates an expressload
* segment.
*
link -x nba keep=nba
*
* The Rez compiler packs the executable code and a name into a file for
* HyperStudio.
*
compile nba.rez keep=Beep
filetype Beep $BC $4007

View File

@ -0,0 +1,23 @@
/*****************************************************************
*
* HyperStudio NBA
*
* This is the resource file for nba.cc.
*
* By Mike Westerfield
*
* Copyright 1993
* Byte Works, Inc.
*
*****************************************************************/
#include "types.rez"
read $8017($7FF0, convert) "nba";
resource rResName ($00018017) {
1,
{
$7FF0, "Beep";
}
};

View File

@ -0,0 +1,67 @@
/*****************************************************************
*
* Ackermann
*
* This program implements a famous mathematical function that
* is often used to examine recursion. It is deceptively
* simple, but can take enormous amounts of time and stack
* space for relatively small arguments. For that reason,
* rangechecking has been enabled to ensure the integrity of the
* stack.
*
* By Mike Westerfield
*
* Copyright 1987-1989
* Byte Works, Inc.
*
*****************************************************************/
#pragma keep "Ackermann"
#pragma debug 0x0001
#pragma lint -1
#include <stdio.h>
/* Constants */
#define maxm 2 /* max value of 1st argument */
#define maxn 3 /* max value of 2nd argument */
/* Global variables */
int a, m, n, depth, maxdepth;
/****************************************************************
*
* Ackermann - Demonstrates recursion in ORCA/C
*
****************************************************************/
int Ackermann (int m, int n)
{
int result;
depth++;
if (depth > maxdepth)
maxdepth = depth;
if (m == 0)
return (n + 1);
if (n == 0)
return (Ackermann (m-1, 1));
result = Ackermann (m-1, Ackermann (m, n-1));
depth--;
return result;
}
int main (void)
{
for (m = 0; m <= maxm; m++)
for (n = 0; n <= maxn; n++) {
depth = 0;
maxdepth = 0;
a = Ackermann (m, n);
printf ("Ackermann(%d, %d) = %-4d ", m, n, a);
printf ("Max recursion depth was %d\n", maxdepth);
}
}

View File

@ -0,0 +1,101 @@
/************************************************
*
* Artillery
*
* This classic interactive text game lets you
* pick the angle of your artillery gun in
* an attempt to knock out the enemy position.
* The computer picks a secret distance. When
* you fire, you will be told how much you
* missed by, and must fire again. The object
* is to hit the target with the fewest shells.
*
************************************************/
#pragma keep "Artillery"
#pragma lint -1
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <misctool.h>
#define FALSE 0 /* boolean constants */
#define TRUE 1
#define BLASTRADIUS 50.0 /* max distance from target for a hit */
#define DTR 0.01745329 /* convert from degrees to radians */
#define VELOCITY 434.6 /* muzzle velocity */
int main(void)
{
float angle, /* angle */
distance, /* distance to the target */
flightTime, /* time of flight */
x, /* distance to impact */
vx,vy; /* x, y velocities */
int done, /* is there a hit, yet? */
tries, /* number of shots */
i; /* loop variable */
/* choose a distance to the target */
srand((int) time(NULL));
for (i = 0; i < 100; ++i)
rand();
distance = rand()/5.55373;
/* not done yet... */
done = FALSE;
tries = 1;
/* shoot 'til we hit it */
do {
/* get the firing angle */
printf("Firing angle: ");
scanf("%f", &angle);
/* compute the muzzle velocity in x, y */
angle *= DTR;
vx = cos(angle)*VELOCITY;
vy = sin(angle)*VELOCITY;
/* find the time of flight */
/* (velocity = acceleration*flightTime, two trips) */
flightTime = 2.0*vy/32.0;
/* find the distance */
/* (distance = velocity*flightTime) */
x = vx*flightTime;
/* see what happened... */
if (fabs(distance-x) < BLASTRADIUS) {
done = TRUE;
printf("A hit, after %d", tries);
if (tries == 1)
printf(" try!\n");
else
printf(" tries!\n");
switch (tries) {
case 1:
printf("(A lucky shot...)\n");
break;
case 2:
printf("Phenomenal shooting!\n");
break;
case 3:
printf("Good shooting.\n");
break;
otherwise:
printf("Practice makes perfect - try again.\n");
}
}
else if (distance > x)
printf("You were short by %d feet.\n", (int)(distance-x));
else
printf("You were over by %d feet.\n", (int)(x-distance));
++tries;
}
while (!done);
}

View File

@ -0,0 +1,45 @@
/***************************************************************
*
* Command Line
*
* On the Apple IIgs, all EXE programs can expect three things
* to be passed to them by the shell: a user ID number for use
* with tool kits, an eight character shell ID which
* identifies the shell that executed the program, and the
* text from the command line itself. This program shows how
* to access these values from C, printing them to the
* screen. Be sure and execute the program with some text
* after the name - for example,
*
* CLINE Hello, world.
*
* When any EXE program returns to the shell, it passes an
* error code in the A register. You can set this value from
* C by returning an integer value as the result of main, as
* shown in this program.
*
* If you compile this program from the desktop, turn debug
* code off before executing the program from the shell window.
*
***************************************************************/
#pragma keep "CLine"
#pragma lint -1
#include <stdio.h>
#include <orca.h>
int main(void)
{
char *shellName, *line;
int userNumber;
userNumber = userid();
shellName = shellid();
line = commandline();
printf("User ID: %d\n", userNumber);
printf("Shell ID: %s\n", shellName);
printf("Command line: %s\n", line);
return 0;
}

View File

@ -0,0 +1,52 @@
/*******************************************************************
*
* Error Exit
*
* You can call the library routines that handle run-time errors
* from your own program. One of these, called strerror, will
* print a text run-time error message to standard output. You
* pass a single integer parameter, which is the run-time error
* number. This procedure is generally called from an error trap
* subroutine - see the sample program ERRORTRAP.CC for an example
* of how to trap errors. In this program strerror is used to
* list the current run-time error messages.
*
* The two built-in macros __FILE__ and __LINE__ are used to print
* the current line number and the name of the current source file.
*
* The library subroutine SystemErrorLocation provides trace-back
* information; it is further covered in the text sample program
* ERRORTRAP.CC.
*
* By Mike Westerfield and Barbara Allred
*
* Copyright 1987-1989
* Byte Works, Inc.
*
*********************************************************************/
#pragma keep "ErrorExit"
#pragma debug 8 /* enable trace-back of code */
#pragma lint -1
#include <string.h>
#include <errno.h>
#include <stdio.h>
extern pascal void SystemErrorLocation (void);
/* A library procedure that prints the current location and a traceback. */
int main (void)
{
int i;
printf ("Run-time error messages are:\n\n");
for (i = 1; i <= sys_nerr; i++)
printf ("%3d: %s\n", i, strerror (i));
printf ("\nCurrent line: %d\nCurrent file: %s\n", __LINE__, __FILE__);
printf ("Exiting with a traceback.\n");
SystemErrorLocation ();
}

View File

@ -0,0 +1,97 @@
/******************************************************************
*
* Error Trap
*
* You can trap run-time errors with ORCA/C. There are several
* reasons to do this, including:
*
* 1. Error messages take up space. By replacing the
* system error handler with your own, you can cut
* out the space needed to store the run-time error
* messages.
* 2. You may want to trap some kinds of run-time
* errors, like file not found or out of memory,
* and handle them yourself. If you do not, the
* error will cause the program to stop executing,
* which may not be the desired result.
*
* This program shows how to intercept and handle run-time
* errors. This is done by placing a function in your program
* called SYSTEMERROR. The function has a single parameter,
* which is an integer error number. SYSTEMERROR replaces a
* function by the same name that is normally linked in from
* the libraries. Another library function, SystemErrorLocation,
* provides the name of the function and the line number where
* the run-time error occurred.
*
* Note that if you do not want to handle a particular error,
* you can call the system error handlers from your program.
* See the sample program ERROREXIT.CC for an example.
*
* By Mike Westerfield and Barbara Allred
*
* Copyright 1987-1989
* Byte Works, Inc.
*
*******************************************************************/
#pragma keep "ErrorTrap"
#pragma debug 9 /* enable range checking + trace-back */
#pragma lint -1
#include <stdio.h>
extern pascal void SystemErrorLocation (void);
/* A library procedure that prints the current location and a traceback. */
/****************************************************************
*
* BadFunction - Subroutine that will generate a run-time error
*
****************************************************************/
static void BadFunction (void)
{
char ch [8000]; /* this array is too large for */
/* the default run-time stack */
(void)ch; /* dummy use of ch to avoid lint msg */
}
/****************************************************************
*
* DoIt - Calls function that will generate a run-time error
*
****************************************************************/
static void DoIt (void)
{
BadFunction(); /* call function with large array */
}
/****************************************************************
*
* SystemError - Replaces SYSTEMERROR function in the ORCA library
*
****************************************************************/
static void SYSTEMERROR (int errorNumber)
{
printf ("Run-time error detected. error number = %d\n", errorNumber);
}
/****************************************************************
*
* Main program starts here
*
****************************************************************/
int main(void)
{
DoIt();
SystemErrorLocation();
}

View File

@ -0,0 +1,61 @@
/************************************************
*
* Finance
*
* This program prints the balance on an
* account for monthly payments, along with the
* total amount paid so far.
*
*************************************************/
#pragma keep "Finance"
#pragma lint -1
#include <stdio.h>
#define LOANAMOUNT 10000.0 /* amount of the loan */
#define PAYMENT 600.0 /* monthly payment */
#define INTEREST 15 /* yearly interest (as %) */
int main(void)
{
float balance, /* amount left to pay */
monthlyInterest, /* multiplier for interest */
paid ; /* total amount paid */
int month; /* month number */
/* set up the initial values */
balance = LOANAMOUNT;
paid = month = 0;
monthlyInterest = 1.0 + INTEREST/1200.0;
/* write out the conditions */
printf("Payment schedule for a loan of %10.2f\n", LOANAMOUNT);
printf("with monthly payments of %5.2f at an\n", PAYMENT);
printf("interest rate of %d%%.\n\n", INTEREST);
printf(" month balance amount paid\n");
printf(" ----- ------- -----------\n");
/* check for payments that are too small */
if (balance*monthlyInterest - balance >= PAYMENT)
printf("The payment is too small!");
else
while (balance > 0) {
/* add in the interest */
balance *= monthlyInterest;
/* make a payment */
if (balance > PAYMENT) {
balance -= PAYMENT;
paid += PAYMENT;
}
else {
paid += balance;
balance = 0;
}
/* update the month number */
++month;
/* write the new statistics */
printf("%15d %14.2f %14.2f\n", month, balance, paid);
}
}

View File

@ -0,0 +1,107 @@
/*****************************************************************
*
* Keyboard Handling
*
* This program shows one way to access the keyboard directly
* from ORCA/C. Keep in mind that the standard file input
* collects an entire line of characters before reporting the
* first character. This is necessary to allow editing of the
* input line. When using the desktop environment, you can get
* keypress events from the event manager. This program shows
* how to detect a keypress as soon as it is hit. It echoes
* keys until you type CONTROL-@ (ASCII 0).
*
* The program works by reading the keyboard (at $C000) until
* the value is negative, indicating that a key has been
* pressed. It then stores a value (any value will do) in
* $C010 to indicate that the key has been read. This makes
* the value at $C010 positive (bit 7 is clear). The value of
* the key is then ANDed with $7F to clear the high bit.
*
* THIS METHOD OF READING THE KEYBOARD ONLY WORKS IN THE TEXT
* ENVIRONMENT. When the event manager is active, as it always
* is in a desktop program, you should call the event manager
* to read keystrokes.
*
* Checking to see when a key has been pressed is bundled into
* the function KeyPress. Returning the key and clearing the
* strobe is done in ReadChar.
*
* See key2 for a version that splits the keyboard routines off
* into a separately compilable module.
*
* See key3 for a version that uses assembly language to do the
* same thing.
*
* By Mike Westerfield and Barbara Allred
*
* Copyright 1987-1989
* Byte Works, Inc.
*
*******************************************************************/
#pragma keep "Key"
#pragma lint -1
#include <stdio.h>
static char ch; /* character read from keyboard */
/****************************************************************
*
* KeyPress - Check if a key has been pressed
*
****************************************************************/
int KeyPress(void)
{
char *keyboard;
keyboard = (char *) 0x00C000;
return ((*keyboard) & 0x80) != 0;
}
/****************************************************************
*
* ReadChar - Return the last character typed on the keyboard.
* Note: Returns a character whether or not one has
* been typed!
*
****************************************************************/
char ReadChar (void)
{
char *keyboard, *strobe;
keyboard = (char *) 0x00C000;
strobe = (char *) 0x00C010;
*strobe = 0;
return *keyboard & 0x7F;
}
/****************************************************************
*
* Main program starts here
*
****************************************************************/
int main(void)
{
printf ("Press any key(s) and then RETURN. Enter CTRL-@ to quit.\n");
do {
while (! KeyPress()) /* wait for a keypress */
;
ch = ReadChar(); /* get character typed from keybrd */
if (ch == 0x0D) /* write character to the screen */
printf ("\n");
else
printf ("%c", ch);
}
while (ch != 0);
return 0;
}

View File

@ -0,0 +1,20 @@
unset exit
echo compile key2.cc
compile key2.cc
if {status} == 0
echo compile key2.funcs
compile key2.funcs
if {status} == 0
echo link key2.cc key2.funcs
link key2 funcs keep=Key2
if {status} == 0
key2
else
echo Unable to link key2.cc key2.funcs
end
else
echo Unable to compile key2.funcs
end
else
echo Unable to compile key2.cc
end

View File

@ -0,0 +1,43 @@
/*****************************************************************
*
* This file contains the functions for KEY2.CC. See that file
* for detailed comments.
*
*******************************************************************/
#pragma keep "Funcs"
/****************************************************************
*
* KeyPress - Check if a key has been pressed
*
****************************************************************/
int KeyPress(void)
{
char *keyboard;
keyboard = (char *) 0x00C000;
return ((*keyboard) & 0x80) != 0;
}
/****************************************************************
*
* ReadChar - Returns the last character typed on the keyboard.
* Note: Returns a character whether or not one has
* been typed!
*
****************************************************************/
char ReadChar(void)
{
char *keyboard, *strobe;
keyboard = (char *) 0x00C000;
strobe = (char *) 0x00C010;
*strobe = 0;
return *keyboard & 0x7F;
}

View File

@ -0,0 +1,61 @@
/*****************************************************************
*
* Keyboard Handling
*
* This program demonstrates separate compilation by splitting
* the program KEY into two parts: the main program, and a
* separately compiled file with the keyboard subroutines that
* can then be called from many different programs without the
* need for recompiling. See KEY.CC for a full description of
* what this program does.
*
* The program now consists of four files:
*
* Key2.Build - EXEC file which separately compiles the two
* source files, then links their object
* modules to create the final program. To
* use the EXEC file, simply type KEY2.BUILD
* from the command line.
*
* Key2.cc - File containing main program.
*
* Key2.h - Header file accessed by the main program;
* Contains declarations of external functions.
*
* Key2.Funcs - File containing keyboard functions called
* by main program.
*
* See Key3 for a version that uses assembly language to read
* the keyboard.
*
* By Mike Westerfield and Barbara Allred
*
* Copyright 1987-1989
* Byte Works, Inc.
*
*******************************************************************/
#pragma keep "Key2"
#pragma lint -1
#include "Key2.h"
#include <stdio.h>
int main(void)
{
char ch;
printf ("Press any key(s) and then RETURN. Enter CTRL-@ to quit.\n");
do {
while (! KeyPress()) /* wait for a keypress */
;
ch = ReadChar(); /* get character typed from keybrd */
if (ch == 0x0D) /* write character to the screen */
printf ("\n");
else
printf ("%c", ch);
}
while (ch != 0);
return 0;
}

View File

@ -0,0 +1,4 @@
/* Header file for program Key2.CC */
extern int KeyPress(void);
extern char ReadChar(void);

View File

@ -0,0 +1,41 @@
****************************************************************
*
* KeyPress - Check to see if a key has been pressed
*
* Outputs:
* A - 1 (true) if pressed, else 0
*
****************************************************************
*
KeyPress start
keyBoard equ $C000 keyboard location
sep #$30 use short regs for load
lda >keyBoard load keyboard value
asl A shift sign bit into bit 0
rol A
rep #$30 back to long regs
and #1 and out all but the bit we want
rtl
end
****************************************************************
*
* ReadChar - return the last character typed on the keyboard
*
* Outputs:
* A - character typed
*
****************************************************************
*
ReadChar start
keyBoard equ $C000 keyboard location
strobe equ $C010 strobe location
sep #$30 use short regs
sta >strobe clear strobe
lda >keyBoard load character
rep #$30 back to long regs
and #$007F and out high bits
rtl
end

View File

@ -0,0 +1,64 @@
/*****************************************************************
*
* Keyboard Handling
*
* This is the final incarnation of the keyboard polling sample.
* See KEY.CC for complete comments on what the program does and
* how it works.
*
* In this version, we will write the two subroutines in
* assembly language. While you could use separate compilation
* to compile and assemble the two pieces separately, then
* link them, as in the last example, we will use chaining
* to avoid all of that. Chaining is a feature of all
* languages fully installed in ORCA or APW that allows a
* single program to be written in more than one language
* without resorting to separate compilation. Which method
* you prefer - chaining or separate compilation - depends
* on your own taste.
*
* To chain the two files together, we just place an append
* command after the end of the program. The rest is automatic
* To compile, assemble, link, and execute, we can now use the
* familiar RUN command:
*
* run key3.cc
*
* Note: both the assembler and compiler must be properly
* installed for this to work. The assembler is sold
* separately as ORCA/M 2.0 for the Apple IIGS.
*
* By Mike Westerfield and Barbara Allred
*
* Copyright 1987-1989
* Byte Works, Inc.
*
*******************************************************************/
#pragma keep "Key3"
#pragma lint -1
#include <stdio.h>
int main (void)
{
extern int KEYPRESS (void); /* declare assembly-language */
extern int READCHAR (void); /* routines to be called */
char ch; /* character read from keyboard */
printf("Press any key(s) and then RETURN. Enter CTRL-@ to quit.\n");
do {
while (! KEYPRESS()) /* wait for a keypress */
;
ch = READCHAR(); /* get character typed from keybrd */
if (ch == 0x0D) /* write character to the screen */
printf ("\n");
else
printf ("%c", ch);
}
while (ch != 0);
return 0;
}
#append "Key3.asm"

View File

@ -0,0 +1,34 @@
/*****************************************************************
*
* Text Printer Demo
*
* This example shows how to access the .PRINTER text printer
* driver from a C program. The .PRINTER driver must be installed
* before this sample is executed.
*
* There really isn't much to this sample, which may seem bad at
* first, but it's really good: accessing the text printer driver
* really is as simple as opening the printer and writing to it!
*
* By Mike Westerfield
*
* Copyright 1993
* Byte Works, Inc.
*
*****************************************************************/
#pragma keep "Print"
#pragma lint -1
#include <stdio.h>
void main (void)
{
FILE *f;
f = fopen(".printer", "w+");
fprintf(f, "Hello, printer!\n");
fputc('\f', f); /* on most printers, this will eject a page */
fclose(f);
}

View File

@ -0,0 +1,64 @@
/****************************************************************
*
* Trace
*
* ORCA/C can give you a traceback when a run-time error occurs.
* A traceback shows the function and line number where the
* error occurred, then gives a list of functions and line
* numbers that show what subroutine calls were made to get to
* the point where the error occurred. This program illustrates
* this by deliberately failing in the function named Fail.
*
* By Mike Westerfield and Barbara Allred
*
* Copyright 1987-1989
* Byte Works, Inc.
*
******************************************************************/
#pragma keep "Trace"
#pragma debug 9
#pragma lint -1
#include <stdio.h>
/****************************************************************
*
* Fail - Subroutine that will generate a run-time error
*
****************************************************************/
static void Fail (void)
{
char ch [8000]; /* this array is too large for */
/* the default run-time stack */
(void)ch; /* dummy use of ch to avoid lint msg */
}
/****************************************************************
*
* DoIt - Calls subroutine that will generate a run-time error
*
****************************************************************/
static void DoIt (void)
{
Fail();
}
/****************************************************************
*
* Main program starts here
*
****************************************************************/
int main (void)
{
printf ("This program fails. Generating a traceback:\n");
DoIt();
}

View File

@ -1,15 +1,25 @@
Welcome to ORCA/C 2.2.0 B6! This is an update release containing
patches from community members (Stephen Heumann and Kelvin Sherlock),
which fix bugs and add new features. For details on these changes,
see the cc.notes file in the Release.Notes directory.
This is an update package that can be used to update ORCA/C 2.1.0 or
2.2.0 to ORCA/C 2.2.1. You must have an existing copy of ORCA/C 2.1.0
or 2.2.0 in order to use this update. If you do not already have a
copy, you can get it as part of Opus ][: The Software, a collection of
Byte Works software which is sold by Juiced.GS:
https://juiced.gs/store/opus-ii-software/
This package is designed to be applied as an update to an existing
ORCA installation containing ORCA/C 2.1.0 or later (including the one
provided on Opus ][: The Software). To apply the update, simply copy
the files from this distribution into the corresponding locations in
your ORCA installation, replacing any older versions. (One easy way
to do this is to extract the archive containing this update directly
on top of your ORCA installation, overwriting all modified files.)
This update must be applied to an existing ORCA installation containing
ORCA/C 2.1.0 or ORCA/C 2.2.0 (including the one provided on Opus ][:
The Software). To apply the update, you just need to copy the files
from this distribution into the corresponding locations in your ORCA
installation, replacing any older versions.
If you received this update as a SHK file, you can simply extract the
files from it directly on top of your ORCA installation.
If you received this update as a disk image, you can apply the update
by copying the files into place using the Finder, or by running the
following command within the root directory of your ORCA installation
using the text-based ORCA shell:
COPY -C :ORCAC.221:=
In addition to the ORCA shell environment, this update can also be
used under other environments that are compatible with ORCA/C, such as
@ -18,20 +28,3 @@ into the directory containing files from a standard ORCA installation
(normally /lang/orca for GNO). An updated version of ORCALib suitable
for use under GNO is available as a separate download at:
https://github.com/byteworksinc/ORCALib/releases
If you have any questions, or if you want to get involved in ORCA/C
development, please get in touch. The ORCA/C development project is
hosted on GitHub, and bug reports or patches can be submitted there:
https://github.com/byteworksinc/ORCA-C
Thanks to:
* Mike Westerfield, for writing ORCA/C, releasing the source code,
and permitting it to be updated by the community.
* Kelvin Sherlock, for providing several patches and bug reports, and
for writing several useful tools for modern Apple II development.
* Soenke Behrens, for compiling a list of ORCA/C bug reports and test
cases, which has helped me to identify and fix a number of bugs.
* The developers of Csmith (http://embed.cs.utah.edu/csmith/), an
automated compiler testing tool that has helped to find several bugs.
--Stephen Heumann (stephenheumann@gmail.com)

2
CC.pas
View File

@ -140,6 +140,8 @@ DoGlobals; {create the ~GLOBALS and ~ARRAYS segment
{shut down the compiler}
TermHeader; {make sure the compiled header file is closed}
CheckStaticFunctions; {check for undefined functions}
if (lint & lintUnused) <> 0 then {check for unused static vars}
CheckUnused(globalTable);
ffDCBGS.action := 7; {purge the source file}
ffDCBGS.pcount := 14;
ffDCBGS.pathName := @includeFileGS.theString;

8
CC.rez
View File

@ -4,12 +4,12 @@ resource rVersion(1) {
{
2, /* Major revision */
2, /* Minor revision */
0, /* Bug version */
beta, /* Release stage */
6, /* Non-final release # */
1, /* Bug version */
development, /* Release stage */
1, /* Non-final release # */
},
verUS, /* Region code */
"ORCA/C", /* Short version number */
"Copyright 1997, Byte Works, Inc.\n" /* Long version number */
"Updated 2022"
"Updated 2024"
};

View File

@ -44,37 +44,43 @@ lb1 lda [fromPtr],Y
Hash start cc
hashSize equ 876 # hash buckets - 1
sum equ 0 hash
disp equ 0 disp into hash table
length equ 2 length of string
subroutine (4:sPtr),4
stz sum default to bucket 0
lda [sPtr] set the length of the string
tax
and #$00FF
sta length
ldy #1 start with char 1
lda [sPtr] if 1st char is '~', start with char 6
txa if 1st char is '~', start with char 6
and #$FF00
cmp #'~'*256
bne lb1
bne lb0
ldy #6
lb1 lda [sPtr],Y get the value to add in
and #$3F3F
cpy length if there is only 1 char left then
bne lb2
and #$00FF and out the high byte
lb2 clc add it to the sum
adc sum
sta sum
iny next char
lb0 lda #0 initial value is 0
bra lb2 while there are at least 2 chars left
lb1 asl a rotate sum left one bit
adc [sPtr],Y add in next two bytes
iny advance two chars
iny
cpy length
ble lb1
mod2 sum,#hashSize+1 return disp
asl sum
asl sum
lb2 cpy length
blt lb1
bne lb3 if there is 1 char left then
asl a rotate sum left one bit
sta disp
lda [sPtr],Y
and #$00FF and out the high byte
adc disp add last byte to the sum
sec
lb3 sbc #hashSize+1 disp := (sum mod (hashSize+1)) << 2
bcs lb3
adc #hashSize+1
asl a
asl a
sta disp
return 2:sum
return 2:disp return disp
end

View File

@ -74,6 +74,7 @@ interface
const
{hashsize appears in CCOMMON.ASM}
hashSize = 876; {# hash buckets - 1}
{NOTE: hashsize2 is used in Symbol.asm}
hashSize2 = 1753; {# hash buckets * 2 - 1}
maxLine = 255; {max length of a line}
maxPath = 255; {max length of a path name}
@ -93,6 +94,8 @@ const
lintOverflow = $0020; {check for overflows}
lintC99Syntax = $0040; {check for syntax that C99 disallows}
lintReturn = $0080; {flag issues with how functions return}
lintUnused = $0100; {check for unused variables}
lintConstantRange = $0200; {check for out-of-range constants}
{bit masks for GetLInfo flags}
{----------------------------}
@ -109,7 +112,7 @@ const
flag_t = $00001000; {treat all errors as terminal?}
flag_w = $00000200; {wait when an error is found?}
versionStr = '2.2.0 B6'; {compiler version}
versionStr = '2.2.1 dev'; {compiler version}
type
{Misc.}
@ -142,6 +145,9 @@ type
end;
gsosOutStringPtr = ^gsosOutString;
{ C language standards }
cStandardEnum = (c89,c95,c99,c11,c17,c23);
{ The base types include two main categories. The values starting }
{ with cg are defined in the code generator, and may be passed to the }
{ code generator for resolution. The cc types are used internally in }
@ -195,10 +201,13 @@ type
lteqop,gteqop,eqeqop,exceqop,andandop,
barbarop,pluseqop,minuseqop,asteriskeqop,slasheqop,
percenteqop,ltlteqop,gtgteqop,andeqop,caroteqop,
bareqop,poundpoundop,
bareqop,poundpoundop,dotdotdotsy,
ppnumber, {preprocessing number (pp-token)}
otherch, {other non-whitespace char (pp-token)}
eolsy,eofsy, {control characters}
typedef, {user types}
uminus,uand,uasterisk, {converted operations}
{converted operations}
uminus,uplus,uand,uasterisk,
parameteroper,castoper,opplusplus,opminusminus,compoundliteral,
macroParm); {macro language}
@ -209,14 +218,15 @@ type
(illegal,ch_special,ch_dash,ch_plus,ch_lt,ch_gt,ch_eq,ch_exc,
ch_and,ch_bar,ch_dot,ch_white,ch_eol,ch_eof,ch_char,ch_string,
ch_asterisk,ch_slash,ch_percent,ch_carot,ch_pound,ch_colon,
ch_backslash,letter,digit);
ch_backslash,ch_other,letter,digit);
{prefixes of a character/string literal}
charStrPrefixEnum = (prefix_none,prefix_L,prefix_u16,prefix_U32,prefix_u8);
tokenSet = set of tokenEnum;
tokenClass = (reservedWord,reservedSymbol,identifier,intConstant,longConstant,
longlongConstant,realConstant,stringConstant,macroParameter);
longlongConstant,realConstant,stringConstant,otherCharacter,
preprocessingNumber,macroParameter);
identPtr = ^identRecord; {^ to a symbol table entry}
tokenType = record {a token}
kind: tokenEnum; {kind of token}
@ -233,6 +243,8 @@ type
stringConstant: (sval: longstringPtr;
ispstring: boolean;
prefix: charStrPrefixEnum);
otherCharacter: (ch: char); {used for preprocessing tokens only}
preprocessingNumber: (errCode: integer); {used for pp tokens only}
macroParameter: (pnum: integer);
end;
@ -318,14 +330,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,
@ -365,15 +380,20 @@ type
iPtr: initializerPtr; {pointer to the first initializer}
isForwardDeclared: boolean; {does this var use a forward declared type?}
class: tokenEnum; {storage class}
used: boolean; {is this identifier used?}
case storage: storageType of
stackFrame: (lln: integer; {local label #}
clnext: identPtr); {next compound literal}
parameter: (pln: integer; {paramater label #}
pdisp: integer; {disp of parameter}
pnext: identPtr); {next parameter}
external: ();
external: (inlineDefinition: boolean); {(potential) inline definition of function?}
global,private: ();
none: ();
none: (
case anonMemberField: boolean of {field from an anonymous struct/union member?}
true : (anonMember: identPtr); {containing anonymous struct/union}
false: ();
);
end;
{mini-assembler}
@ -476,6 +496,7 @@ var
bofPtr: ptr; {pointer to the start of sourceFile}
chPtr: ptr; {pointer to the next character in the file}
changedSourceFile: boolean; {source file changed in function?}
cStd: cStandardEnum; {selected C standard}
debugSourceFileGS: gsosOutString; {debug source file name}
{debugType is also in SCANNER.ASM}
debugType: (stop,break,autogo); {line number debug types}
@ -488,9 +509,9 @@ var
infoStringGS: gsosOutString; {language specific command line info}
intLabel: integer; {last used label number}
languageNumber: integer; {our language number}
lastLine: 0..maxint; {last line number used by pc_nam}
lastLine: 0..maxint4; {last line number used by pc_nam}
liDCBGS: getLInfoDCBGS; {get/set LInfo DCB}
lineNumber: 0..maxint; {source line number}
lineNumber: 0..maxint4; {source line number}
nameFound: boolean; {has a pc_nam been generated?}
nextLocalLabel: integer; {next available local data label number}
numErrors: integer; {number of errors in the program}
@ -500,6 +521,7 @@ var
partialFileGS: gsosOutString; {partial compile list}
pragmaKeepFile: gsosOutStringPtr; {filename specified in #pragma keep}
sourceFileGS: gsosOutString; {presumed source file name}
strictMode: boolean; {strictly follow standard, without extensions?}
tempList: tempPtr; {list of temp work variables}
longlong0: longlong; {the value 0 as a longlong}
longlong1: longlong; {the value 1 as a longlong}
@ -515,10 +537,6 @@ var
isConstant: boolean; {is the initializer expression constant?}
expressionIsLongLong: boolean; {is the last constant expression long long?}
{type specifier results}
{----------------------}
typeSpec: typePtr; {type specifier}
{flags}
{-----}
codegenStarted: boolean; {have we started the code generator?}
@ -820,6 +838,8 @@ var
msgGS: gsosInString; {message}
begin {ExitToEditor}
if disp < 0 then {sanity check disp}
disp := 0;
msgGS.size := length(msg^); {set up the error message}
msgGS.theString := msg^;
liDCBGS.org := disp; {mark the error}
@ -997,7 +1017,7 @@ case errnum of {print the error}
8 : msg := 'you cannot change languages from an included file';
9 : msg := concat('Error writing ', objFile.theString.theString);
10: msg := 'ORCA/C requires version 2.0 or later of the shell';
11: msg := 'The program is too large to compile to memory -- use Compile to Disk';
{11: msg := 'The program is too large to compile to memory -- use Compile to Disk';}
12: msg := 'Invalid sym file detected. Re-run ORCA/C to proceed.';
13: msg := 'file name or command-line parameter is too long';
otherwise: begin

37
CGC.asm
View File

@ -1,40 +1,6 @@
mcopy cgc.macros
****************************************************************
*
* CnvSX - Convert floating point to SANE extended
*
* Inputs:
* rec - pointer to a record
*
****************************************************************
*
CnvSX start cg
rec equ 4 record containing values
rec_real equ 0 disp to real (extended) value
rec_ext equ 10 disp to extended (SANE) value
tsc set up DP
phd
tcd
ph4 rec push addr of real number
clc push addr of SANE number
lda rec
adc #rec_ext
tax
lda rec+2
adc #0
pha
phx
fx2x convert TOS to extended
move4 0,4 return
pld
pla
pla
rtl
end
****************************************************************
*
* CnvSC - Convert floating point to SANE comp
*
* Inputs:
@ -48,8 +14,7 @@ rec_ext equ 10 disp to extended (SANE) value
CnvSC start cg
rec equ 4 record containing values
rec_real equ 0 disp to real (extended) value
rec_ext equ 10 disp to extended (SANE) value
rec_cmp equ 20 disp to comp (SANE) value
rec_cmp equ 10 disp to comp (SANE) value
tsc set up DP
phd

View File

@ -175,12 +175,6 @@
sta 2+&op
mend
MACRO
&LAB FX2X
&LAB PEA $0010
LDX #$090A
JSL $E10000
MEND
MACRO
&LAB FX2C
&LAB PEA $0510
LDX #$090A
@ -435,3 +429,85 @@
.g
mnote "Missing closing '}'",16
mend
macro
&l add4 &m1,&m2,&m3
lclb &yistwo
lclc &c
&l ~setm
aif c:&m3,.a
&c amid "&m2",1,1
aif "&c"<>"#",.a
&c amid "&m1",1,1
aif "&c"="{",.a
aif "&c"="[",.a
&c amid "&m2",2,l:&m2-1
aif &c>=65536,.a
clc
~lda &m1
~op adc,&m2
~sta &m1
bcc ~&SYSCNT
~op.h inc,&m1
~&SYSCNT anop
ago .c
.a
aif c:&m3,.b
lclc &m3
&m3 setc &m1
.b
clc
~lda &m1
~op adc,&m2
~sta &m3
~lda.h &m1
~op.h adc,&m2
~sta.h &m3
.c
~restm
mend
macro
&l ~op &opc,&op
lclc &c
&c amid "&op",1,1
aif "&c"<>"{",.b
&c amid "&op",l:&op,1
aif "&c"="}",.a
mnote "Missing closing '}'",2
&op setc &op}
.a
&op amid "&op",2,l:&op-2
&op setc (&op)
.b
&l &opc &op
mend
macro
&l ~op.h &opc,&op
&l anop
lclc &c
&c amid "&op",1,1
aif "&c"="[",.b
aif "&c"<>"{",.d
&c amid "&op",l:&op,1
aif "&c"="}",.a
mnote "Missing closing '}'",2
&op setc &op}
.a
&op amid "&op",2,l:&op-2
&op setc (&op)
.b
aif &yistwo,.c
&yistwo setb 1
ldy #2
.c
&op setc "&op,y"
&opc &op
mexit
.d
aif "&c"<>"#",.e
&op amid "&op",2,l:&op-1
&op setc "#^&op"
&opc &op
mexit
.e
&opc 2+&op
mend

12
CGC.pas
View File

@ -31,9 +31,8 @@ uses CCommon, CGI;
type
{pcode code generation}
{---------------------}
realrec = record {used to convert from real to in-SANE}
realrec = record {used to convert from real to comp}
itsReal: extended;
inSANE: packed array[1..10] of byte;
inCOMP: packed array[1..8] of byte;
end;
@ -58,15 +57,6 @@ procedure CnvSC (rec: realrec); extern;
{ has space for the result }
procedure CnvSX (rec: realrec); extern;
{ convert a real number to SANE extended format }
{ }
{ parameters: }
{ rec - record containing the value to convert; also }
{ has space for the result }
procedure CnvXLL (var result: longlong; val: extended); extern;
{ convert a real number to long long }

View File

@ -57,7 +57,7 @@
{ Gen2(pc_mov, banks, bytes) }
{ }
{ The top of stack contains a source address, and TOS-1 has a }
{ destination address. The destination address is removed, }
{ destination address. The source address is removed, }
{ and BYTES bytes are moved from the source to the }
{ destination. BANKS is the number of full banks to move; it }
{ is used when 64K or more must be moved. The memory areas }
@ -196,6 +196,15 @@
{ a SIZE bit value. Extra bits are dropped. }
{ }
{ }
{ pc_ckp - check for null pointer }
{ }
{ Gen0(pc_ckp) }
{ Gen0(pc_ckn) }
{ }
{ Make sure a pointer value is not null. The pc_ckp form }
{ checks the value at tos; pc_ckn checks the value at tos-1. }
{ }
{ }
{ pc_cop - copy to a local variable }
{ }
{ Gen2t(pc_cop, label, disp, type) }
@ -306,6 +315,14 @@
{ the stack. }
{ }
{ }
{ pc_fix - fix a floating-point variable }
{ }
{ Gen1t(pc_fix, lab, type) }
{ }
{ Change a floating-point value (generally a passed parameter) }
{ from extended to cgReal, cgDouble,or cgComp. }
{ }
{ }
{ pc_gil - increment and load from a global variable }
{ pc_gli - load a global variable, then inc the original }
{ pc_gdl - decrement and load from a global variable }
@ -787,6 +804,17 @@
{ into the stack frame. }
{ }
{ }
{ pc_rev - return a value from a subroutine }
{ }
{ Gen0t(pc_rev, type) }
{ }
{ This pcode is used to return from a function. The type is }
{ the type of the function, and is used to tell the code }
{ generator what type of value to return. It may be cgByte, }
{ cgUByte, cgWord, cgUWord, cgLong, or cgULong. The value }
{ to return is removed from the evaluation stack. }
{ }
{ }
{ pc_cui - call user procedure, indirect }
{ }
{ Gen1t(pc_cui, repair, ftype) }

View File

@ -133,10 +133,13 @@ opt[pc_slq] := 'slq';
opt[pc_sqr] := 'sqr';
opt[pc_wsr] := 'wsr';
opt[pc_rbo] := 'rbo';
opt[pc_rev] := 'rev';
opt[pc_ckp] := 'ckp';
opt[pc_ckn] := 'ckn';
end; {InitWriteCode}
procedure PrintDAG (tag: stringPtr; code: icptr);
procedure PrintDAG {tag: stringPtr; code: icptr};
{ print a DAG }
{ }
@ -280,14 +283,14 @@ with code^ do
pc_bnt,pc_blx,pc_bnl,pc_ngi,pc_ngl,pc_ngr,pc_ixa,pc_mdl,
pc_udi,pc_udl,pc_bqr,pc_bqx,pc_baq,pc_bnq,pc_ngq,pc_adq,pc_sbq,
pc_mpq,pc_umq,pc_dvq,pc_udq,pc_mdq,pc_uqm,pc_slq,pc_sqr,pc_wsr,
pc_rbo,pc_sll,pc_shr,pc_usr,pc_slr,pc_vsr: ;
pc_rbo,pc_sll,pc_shr,pc_usr,pc_slr,pc_vsr,pc_ckp,pc_ckn: ;
dc_prm:
write(' ', q:1, ':', r:1, ':', s:1);
pc_equ,pc_neq,pc_geq,pc_leq,pc_grt,pc_les,pc_pop,pc_ret,pc_bno,
pc_cpi,pc_sto,pc_tri,pc_stk,pc_idl,pc_iil,pc_ili,pc_ild:
pc_cpi,pc_sto,pc_tri,pc_stk,pc_idl,pc_iil,pc_ili,pc_ild,pc_rev:
WriteType(optype);
pc_cnv,pc_cnn: begin

174
CGI.pas
View File

@ -33,12 +33,13 @@ const
cge1 = 57; {compiler error}
cge2 = 58; {implementation restriction: too many local labels}
cge3 = 60; {implementation restriction: string space exhausted}
cge4 = 188; {local variable out of range for DP addressing}
{65816 native code generation}
{----------------------------}
{instruction modifier flags}
shift8 = 1; {shift operand left 8 bits}
shift16 = 2; {shift operand left 16 bits}
shift8 = 1; {shift operand right 8 bits}
shift16 = 2; {shift operand right 16 bits}
toolCall = 4; {generate a tool call}
stringReference = 8; {generate a string reference}
isPrivate = 32; {is the label private?}
@ -46,6 +47,8 @@ const
localLab = 128; {the operand is a local lab}
forFlags = 256; {instruction used for effect on flags only}
subtract1 = 512; {subtract 1 from address operand}
shiftLeft8 = 1024; {shift operand left 8 bits}
labelUsedOnce = 2048; {only one branch targets this label}
m_adc_abs = $6D; {op code #s for 65816 instructions}
m_adc_dir = $65;
@ -69,6 +72,7 @@ const
m_bpl = $10;
m_bra = $80;
m_brl = $82;
m_bvc = $50;
m_bvs = $70;
m_clc = $18;
m_cmp_abs = $CD;
@ -83,6 +87,7 @@ const
m_cpx_abs = 236;
m_cpx_dir = 228;
m_cpx_imm = 224;
m_cpy_imm = $C0;
m_dea = 58;
m_dec_abs = 206;
m_dec_absX = $DE;
@ -204,8 +209,13 @@ const
d_wrd = 261;
d_sym = 262;
d_cns = 263;
d_dcb = 264;
d_dcw = 265;
d_dcl = 266;
max_opcode = 263;
max_opcode = 266;
asmFlag = $8000; {or'd with opcode to indicate asm code}
{Code Generation}
{---------------}
@ -248,7 +258,8 @@ type
pc_gli,pc_gdl,pc_gld,pc_cpi,pc_tri,pc_lbu,pc_lbf,pc_sbf,pc_cbf,dc_cns,
dc_prm,pc_nat,pc_bno,pc_nop,pc_psh,pc_ili,pc_iil,pc_ild,pc_idl,
pc_bqr,pc_bqx,pc_baq,pc_bnq,pc_ngq,pc_adq,pc_sbq,pc_mpq,pc_umq,pc_dvq,
pc_udq,pc_mdq,pc_uqm,pc_slq,pc_sqr,pc_wsr,pc_rbo);
pc_udq,pc_mdq,pc_uqm,pc_slq,pc_sqr,pc_wsr,pc_rbo,pc_fix,pc_rev,pc_ckp,
pc_ckn);
{intermediate code}
{-----------------}
@ -273,11 +284,17 @@ 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;
codeRef = icptr; {reference to a code location}
{basic blocks}
{------------}
iclist = ^iclistRecord; {used to form lists of records}
@ -323,6 +340,7 @@ var
{quality or characteristics of }
{code }
{------------------------------}
checkNullPointers: boolean; {check for null pointer dereferences?}
checkStack: boolean; {check stack for stack errors?}
cLineOptimize: boolean; {+o flag set?}
code: icptr; {current intermediate code record}
@ -330,6 +348,7 @@ var
commonSubexpression: boolean; {do common subexpression removal?}
currentSegment,defaultSegment: segNameType; {current & default seg names}
segmentKind: integer; {kind field of segment (ored with start/data)}
defaultSegmentKind: integer; {default segment kind}
debugFlag: boolean; {generate debugger calls?}
debugStrFlag: boolean; {gsbug/niftylist debug names?}
dataBank: boolean; {save, restore data bank?}
@ -568,6 +587,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 }
@ -631,6 +660,21 @@ procedure GenTool (fop: pcodes; fp1, fp2: integer; dispatcher: longint);
{ dispatcher - tool entry point }
function GetCodeLocation: codeRef;
{ Get a reference to the current location in the generated }
{ code, suitable to be passed to RemoveCode. }
procedure InsertCode (theCode: codeRef);
{ Insert a section of already-generated code that was }
{ previously removed with RemoveCode. }
{ }
{ parameters: }
{ theCode - code removed (returned from RemoveCode) }
{procedure PrintBlocks (tag: stringPtr; bp: blockPtr); {debug}
{ print a series of basic blocks }
@ -640,6 +684,28 @@ procedure GenTool (fop: pcodes; fp1, fp2: integer; dispatcher: longint);
{ bp - first block to print }
{procedure PrintDAG (tag: stringPtr; code: icptr); {debug}
{ print a DAG }
{ }
{ parameters: }
{ tag - label for lines }
{ code - first node in DAG }
function RemoveCode (start: codeRef): codeRef;
{ Remove a section of already-generated code, from immediately }
{ after start up to the latest code generated. Returns the }
{ code removed, so it may be re-inserted later. }
{ }
{ parameters: }
{ start - location to start removing from }
{ }
{ Note: start must be a top-level pcode (not a subexpression). }
{ Note: The region removed must not include a dc_enp. }
function TypeSize (tp: baseTypeEnum): integer;
{ Find the size, in bytes, of a variable }
@ -801,9 +867,12 @@ isXCMD := false;
codeGeneration := false; {code generation is not turned on yet}
currentSegment := ' '; {start with the blank segment}
defaultSegment := ' ';
segmentKind := 0; {default to static code segments}
defaultSegmentKind := 0;
smallMemoryModel := true; {small memory model}
dataBank := false; {don't save/restore data bank}
strictVararg := not cLineOptimize; {save/restore caller's stack around vararg}
strictVararg := {save/restore caller's stack around vararg}
(not cLineOptimize) or strictMode;
saveStack := not cLineOptimize; {save/restore caller's stack reg}
checkStack := false; {don't check stack for stack errors}
stackSize := 0; {default to the launcher's stack size}
@ -819,6 +888,7 @@ profileFlag := false; {don't generate profiling code}
debugFlag := false; {don't generate debug code}
debugStrFlag := false; {don't generate gsbug debug strings}
traceBack := false; {don't generate traceback code}
checkNullPointers := false; {don't check null pointers}
volatile := false; {no volatile qualifiers found}
registers := cLineOptimize; {don't do register optimizations}
@ -1224,6 +1294,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 }
@ -1376,6 +1470,74 @@ if codeGeneration then begin
end; {GenLdcReal}
function GetCodeLocation{: codeRef};
{ Get a reference to the current location in the generated }
{ code, suitable to be passed to RemoveCode. }
begin {GetCodeLocation}
GetCodeLocation := DAGhead;
end {GetCodeLocation};
procedure InsertCode {theCode: codeRef};
{ Insert a section of already-generated code that was }
{ previously removed with RemoveCode. }
{ }
{ parameters: }
{ theCode - code removed (returned from RemoveCode) }
var
lcode: icptr;
begin {InsertCode}
if theCode <> nil then
if codeGeneration then begin
lcode := theCode;
{ PrintDAG(@'Inserting: ', lcode); {debug}
while lcode^.next <> nil do
lcode := lcode^.next;
lcode^.next := DAGhead;
DAGhead := theCode;
end; {if}
end; {InsertCode}
function RemoveCode {start: codeRef): codeRef};
{ Remove a section of already-generated code, from immediately }
{ after start up to the latest code generated. Returns the }
{ code removed, so it may be re-inserted later. }
{ }
{ parameters: }
{ start - location to start removing from }
{ }
{ Note: start must be a top-level pcode (not a subexpression). }
{ Note: The region removed must not include a dc_enp. }
var
lcode: icptr;
begin {RemoveCode}
if start = DAGhead then
RemoveCode := nil
else begin
RemoveCode := DAGhead;
if codeGeneration then begin
lcode := DAGhead;
while (lcode^.next <> start) and (lcode^.next <> nil) do
lcode := lcode^.next;
if lcode^.next = nil then
Error(cge1);
lcode^.next := nil;
{ PrintDAG(@'Removing: ', DAGhead); {debug}
DAGhead := start;
end; {if}
end; {else}
end; {RemoveCode}
function TypeSize {tp: baseTypeEnum): integer};
{ Find the size, in bytes, of a variable }

98
DAG.pas
View File

@ -202,7 +202,8 @@ else if (op1 <> nil) and (op2 <> nil) then
or fastMath then
CodesMatch := true;
cgString:
CodesMatch := LongStrCmp(op1^.str, op2^.str);
if not (op1^.isByteSeq or op1^.isByteSeq) then
CodesMatch := LongStrCmp(op1^.str, op2^.str);
cgVoid, ccPointer:
if op1^.pval = op2^.pval then
CodesMatch := LongStrCmp(op1^.str, op2^.str);
@ -429,26 +430,6 @@ while not (op^.next^.opcode in [dc_lab, dc_enp, dc_cns, dc_glb,
end; {RemoveDeadCode}
function NoFunctions (op: icptr): boolean;
{ are there any function calls? }
{ }
{ parameters: }
{ op - operation tree to search }
{ }
{ returns: True if there are no pc_cup or pc_cui operations }
{ in the tree, else false. }
begin {NoFunctions}
if op = nil then
NoFunctions := true
else if op^.opcode in [pc_cup,pc_cui,pc_tl1] then
NoFunctions := false
else
NoFunctions := NoFunctions(op^.left) or NoFunctions(op^.right);
end; {NoFunctions}
function OneBit (val: longint): boolean;
{ See if there is exactly one bit set in val }
@ -507,9 +488,6 @@ var
{ parameters: }
{ op - tree to check }
var
result: boolean; {temp result}
begin {SideEffects}
if op = nil then begin
if volatile then
@ -520,7 +498,8 @@ var
else if op^.opcode in
[pc_mov,pc_cbf,pc_cop,pc_cpi,pc_cpo,pc_gil,pc_gli,pc_gdl,
pc_gld,pc_iil,pc_ili,pc_idl,pc_ild,pc_lil,pc_lli,pc_ldl,
pc_lld,pc_sbf,pc_sro,pc_sto,pc_str,pc_cui,pc_cup,pc_tl1] then
pc_lld,pc_sbf,pc_sro,pc_sto,pc_str,pc_cui,pc_cup,pc_tl1,
pc_fix,pc_ckp] then
SideEffects := true
else if op^.opcode = pc_ldc then
SideEffects := false
@ -538,7 +517,6 @@ var
{ newOpcode - opcode to use if the jump sense is reversed }
var
done: boolean; {optimization done test}
topcode: pcodes; {temp opcode}
begin {JumpOptimizations}
@ -587,6 +565,12 @@ var
false: (rval: real);
end;
cnvdbl: record {for stuffing a double in a quad space}
case boolean of
true: (qval: longlong);
false: (rval: double);
end;
begin {RealStoreOptimizations}
if opl^.opcode = pc_cnv then
if baseTypeEnum(opl^.q & $000F) = op^.optype then
@ -603,7 +587,7 @@ var
if lab^ = op^.lab^ then
same := true;
end {if}
else {if op^.opcode = pc_str then}
else if op^.opcode = pc_str then
if opcode = pc_lod then
if q = op^.q then
if r = op^.r then
@ -653,6 +637,19 @@ var
opl^.optype := cgLong;
op^.optype := cgLong;
end; {if}
end {if}
else if op^.optype = cgDouble then begin
if opl^.opcode = pc_ldc then begin
cnvdbl.rval := opl^.rval;
opl^.qval := cnvdbl.qval;
opl^.optype := cgQuad;
op^.optype := cgQuad;
end {if}
else if opl^.opcode in [pc_ind,pc_ldo,pc_lod] then
if opl^.optype = cgDouble then begin
opl^.optype := cgQuad;
op^.optype := cgQuad;
end; {if}
end; {if}
end; {RealStoreOptimizations}
@ -750,11 +747,13 @@ case op^.opcode of {check for optimizations of this node}
op^.opcode := pc_inc;
op^.q := q;
op^.right := nil;
PeepHoleOptimization(opv);
end {else if}
else {if q < 0 then} begin
op^.opcode := pc_dec;
op^.q := -q;
op^.right := nil;
PeepHoleOptimization(opv);
end; {else if}
end {if}
else if CodesMatch(op^.left, op^.right, false) then begin
@ -819,6 +818,7 @@ case op^.opcode of {check for optimizations of this node}
op^.q := ord(lval);
op^.right := nil;
done := true;
PeepHoleOptimization(opv);
end {else if}
else if (lval > -maxint) and (lval < 0) then begin
op^.opcode := pc_dec;
@ -826,6 +826,7 @@ case op^.opcode of {check for optimizations of this node}
op^.q := -ord(lval);
op^.right := nil;
done := true;
PeepHoleOptimization(opv);
end; {else if}
end {if}
else if CodesMatch(op^.left, op^.right, false) then
@ -1750,8 +1751,10 @@ case op^.opcode of {check for optimizations of this node}
opv := op^.right;
end; {if}
end {if}
else
else begin
op^.opcode := pc_neq;
PeepHoleOptimization(opv);
end; {else}
end {if}
end {if}
else if op^.left^.opcode = pc_ldc then
@ -1836,8 +1839,14 @@ case op^.opcode of {check for optimizations of this node}
and (op^.right^.qval.lo = 0) and (op^.right^.qval.hi = 0)) then
begin
case op^.opcode of
pc_leq: op^.opcode := pc_equ;
pc_grt: op^.opcode := pc_neq;
pc_leq: begin
op^.opcode := pc_equ;
PeepHoleOptimization(opv);
end;
pc_grt: begin
op^.opcode := pc_neq;
PeepHoleOptimization(opv);
end;
pc_les: if not SideEffects(op^.left) then begin
op^.right^.optype := cgWord;
op^.right^.q := 0;
@ -1915,6 +1924,7 @@ case op^.opcode of {check for optimizations of this node}
else begin
op^.opcode := pc_neq;
op^.optype := cgLong;
PeepHoleOptimization(opv);
end; {else}
end; {if}
end {if}
@ -2282,11 +2292,13 @@ case op^.opcode of {check for optimizations of this node}
op^.opcode := pc_dec;
op^.q := q;
op^.right := nil;
PeepHoleOptimization(opv);
end {else if}
else {if q < 0) then} begin
op^.opcode := pc_inc;
op^.q := -q;
op^.right := nil;
PeepHoleOptimization(opv);
end; {else if}
end {if}
else if op^.left^.opcode in [pc_inc,pc_dec] then
@ -2337,12 +2349,14 @@ case op^.opcode of {check for optimizations of this node}
op^.q := ord(lval);
op^.right := nil;
op^.optype := cgLong;
PeepHoleOptimization(opv);
end {else if}
else if (lval > -maxint) and (lval < 0) then begin
op^.opcode := pc_inc;
op^.q := -ord(lval);
op^.right := nil;
op^.optype := cgLong;
PeepHoleOptimization(opv);
end; {else if}
end; {if}
end; {case pc_sbl}
@ -2461,22 +2475,23 @@ case op^.opcode of {check for optimizations of this node}
end; {case pc_sro, pc_str}
pc_sto: begin {pc_sto}
if op^.optype in [cgReal,cgDouble,cgExtended,cgComp] then
RealStoreOptimizations(op, op^.right);
op2 := op^.right;
if op^.left^.opcode = pc_lao then begin
op^.q := op^.left^.q;
op^.lab := op^.left^.lab;
op^.opcode := pc_sro;
op^.left := op^.right;
op^.left := op2;
op^.right := nil;
end {if}
else if op^.left^.opcode = pc_lda then begin
op^.q := op^.left^.q;
op^.r := op^.left^.r;
op^.opcode := pc_str;
op^.left := op^.right;
op^.left := op2;
op^.right := nil;
end; {if}
if op^.optype in [cgReal,cgDouble,cgExtended,cgComp] then
RealStoreOptimizations(op, op2);
end; {case pc_sto}
pc_sqr: begin {pc_sqr}
@ -2817,7 +2832,7 @@ case op^.opcode of
pc_cnn, pc_cnv:
TypeOf := baseTypeEnum(op^.q & $000F);
pc_stk:
pc_stk, pc_ckp:
TypeOf := TypeOf(op^.left);
pc_bno:
@ -5479,7 +5494,7 @@ case code^.opcode of
pc_bnt, pc_bnl, pc_cnv, pc_dec, pc_inc, pc_ind, pc_lbf, pc_lbu,
pc_ngi, pc_ngl, pc_ngr, pc_not, pc_stk, pc_cop, pc_cpo, pc_tl1,
pc_sro, pc_str, pc_fjp, pc_tjp, pc_xjp, pc_cup, pc_pop, pc_iil,
pc_ili, pc_idl, pc_ild, pc_bnq, pc_ngq, pc_rbo:
pc_ili, pc_idl, pc_ild, pc_bnq, pc_ngq, pc_rbo, pc_rev, pc_ckp:
begin
code^.left := Pop;
Push(code);
@ -5503,7 +5518,7 @@ case code^.opcode of
pc_gil, pc_gli, pc_gdl, pc_gld, pc_lil, pc_lli, pc_ldl, pc_lld,
pc_lad, pc_lao, pc_lca, pc_lda, pc_ldc, pc_ldo, pc_lod, pc_nop,
dc_cns, dc_glb, dc_dst, pc_lnm, pc_nam, pc_nat, dc_lab, pc_add,
pc_ujp, dc_pin, pc_ent, dc_sym:
pc_ujp, dc_pin, pc_ent, dc_sym, pc_fix:
Push(code);
pc_ret:
@ -5514,6 +5529,15 @@ case code^.opcode of
Push(code);
end;
pc_ckn:
begin
code^.opcode := pc_ckp;
temp := Pop;
code^.left := Pop;
Push(code);
Push(temp);
end;
pc_cnn:
begin
code^.opcode := pc_cnv;

View File

@ -250,12 +250,11 @@ procedure Match (kind: tokenEnum; err: integer); extern;
{ err - error number if the expected token is not found }
procedure TypeName; extern;
function TypeName: typePtr; extern;
{ process a type name (used for casts and sizeof/_Alignof) }
{ }
{ outputs: }
{ typeSpec - pointer to the type }
{ returns: a pointer to the type }
function MakeFuncIdentifier: identPtr; extern;
@ -278,7 +277,7 @@ function MakeCompoundLiteral(tp: typePtr): identPtr; extern;
{ tp - the type of the compound literal }
procedure AutoInit (variable: identPtr; line: integer;
procedure AutoInit (variable: identPtr; line: longint;
isCompoundLiteral: boolean); extern;
{ generate code to initialize an auto variable }
@ -611,6 +610,41 @@ var
baseType1,baseType2: baseTypeEnum; {temp variables (for speed)}
kind1,kind2: typeKind; {temp variables (for speed)}
procedure CheckConstantRange(t1: typePtr; value: longint);
{ Check for situations where an implicit conversion will }
{ change the value of a constant. }
{ }
{ Note: This currently only addresses conversions to 8-bit }
{ or 16-bit integer types, and intentionally does not }
{ distinguish between signed and unsigned types. }
var
min,max: longint; {min/max allowed values}
begin {CheckConstantRange}
if t1^.cType = ctBool then begin
min := 0;
max := 1;
end {if}
else if t1^.baseType in [cgByte,cgUByte] then begin
min := -128;
max := 255;
end {else if}
else if t1^.baseType in [cgWord,cgUWord] then begin
min := -32768;
max := 65536;
end {else if}
else begin
min := -maxint4-1;
max := maxint4;
end; {else}
if (value < min) or (value > max) then
Error(186);
end; {CheckConstantRange}
begin {AssignmentConversion}
kind1 := t1^.kind;
kind2 := t2^.kind;
@ -631,6 +665,9 @@ else if kind2 in
case kind1 of
scalarType: begin
if ((lint & lintConstantRange) <> 0) then
if isConstant then
CheckConstantRange(t1, value);
baseType1 := t1^.baseType;
if baseType1 in [cgReal,cgDouble,cgComp] then
baseType1 := cgExtended;
@ -702,6 +739,9 @@ else if kind2 in
enumType: begin
if kind2 = scalarType then begin
if ((lint & lintConstantRange) <> 0) then
if isConstant then
CheckConstantRange(intPtr, value);
baseType2 := t2^.baseType;
if baseType2 in [cgString,cgVoid] then
Error(47)
@ -756,6 +796,7 @@ var
opStack: tokenPtr; {operation stack}
parenCount: integer; {# of open parenthesis}
stack: tokenPtr; {operand stack}
tType: typePtr; {type for cast/sizeof/etc.}
op,sp: tokenPtr; {work pointers}
@ -986,6 +1027,7 @@ var
stack^.token.class := longlongConstant;
stack^.token.kind := longlongconst;
stack^.token.qval := longlong0;
id := nil;
end {if}
{if the id is not declared, create a function returning integer}
@ -1008,7 +1050,7 @@ var
{fnPtr^.dispatcher := 0;}
np := pointer(GMalloc(length(fToken.name^)+1));
CopyString(pointer(np), pointer(fToken.name));
id := NewSymbol(np, fnPtr, ident, variableSpace, declared);
id := NewSymbol(np, fnPtr, ident, variableSpace, declared, false);
if ((lint & lintUndefFn) <> 0) or ((lint & lintC99Syntax) <> 0) then
Error(51);
end {if}
@ -1022,6 +1064,9 @@ var
stack^.token.kind := intconst;
stack^.token.ival := id^.itype^.eval;
end; {else if}
if id <> nil then
id^.used := true;
stack^.id := id; {save the identifier}
ComplexTerm; {handle subscripts, selection, etc.}
1:
@ -1369,7 +1414,11 @@ var
op1 := op1 * op2;
slashch : begin {/}
if op2 = 0 then begin
Error(109);
if not (kind in [normalExpression,
autoInitializerExpression]) then
Error(109)
else if ((lint & lintOverflow) <> 0) then
Error(129);
op2 := 1;
end; {if}
if unsigned then
@ -1379,7 +1428,11 @@ var
end;
percentch : begin {%}
if op2 = 0 then begin
Error(109);
if not (kind in [normalExpression,
autoInitializerExpression]) then
Error(109)
else if ((lint & lintOverflow) <> 0) then
Error(129);
op2 := 1;
end; {if}
if unsigned then
@ -1525,7 +1578,11 @@ var
asteriskch : umul64(llop1, llop2); {*}
slashch : begin {/}
if (llop2.lo = 0) and (llop2.hi = 0) then begin
Error(109);
if not (kind in [normalExpression,
autoInitializerExpression]) then
Error(109)
else if ((lint & lintOverflow) <> 0) then
Error(129);
llop2 := longlong1;
end; {if}
if unsigned then
@ -1535,7 +1592,11 @@ var
end;
percentch : begin {%}
if (llop2.lo = 0) and (llop2.hi = 0) then begin
Error(109);
if not (kind in [normalExpression,
autoInitializerExpression]) then
Error(109)
else if ((lint & lintOverflow) <> 0) then
Error(129);
llop2 := longlong1;
end; {if}
if unsigned then
@ -1659,6 +1720,7 @@ var
tildech, {~}
excch, {!}
uminus, {unary -}
uplus, {unary +}
uand, {unary &}
uasterisk: begin {unary *}
op^.left := Pop;
@ -1666,12 +1728,16 @@ var
if op^.token.kind = sizeofsy then begin
op^.token.kind := ulongConst;
op^.token.class := longConstant;
if op^.left^.token.kind = stringConst then
kindLeft := op^.left^.token.kind;
if kindLeft = stringConst then
op^.token.lval := op^.left^.token.sval^.length
else begin
lCodeGeneration := codeGeneration;
codeGeneration := false;
GenerateCode(op^.left);
if kindLeft = dotch then
if isBitfield then
Error(49);
codeGeneration := lCodeGeneration and (numErrors = 0);
op^.token.lval := expressionType^.size;
with expressionType^ do
@ -1810,6 +1876,7 @@ var
ekind := intconst;
end;
uminus : op1 := -op1; {unary -}
uplus : ; {unary +}
uasterisk : Error(79); {unary *}
otherwise: Error(57);
end; {case}
@ -1852,6 +1919,7 @@ var
if llop1.lo = 0 then
llop1.hi := llop1.hi + 1;
end;
uplus : ; {unary +}
uasterisk : Error(79); {unary *}
otherwise: Error(57);
end; {case}
@ -1880,6 +1948,11 @@ var
op^.token.kind := ekind;
op^.token.rval := -rop1;
end;
uplus : begin {unary +}
op^.token.class := realConstant;
op^.token.kind := ekind;
op^.token.rval := rop1;
end;
excch : begin {!}
op^.token.class := intConstant;
op^.token.kind := intconst;
@ -2002,8 +2075,7 @@ var
while not (token.kind in [colonch,commach,rparench,eofsy]) do
NextToken;
end; {if}
TypeName; {get the type name}
currentType := typeSpec;
currentType := TypeName; {get the type name}
if (currentType^.size = 0) or (currentType^.kind = functionType) then
Error(133);
tl := typesSeen; {check if it is a duplicate}
@ -2124,7 +2196,7 @@ begin {ExpressionTree}
opStack := nil;
stack := nil;
if token.kind = typedef then {handle typedefs that are hidden}
if FindSymbol(token,allSpaces,false,true) <> nil then
if FindSymbol(token,variableSpace,false,true) <> nil then
if token.symbolPtr^.class <> typedefsy then
token.kind := ident;
if token.kind in startExpression then begin
@ -2214,7 +2286,7 @@ if token.kind in startExpression then begin
doingSizeof := true
else if opStack^.token.kind = _Alignofsy then
doingAlignof := true;
TypeName;
tType := TypeName;
if doingSizeof or doingAlignof then begin
{handle a sizeof operator}
@ -2229,10 +2301,10 @@ if token.kind in startExpression then begin
sp^.token.kind := ulongconst;
sp^.token.class := longConstant;
if doingSizeof then
sp^.token.lval := typeSpec^.size
sp^.token.lval := tType^.size
else {if doingAlignof then}
sp^.token.lval := 1;
with typeSpec^ do
with tType^ do
if (size = 0) or ((kind = arrayType) and (elements = 0)) then
Error(133);
sp^.next := stack;
@ -2246,7 +2318,7 @@ if token.kind in startExpression then begin
op^.left := nil;
op^.middle := nil;
op^.right := nil;
op^.castType := typeSpec;
op^.castType := tType;
op^.token.kind := castoper;
op^.token.class := reservedWord;
op^.next := opStack;
@ -2279,10 +2351,7 @@ if token.kind in startExpression then begin
asteriskch: token.kind := uasterisk;
minusch : token.kind := uminus;
andch : token.kind := uand;
plusch : begin
NextToken;
goto 2;
end;
plusch : token.kind := uplus;
otherwise : Error(57);
end; {case}
if icp[token.kind] = notAnOperation then
@ -2306,7 +2375,7 @@ if token.kind in startExpression then begin
end; {if}
if token.kind in {make sure we get what we want}
[plusplusop,minusminusop,sizeofsy,_Alignofsy,tildech,excch,
uasterisk,uminus,uand] then begin
uasterisk,uminus,uplus,uand] then begin
if not expectingTerm then begin
Error(38);
Skip;
@ -2762,6 +2831,8 @@ procedure ChangePointer (op: pcodes; size: longint; tp: baseTypeEnum);
begin {ChangePointer}
if size = 0 then
Error(122);
if checkNullPointers then
Gen0(pc_ckn);
case tp of
cgByte,cgUByte,cgWord,cgUWord: begin
if (size = long(size).lsw) and (op = pc_adl)
@ -2821,6 +2892,7 @@ var
doingScalar: boolean; {temp; for assignment operators}
et: baseTypeEnum; {temp storage for a base type}
i: integer; {loop variable}
isConst: boolean; {is this a constant?}
isNullPtrConst: boolean; {is this a null pointer constant?}
isVolatile: boolean; {is this a volatile op?}
lType: typePtr; {type of operands}
@ -2838,6 +2910,23 @@ var
ldoDispose: boolean; {local copy of doDispose}
procedure CheckForIncompleteStructType;
{ Check if expressionType is an incomplete struct/union type. }
var
tp: typePtr; {the type}
begin
tp := expressionType;
while tp^.kind = definedType do
tp := tp^.dType;
if tp^.kind in [structType,unionType] then
if tp^.size = 0 then
Error(187);
end;
function ExpressionKind (tree: tokenPtr): typeKind;
{ returns the type of an expression }
@ -2871,7 +2960,7 @@ var
end; {ExpressionKind}
procedure LoadAddress (tree: tokenPtr);
procedure LoadAddress (tree: tokenPtr; nullCheck: boolean);
{ load the address of an l-value }
{ }
@ -2928,7 +3017,7 @@ var
{evaluate a compound literal and load its address}
AutoInit(tree^.id, 0, true);
tree^.token.kind := ident;
LoadAddress(tree);
LoadAddress(tree, false);
tree^.token.kind := compoundliteral;
Gen0t(pc_bno, cgULong);
end {if}
@ -2936,6 +3025,8 @@ var
{load the address of the item pointed to by the pointer}
GenerateCode(tree^.left);
if nullCheck then
Gen0(pc_ckp);
isBitField := false;
if not (expressionType^.kind in [pointerType,arrayType,functionType]) then
Error(79);
@ -2943,7 +3034,7 @@ var
else if tree^.token.kind = dotch then begin
{load the address of a field of a record}
LoadAddress(tree^.left);
LoadAddress(tree^.left, nullCheck);
eType := expressionType;
if eType^.kind in [arrayType,pointerType] then begin
if eType^.kind = arrayType then
@ -2966,15 +3057,18 @@ var
else if tree^.token.kind = castoper then begin
{load the address of a field of a record}
LoadAddress(tree^.left);
LoadAddress(tree^.left, nullCheck);
expressionType := tree^.castType;
if expressionType^.kind <> arrayType then
expressionType := MakePointerTo(expressionType);
end {else if}
else if ExpressionKind(tree) in [arrayType,pointerType,structType,unionType]
then
GenerateCode(tree)
then begin
GenerateCode(tree);
if nullCheck then
Gen0(pc_ckp);
end {else if}
else begin
expressionType := intPtr; {set default type in case of error}
if doDispose then {prevent spurious errors}
@ -3057,6 +3151,8 @@ var
end; {case}
pointerType,arrayType: begin
if checkNullPointers then
Gen0(pc_ckp);
GenldcLong(expressionType^.pType^.size);
if inc then
Gen0(pc_adl)
@ -3135,10 +3231,12 @@ var
lSize := iType^.pType^.size;
if lSize = 0 then
Error(122);
if long(lSize).msw <> 0 then begin
if (long(lSize).msw <> 0) or checkNullPointers then begin
{handle inc/dec of >64K}
{handle inc/dec of >64K or with null pointer check}
LoadScalar(tree^.id);
if checkNullPointers then
Gen0(pc_ckp);
GenLdcLong(lSize);
if pc_l in [pc_lli,pc_lil] then
Gen0(pc_adl)
@ -3176,7 +3274,7 @@ var
else begin
{do an indirect ++ or --}
LoadAddress(tree); {get the address to save to}
LoadAddress(tree, checkNullPointers); {get the address to save to}
if expressionType^.kind = arrayType then
expressionType := expressionType^.aType
else if expressionType^.kind = pointerType then
@ -3216,8 +3314,10 @@ var
else
Gen2t(pc_ind, ord(tqVolatile in expressionType^.qualifiers), 0, tp);
if pc_l in [pc_lli,pc_lld] then
if expressionType^.cType in [ctBool,ctFloat,ctDouble,ctLongDouble,
ctComp] then begin
if (expressionType^.kind = scalarType) and
(expressionType^.cType in
[ctBool,ctFloat,ctDouble,ctLongDouble,ctComp])
then begin
t1 := GetTemp(ord(expressionType^.size));
Gen2t(pc_cop, t1, 0, expressionType^.baseType);
end; {if}
@ -3228,8 +3328,10 @@ var
Gen0t(pc_cpi, tp);
Gen0t(pc_bno, tp);
if pc_l in [pc_lli,pc_lld] then {correct the value for postfix ops}
if expressionType^.cType in [ctBool,ctFloat,ctDouble,ctLongDouble,
ctComp] then begin
if (expressionType^.kind = scalarType) and
(expressionType^.cType in
[ctBool,ctFloat,ctDouble,ctLongDouble,ctComp])
then begin
Gen0t(pc_pop, expressionType^.baseType);
Gen2t(pc_lod, t1, 0, expressionType^.baseType);
Gen0t(pc_bno, expressionType^.baseType);
@ -3252,6 +3354,7 @@ var
fntype: typePtr; {temp function type}
ftree: tokenPtr; {function address tree}
ftype: typePtr; {function type}
hasVarargs: boolean; {varargs call with 1+ varargs passed?}
i: integer; {loop variable}
indirect: boolean; {is this an indirect call?}
ldoDispose: boolean; {local copy of doDispose}
@ -3267,9 +3370,7 @@ var
{ fType - function type }
var
kind: typeKind; {for expression kinds}
ldoDispose: boolean; {local copy of doDispose}
lnumErrors: integer; {number of errors before type check}
numParms: integer; {# of parameters generated}
parameters: parameterPtr; {next prototyped parameter}
pCount: integer; {# of parameters prototyped}
@ -3319,8 +3420,11 @@ var
fmt := fmt_none;
fp := nil;
if ((lint & lintPrintf) <> 0) and fType^.varargs and not indirect then
fmt := FormatClassify(ftree^.id^.name^);
if (lint & lintPrintf) <> 0 then
if fType^.varargs then
if not indirect then
if ftree^.id^.storage <> private then
fmt := FormatClassify(ftree^.id^.name^);
while parameters <> nil do begin {count the prototypes}
pCount := pCount+1;
@ -3333,8 +3437,11 @@ var
tp := tp^.right;
end; {while}
tp := parms;
if (pCount > 0) or ((pCount <> 0) and not ftype^.varargs) then
Error(85);
if pCount <> 0 then
if ftype^.varargs and (pcount < 0) then
hasVarargs := true
else
Error(85);
end; {if}
tp := parms;
@ -3345,25 +3452,26 @@ var
doDispose := false;
while tp <> nil do begin
if tp^.middle <> nil then begin
lnumErrors := numErrors;
kind := ExpressionKind(tp^.middle);
if numErrors = lnumErrors then
if kind in [structType,unionType] then begin
GenerateCode(tp^.middle);
if expressionType^.size & $FFFF8000 <> 0 then
GenerateCode(tp^.middle);
if expressionType^.kind in [structType,unionType,definedType]
then begin
tType := expressionType;
while tType^.kind = definedType do
tType := tType^.dType;
if tType^.kind in [structType,unionType] then begin
if tType^.size & $FFFF8000 <> 0 then
Error(61);
Gen1t(pc_ldc, long(expressionType^.size).lsw, cgWord);
Gen0(pc_psh);
end {else if}
else
GenerateCode(tp^.middle);
Gen1t(pc_ldc, long(tType^.size).lsw, cgWord);
Gen0(pc_psh);
end; {if}
end; {if}
if fmt <> fmt_none then begin
new(tfp);
tfp^.next := fp;
tfp^.tk := tp^.middle;
tfp^.ty := expressionType;
fp := tfp;
end;
new(tfp);
tfp^.next := fp;
tfp^.tk := tp^.middle;
tfp^.ty := expressionType;
fp := tfp;
end; {if}
if prototype then begin
if pCount = 0 then begin
if parameters <> nil then begin
@ -3403,6 +3511,7 @@ var
begin {FunctionCall}
{find the type of the function}
indirect := true; {assume an indirect call}
hasVarargs := false; {assume no variable arguments}
ftree := tree^.left; {get the function tree}
if ftree^.token.kind = ident then {check for direct calls}
if ftree^.id^.itype^.kind = functionType then begin
@ -3437,9 +3546,11 @@ var
if (ftype^.toolNum = 0) and (ftype^.dispatcher = 0) then begin
if indirect then begin
fntype := expressionType;
GenerateCode(ftree);
GenerateCode(ftree);
if checkNullPointers then
Gen0(pc_ckp);
expressionType := fntype;
Gen1t(pc_cui, ord(fType^.varargs and strictVararg),
Gen1t(pc_cui, ord(hasVarargs and strictVararg),
UsualUnaryConversions);
end {if}
else begin
@ -3451,17 +3562,17 @@ var
if fName^[i] in ['a'..'z'] then
fName^[i] := chr(ord(fName^[i]) & $5F);
end; {if}
Gen1tName(pc_cup, ord(fType^.varargs and strictVararg),
Gen1tName(pc_cup, ord(hasVarargs and strictVararg),
UsualUnaryConversions, fname);
end; {else}
if fType^.varargs then
if hasVarargs then
hasVarargsCall := true;
end {if}
else
GenTool(pc_tl1, ftype^.toolNum, long(ftype^.ftype^.size).lsw,
ftype^.dispatcher);
expressionType := ftype^.fType;
lastWasConst := false;
CheckForIncompleteStructType;
end; {else}
end; {FunctionCall}
@ -3586,7 +3697,7 @@ var
begin {GenerateCode}
lastwasconst := false;
isConst := false;
isNullPtrConst := false;
case tree^.token.kind of
@ -3611,17 +3722,18 @@ case tree^.token.kind of
arrayType: begin
LoadAddress(tree);
LoadAddress(tree, false);
expressionType := expressionType^.ptype;
end;
functionType:
LoadAddress(tree);
LoadAddress(tree, false);
structType, unionType: begin
LoadAddress(tree);
LoadAddress(tree, false);
if expressionType^.kind = pointerType then
expressionType := expressionType^.ptype;
CheckForIncompleteStructType;
end;
enumConst: begin
@ -3648,7 +3760,7 @@ case tree^.token.kind of
intConst,uintConst,ushortConst,charConst,scharConst,ucharConst: begin
Gen1t(pc_ldc, tree^.token.ival, cgWord);
lastwasconst := true;
isConst := true;
lastconst := tree^.token.ival;
isNullPtrConst := tree^.token.ival = 0;
if tree^.token.kind = intConst then
@ -3671,7 +3783,7 @@ case tree^.token.kind of
expressionType := longPtr
else
expressionType := ulongPtr;
lastwasconst := true;
isConst := true;
lastconst := tree^.token.lval;
isNullPtrConst := tree^.token.lval = 0;
end; {case longConst}
@ -3683,7 +3795,7 @@ case tree^.token.kind of
else
expressionType := ulonglongPtr;
if (tree^.token.qval.hi = 0) and (tree^.token.qval.lo >= 0) then begin
lastwasconst := true;
isConst := true;
lastconst := tree^.token.qval.lo;
end; {if}
isNullPtrConst := (tree^.token.qval.hi = 0) and (tree^.token.qval.lo = 0);
@ -3744,7 +3856,7 @@ case tree^.token.kind of
end; {with}
end {if}
else begin
LoadAddress(tree^.left);
LoadAddress(tree^.left, checkNullPointers);
lType := expressionType;
lisBitField := isBitField;
lbitDisp := bitDisp;
@ -3801,7 +3913,7 @@ case tree^.token.kind of
end {if}
else begin
doingScalar := false;
LoadAddress(tree^.left);
LoadAddress(tree^.left, checkNullPointers);
lisBitField := isBitField;
lbitDisp := bitDisp;
lbitSize := bitSize;
@ -4315,6 +4427,10 @@ case tree^.token.kind of
{NOTE: assumes aType & pType overlap in typeRecord}
else if not CompTypes(lType^.aType, expressionType^.aType) then
Error(47);
if checkNullPointers then begin
Gen0(pc_ckn);
Gen0(pc_ckp);
end; {if}
Gen0(pc_sbl);
if size <> 1 then begin
GenLdcLong(size);
@ -4481,6 +4597,19 @@ case tree^.token.kind of
end; {case}
end; {case uminus}
uplus: begin {unary +}
GenerateCode(tree^.left);
if expressionType^.kind <> scalarType then
error(66)
else case UsualUnaryConversions of
cgByte,cgUByte,cgWord,cgUWord,cgLong,cgULong,cgQuad,cgUQuad,
cgReal,cgDouble,cgComp,cgExtended:
;
otherwise:
error(66);
end; {case}
end; {case uplus}
tildech: begin {~}
GenerateCode(tree^.left);
if expressionType^.kind <> scalarType then
@ -4543,7 +4672,7 @@ case tree^.token.kind of
if not (tree^.left^.token.kind in
[ident,compoundliteral,stringconst,uasterisk]) then
L_Value(tree^.left);
LoadAddress(tree^.left);
LoadAddress(tree^.left, false);
if tree^.left^.token.kind = stringconst then begin
{build pointer-to-array type for address of string constant}
tType := pointer(Malloc(sizeof(typeRecord)));
@ -4567,6 +4696,9 @@ case tree^.token.kind of
lType := lType^.pType;
expressionType := lType;
isVolatile := tqVolatile in lType^.qualifiers;
if checkNullPointers then
if lType^.kind <> functionType then
Gen0(pc_ckp);
if lType^.kind = scalarType then
if lType^.baseType = cgVoid then
Gen2(pc_cnv, cgULong, cgVoid)
@ -4578,14 +4710,17 @@ case tree^.token.kind of
((lType^.kind in [functionType,arrayType,structType,unionType])
or ((lType^.kind = definedType) and {handle const struct/union}
(lType^.dType^.kind in [structType,unionType]))) then
Error(79);
Error(79)
else
CheckForIncompleteStructType;
end {if}
else
Error(79);
end; {case uasterisk}
dotch: begin {.}
LoadAddress(tree^.left);
LoadAddress(tree^.left, checkNullPointers);
isBitfield := false;
lType := expressionType;
if lType^.kind in [arrayType,pointerType,structType,unionType] then begin
if lType^.kind = arrayType then
@ -4703,6 +4838,7 @@ case tree^.token.kind of
if doDispose then
dispose(tree);
lastWasNullPtrConst := isNullPtrConst;
lastWasConst := isConst;
end; {GenerateCode}

1120
Gen.pas

File diff suppressed because it is too large Load Diff

View File

@ -15,10 +15,10 @@ interface
uses CCommon, MM, Scanner, Symbol, CGI;
{$segment 'SCANNER'}
{$segment 'HEADER'}
const
symFileVersion = 27; {version number of .sym file format}
symFileVersion = 44; {version number of .sym file format}
var
inhibitHeader: boolean; {should .sym includes be blocked?}
@ -721,6 +721,8 @@ procedure EndInclude {chPtr: ptr};
WriteByte(ord(token.ispstring));
WriteByte(ord(token.prefix));
end;
otherCharacter: WriteByte(ord(token.ch));
preprocessingNumber:WriteWord(token.errCode);
macroParameter: WriteWord(token.pnum);
reservedSymbol: if token.kind in [lbracech,rbracech,lbrackch,
rbrackch,poundch,poundpoundop] then
@ -800,7 +802,7 @@ procedure EndInclude {chPtr: ptr};
p_keep: WriteLongString(@pragmaKeepFile^.theString);
p_line: begin
WriteWord(lineNumber);
WriteLong(lineNumber);
WriteLongString(@sourceFileGS.theString);
end;
@ -826,6 +828,7 @@ procedure EndInclude {chPtr: ptr};
| (ord(profileFlag) << 2)
| (ord(traceBack) << 3)
| (ord(checkStack) << 4)
| (ord(checkNullPointers) << 5)
| (ord(debugStrFlag) << 15));
p_lint: begin
@ -886,13 +889,16 @@ procedure EndInclude {chPtr: ptr};
WriteByte(currentSegment[i]);
end; {for}
WriteWord(segmentKind);
WriteWord(defaultSegmentKind);
end;
p_unix: WriteByte(ord(unix_1));
p_fenv_access: WriteByte(ord(fenvAccess));
p_extensions: WriteByte(ord(extendedKeywords));
p_extensions:
WriteByte(ord(extendedKeywords)
| (ord(extendedParameters) << 1));
end; {case}
end; {if}
@ -1102,6 +1108,9 @@ procedure EndInclude {chPtr: ptr};
WriteByte(ord(ip^.isForwardDeclared));
WriteByte(ord(ip^.class));
WriteByte(ord(ip^.storage));
if ip^.storage = external then
WriteByte(ord(ip^.inlineDefinition));
{if ip^.storage = none then ip^.anonMemberField must be false}
end; {WriteIdent}
@ -1196,7 +1205,7 @@ type
var
done: boolean; {for loop termination test}
typeDispList: typeDispPtr; {type displacement/pointer table}
includeFileName: gsosInStringPtr; {name of include file}
includesPtr: ptr; {ptr to includes section from sym file}
i: 1..maxint; {loop/index variable}
@ -1297,7 +1306,6 @@ var
while len > 0 do begin
giRec.pCount := 7;
giRec.pathname := pointer(ReadLongString);
includeFileName := giRec.pathname; {save name to print later}
len := len - (giRec.pathname^.size + 18);
GetFileInfoGS(giRec);
if ToolError = 0 then begin
@ -1315,6 +1323,34 @@ var
end; {DatesMatch}
procedure PrintIncludes;
{ Print "Including ..." lines for the headers }
type
longptr = ^longint;
var
dataPtr: ptr; {pointer to data from sym file}
endPtr: ptr; {pointer to end of includes section}
i: 1..maxint; {loop/index variable}
includeNamePtr: gsosInStringPtr; {pointer to an include file name}
begin {PrintIncludes}
dataPtr := includesPtr;
endPtr := pointer(ord4(dataPtr) + longptr(dataPtr)^ + 4);
dataPtr := pointer(ord4(dataPtr) + 4);
while dataPtr <> endPtr do begin
includeNamePtr := gsosInStringPtr(dataPtr);
write('Including ');
for i := 1 to includeNamePtr^.size do
write(includeNamePtr^.theString[i]);
writeln;
dataPtr := pointer(ord4(dataPtr) + includeNamePtr^.size + 18);
end; {while}
end; {PrintIncludes}
procedure ReadMacroTable;
{ Read macros from the symbol file }
@ -1356,6 +1392,8 @@ var
token.ispstring := ReadByte <> 0;
token.prefix := charStrPrefixEnum(ReadByte);
end;
otherCharacter: token.ch := chr(ReadByte);
preprocessingNumber: token.errCode := ReadWord;
macroParameter: token.pnum := ReadWord;
reservedSymbol: if token.kind in [lbracech,rbracech,lbrackch,
rbrackch,poundch,poundpoundop] then
@ -1452,7 +1490,7 @@ var
end;
p_line: begin
lineNumber := ReadWord;
lineNumber := ReadLong - 1;
lsPtr := ReadLongString;
sourceFileGS.theString.size := lsPtr^.length;
for i := 1 to sourceFileGS.theString.size do
@ -1488,6 +1526,7 @@ var
profileFlag := odd(val >> 2);
traceback := odd(val >> 3);
checkStack := odd(val >> 4);
checkNullPointers := odd(val >> 5);
debugStrFlag := odd(val >> 15);
end;
@ -1556,13 +1595,18 @@ var
currentSegment[i] := chr(ReadByte);
end; {for}
segmentKind := ReadWord;
defaultSegmentKind := ReadWord;
end;
p_unix: unix_1 := boolean(ReadByte);
p_fenv_access: fenvAccess := boolean(ReadByte);
p_extensions: extendedKeywords := boolean(ReadByte);
p_extensions: begin
i := ReadByte;
extendedKeywords := odd(i);
extendedParameters := odd(i >> 1);
end;
otherwise: begin
PurgeSymbols;
@ -1797,6 +1841,11 @@ var
sp^.isForwardDeclared := boolean(ReadByte);
sp^.class := tokenEnum(ReadByte);
sp^.storage := storageType(ReadByte);
sp^.used := false;
if sp^.storage = none then
sp^.anonMemberField := false
else if sp^.storage = external then
sp^.inlineDefinition := boolean(ReadByte);
ReadIdent := sp;
end; {ReadIdent}
@ -1960,14 +2009,11 @@ if not ignoreSymbols then begin
PurgeSymbols;
typeDispList := nil;
while not done do begin
includesPtr := symPtr;
if DatesMatch then begin
if SourceMatches then begin
if progress then begin
write('Including ');
for i := 1 to includeFileName^.size do
write(includeFileName^.theString[i]);
writeln;
end; {if}
if progress then
PrintIncludes;
ReadMacroTable;
ReadSymbolTable;
ReadPragmas;

28
MM.pas
View File

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

BIN
Manual.docx Normal file

Binary file not shown.

View File

@ -87,7 +87,8 @@ lb1 lda nPeep+peep_opcode,X if npeep[i].opcode = d_lab then
inc fn
bra lab1 goto 1;
lb2 anop end;
lda nPeep+peep_opcode,X len := len+size[npeep[i].mode];
lda nPeep+peep_opcode,X len := len+size[npeep[i].opcode & ~asmFlag];
and #$7FFF
tay
lda size,Y
and #$00FF
@ -123,7 +124,8 @@ lb4 lda i while i < nnextspot do begin
inc fn
bra lab1 goto 1;
lb5 anop end;
lda nPeep+peep_opcode,X len := len+size[npeep[i].mode];
lda nPeep+peep_opcode,X len := len+size[npeep[i].opcode & ~asmFlag];
and #$7FFF
tay
lda size,Y
and #$00FF
@ -162,5 +164,5 @@ size dc i1'2,2,2,2,2,2,2,2,1,3,1,1,3,3,3,4'
dc i1'3,2,2,2,2,2,2,2,1,3,1,1,3,3,3,4'
dc i1'2,2,2,2,3,2,2,2,1,3,1,1,3,3,3,4'
dc i1'0,0,1,2,0,2,0,255'
dc i1'0,0,1,2,0,2,0,255,1,2,4'
end

View File

@ -110,6 +110,14 @@ procedure GenLab (lnum: integer);
{ lnum - label number }
procedure GenLabUsedOnce (lnum: integer);
{ generate a label that is only targeted by one branch }
{ }
{ parameters: }
{ lnum - label number }
procedure InitFile (keepName: gsosOutStringPtr; keepFlag: integer; partial: boolean);
{ Set up the object file }
@ -293,7 +301,7 @@ else begin
end; {if}
if shift <> 0 then begin
Out(129); {shift the address}
Out2(-shift); Out2(-1);
Out2(-shift); if (shift > 0) then Out2(-1) else Out2(0);
Out(7);
end; {if}
if lab <> maxlabel then {if not a string, end the expression}
@ -312,7 +320,7 @@ procedure UpDate (lab: integer; labelValue: longint);
{ labelValue - displacement in seg where label is located }
var
next,temp: labelptr; {work pointers}
next: labelptr; {work pointer}
begin {UpDate}
if labeltab[lab].defined then
@ -334,7 +342,6 @@ else begin
Out2(long(labelvalue).lsw);
Out2(long(labelvalue).msw);
blkcnt := blkcnt-4;
temp := next;
next := next^.next;
end; {while}
segdisp := blkcnt;
@ -358,9 +365,10 @@ procedure WriteNative (opcode: integer; mode: addressingMode; operand: integer;
label 1;
type
rkind = (k1,k2,k3,k4); {cnv record types}
rkind = (k1,k2,k3,k4,k5); {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}
@ -368,7 +376,8 @@ var
k1: (rval: real;);
k2: (dval: double;);
k3: (qval: longlong);
k4: (ival1,ival2,ival3,ival4: integer;);
k4: (eval: extended);
k5: (ival1,ival2,ival3,ival4,ival5: integer;);
end;
count: integer; {number of constants to repeat}
i,j,k: integer; {loop variables}
@ -394,7 +403,7 @@ var
pc := pc+1;
end {if}
else if (flags & localLab) <> 0 then
LabelSearch(long(name).lsw, 1, ord(odd(flags div shift16))*16, operand)
LabelSearch(long(name).lsw, 1, ord((flags & shift16) <> 0)*16, operand)
else if (flags & shift16) <> 0 then
RefName(name, operand, 1, -16)
else
@ -426,7 +435,7 @@ var
else if (flags & shift8) <> 0 then
RefName(name, operand, 2, -8)
else if (flags & localLab) <> 0 then
LabelSearch(long(name).lsw, 2, ord(odd(flags div shift16))*16, operand)
LabelSearch(long(name).lsw, 2, ord((flags & shift16) <> 0)*16, operand)
else if (flags & shift16) <> 0 then
RefName(name, operand, 2, -16)
else if name = nil then
@ -458,6 +467,26 @@ var
end; {DefGlobal}
function ShiftSize (flags: integer): integer;
{ Determine the shift size specified by flags. }
{ (Positive means right shift, negative means left shift.) }
{ }
{ parameters: }
{ flags - the flags }
begin {ShiftSize}
if (flags & shift8) <> 0 then
ShiftSize := 8
else if (flags & shift16) <> 0 then
ShiftSize := 16
else if (flags & shiftLeft8) <> 0 then
ShiftSize := -8
else
ShiftSize := 0;
end; {ShiftSize}
begin {WriteNative}
{ writeln('WriteNative: ',opcode:4, ', mode=', ord(mode):1,
' operand=', operand:1); {debug}
@ -474,6 +503,7 @@ case mode of
if not longA then
if operand = 255 then
goto 1;
opcode := opcode & ~asmFlag;
CnOut(opcode);
if opcode = m_pea then
GenImmediate2
@ -487,12 +517,12 @@ case mode of
else if opcode in [m_rep,m_sep,m_cop] then begin
GenImmediate1;
if opcode = m_rep then begin
if odd(operand div 32) then longA := true;
if odd(operand div 16) then longI := true;
if (operand & 32) <> 0 then longA := true;
if (operand & 16) <> 0 then longI := true;
end {if}
else if opcode = m_sep then begin
if odd(operand div 32) then longA := false;
if odd(operand div 16) then longI := false;
if (operand & 32) <> 0 then longA := false;
if (operand & 16) <> 0 then longI := false;
end; {else}
end {else}
else
@ -505,16 +535,16 @@ case mode of
longabs: begin
CnOut(opcode);
isJSL := opcode = m_jsl; {allow for dynamic segs}
isJSL := (opcode & ~asmFlag) = m_jsl; {allow for dynamic segs}
if name = nil then
if odd(flags div toolcall) then begin
if (flags & toolcall) <> 0 then begin
CnOut2(0);
CnOut(225);
end {if}
else
LabelSearch(operand, 3, 0, 0)
else
if odd(flags div toolcall) then begin
if (flags & toolcall) <> 0 then begin
CnOut2(long(name).lsw);
CnOut(long(name).msw);
end {if}
@ -524,7 +554,7 @@ case mode of
end;
longabsolute: begin
if opcode <> d_add then begin
if opcode <> d_dcl then begin
CnOut(opcode);
i := 3;
end {if}
@ -535,7 +565,7 @@ case mode of
else if (flags & constantOpnd) <> 0 then begin
lval := ord4(name);
CnOut2(long(lval).lsw);
if opcode = d_add then
if opcode = d_dcl then
CnOut2(long(lval).msw)
else
CnOut(long(lval).msw);
@ -545,13 +575,13 @@ case mode of
else begin
CnOut2(operand);
CnOut(0);
if opcode = d_add then
if opcode = d_dcl then
CnOut(0);
end; {else}
end;
absolute: begin
if opcode <> d_add then
if opcode <> d_dcw then
CnOut(opcode);
if (flags & localLab) <> 0 then
LabelSearch(long(name).lsw, 2, 0, operand)
@ -564,7 +594,7 @@ case mode of
end;
direct: begin
if opcode <> d_add then
if opcode <> d_dcb then
CnOut(opcode);
if (flags & localLab) <> 0 then
LabelSearch(long(name).lsw, 1, 0, operand)
@ -645,15 +675,28 @@ case mode of
CnOut(cns.inCOMP[j]);
end;
cgExtended : begin
cns.itsReal := icptr(name)^.rval;
CnvSX(cns);
for j := 1 to 10 do
CnOut(cns.inSANE[j]);
cnv.eval := icptr(name)^.rval;
CnOut2(cnv.ival1);
CnOut2(cnv.ival2);
CnOut2(cnv.ival3);
CnOut2(cnv.ival4);
CnOut2(cnv.ival5);
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
@ -701,7 +744,7 @@ case mode of
end;
genAddress: begin
if opcode < 256 then
if opcode < 256 then {includes opcodes with asmFlag}
CnOut(opcode);
if (flags & stringReference) <> 0 then begin
Purge;
@ -732,7 +775,7 @@ case mode of
else
LabelSearch(operand, 1, 16, 0)
else if (flags & subtract1) <> 0 then
LabelSearch(operand, 0, 0, 0)
LabelSearch(operand, 0, ShiftSize(flags), 0)
else
LabelSearch(operand, 2, 0, 0);
end;
@ -816,13 +859,13 @@ case p_opcode of
m_plx:
xRegister.condition := regUnknown;
m_bcc,m_bcs,m_beq,m_bmi,m_bne,m_bpl,m_bvs,
m_bcc,m_bcs,m_beq,m_bmi,m_bne,m_bpl,m_bvc,m_bvs,
m_pha,m_phb,m_phd,m_php,m_phx,m_phy,m_pei_dir,m_tcs:
goto 3;
m_bra,m_brl,m_clc,m_cmp_abs,m_cmp_dir,m_cmp_imm,m_cmp_s,m_cmp_indl,
m_cmp_indly,m_cpx_imm,m_jml,m_jmp_indX,m_plb,m_rtl,m_rts,m_sec,d_add,d_pin,
m_cpx_abs,m_cpx_dir,m_cmp_dirx,m_plp,m_cop,d_wrd: ;
m_cpx_abs,m_cpx_dir,m_cpy_imm,m_cmp_dirx,m_plp,m_cop,d_wrd: ;
m_pea: begin
if aRegister.condition = regImmediate then
@ -1448,9 +1491,9 @@ Out(0); {end the segment}
segDisp := 8; {update header}
Out2(long(pc).lsw);
Out2(long(pc).msw);
if pc > $0000FFFF then
if pc > $00010000 then
if currentSegment <> '~ARRAYS ' then
Error(112);
Error(184);
blkcnt := blkcnt-4; {purge the segment to disk}
segDisp := blkcnt;
CloseSeg;
@ -1525,10 +1568,10 @@ var
for i := ns to nnextSpot-1 do begin
opcode := npeep[i].opcode;
if opcode in
[m_bcc,m_bcs,m_beq,m_bmi,m_bne,m_bpl,m_bra,m_brl,m_bvs,m_jml,
[m_bcc,m_bcs,m_beq,m_bmi,m_bne,m_bpl,m_bra,m_brl,m_bvc,m_bvs,m_jml,
m_jmp_indX,m_jsl,m_lda_abs,m_lda_absx,m_lda_dir,m_lda_dirx,
m_lda_imm,m_lda_indl,m_lda_indly,m_lda_long,m_lda_longx,m_lda_s,
m_mvn,m_pla,m_rtl,m_rts,m_tdc,m_txa,m_tya,m_tsc,d_end,d_bmov,
m_pla,m_rtl,m_rts,m_tdc,m_txa,m_tya,m_tsc,d_end,d_bmov,
d_add,d_pin,d_wrd,d_sym,d_cns] then begin
ASafe := true;
goto 1;
@ -1602,7 +1645,7 @@ var
end; {if}
m_bcs,m_beq,m_bne,m_bmi,m_bpl,m_bcc:
if npeep[ns+2].opcode = d_lab then
if npeep[ns+2].opcode = d_lab then begin
if npeep[ns+2].operand = operand then
if npeep[ns+1].opcode = m_brl then begin
if Short(ns,npeep[ns+1].operand) then begin
@ -1637,7 +1680,22 @@ var
opcode := m_bcs
else
opcode := m_bmi;
end; {else if m_bra}
end {else if m_bra}
else if npeep[ns+3].opcode in [m_bra,m_brl] then
if Short(ns,npeep[ns+3].operand) then begin
operand := npeep[ns+3].operand;
if (npeep[ns+2].flags & labelUsedOnce) <> 0 then
Remove(ns+2);
end; {if}
end {if}
else if npeep[ns+3].opcode = d_lab then
if npeep[ns+3].operand = operand then
if npeep[ns+4].opcode in [m_bra,m_brl] then
if Short(ns,npeep[ns+4].operand) then begin
operand := npeep[ns+4].operand;
if (npeep[ns+3].flags & labelUsedOnce) <> 0 then
Remove(ns+3);
end; {if}
m_brl:
if Short(ns,operand) then begin
@ -1646,7 +1704,8 @@ var
didOne := true;
end; {if}
m_bvs:
{disabled because current codegen does not produce this sequence}
{m_bvs:
if npeep[ns+2].opcode = d_lab then
if npeep[ns+2].operand = operand then
if npeep[ns+1].opcode = m_bmi then
@ -1661,11 +1720,12 @@ var
Remove(ns+3);
end; {if}
m_dec_abs:
{disabled - can generate bad code}
{m_dec_abs:
if npeep[ns+1].opcode = m_lda_abs then
if name^ = npeep[ns+1].name^ then
if npeep[ns+2].opcode = m_beq then
Remove(ns+1);
Remove(ns+1);}
m_lda_abs:
if npeep[ns+1].opcode = m_clc then begin
@ -1740,13 +1800,52 @@ var
npeep[ns+2] := npeep[ns];
Remove(ns);
end {else if}
else if npeep[ns+1].opcode = m_xba then
else if npeep[ns+1].opcode = m_xba then begin
if npeep[ns+2].opcode = m_and_imm then
if npeep[ns+2].operand = $00FF then begin
operand := operand+1;
Remove(ns+1);
end {if}
end {else if}
else if npeep[ns+1].opcode = m_tay then
if npeep[ns+2].opcode in [m_lda_dir,m_lda_indly,m_pla] then begin
opcode := m_ldy_dir;
Remove(ns+1);
end {if}
else if npeep[ns+2].opcode = m_pld then
if npeep[ns+3].opcode = m_tsc then begin
opcode := m_ldy_dir;
Remove(ns+1);
end; {if}
m_ldx_dir:
if npeep[ns+1].opcode = m_txs then {optimize stack repair code}
if npeep[ns+2].opcode = m_tsx then begin
if npeep[ns+3].opcode = m_stx_dir then
if npeep[ns+3].operand = npeep[ns].operand then begin
Remove(ns+2);
Remove(ns+2);
end; {if}
end {if}
else if npeep[ns+2].opcode in
[m_sta_dir,m_sta_abs,m_sta_long,m_sta_indl,m_tyx] then begin
if (npeep[ns+2].opcode <> m_sta_dir)
or (npeep[ns+2].operand <> npeep[ns].operand) then
if npeep[ns+3].opcode = m_tsx then
if npeep[ns+4].opcode = m_stx_dir then
if npeep[ns+4].operand = npeep[ns].operand then begin
Remove(ns+3);
Remove(ns+3);
if npeep[ns+2].opcode = m_tyx then
Remove(ns+2);
end; {if}
end {else if}
else if npeep[ns+2].opcode = m_tsc then begin
npeep[ns].opcode := m_lda_dir;
npeep[ns+1].opcode := m_tcs;
Remove(ns+2);
end; {else if}
m_pei_dir:
if npeep[ns+1].opcode = m_pla then begin
opcode := m_lda_dir;
@ -1806,14 +1905,14 @@ var
if operand = npeep[ns+1].operand then
if name = npeep[ns+1].name then
if not (npeep[ns+2].opcode in
[m_bcc,m_bcs,m_beq,m_bmi,m_bne,m_bpl,m_bvs]) then
[m_bcc,m_bcs,m_beq,m_bmi,m_bne,m_bpl,m_bvc,m_bvs]) then
Remove(ns+1);
m_sta_dir:
if npeep[ns+1].opcode = m_lda_dir then
if operand = npeep[ns+1].operand then
if not (npeep[ns+2].opcode in
[m_bcc,m_bcs,m_beq,m_bmi,m_bne,m_bpl,m_bvs]) then
[m_bcc,m_bcs,m_beq,m_bmi,m_bne,m_bpl,m_bvc,m_bvs]) then
Remove(ns+1);
m_plb:
@ -1838,7 +1937,7 @@ var
end {if}
else if npeep[ns+1].opcode = m_txa then begin
if not (npeep[ns+2].opcode in
[m_bcc,m_bcs,m_beq,m_bmi,m_bne,m_bpl,m_bvs]) then begin
[m_bcc,m_bcs,m_beq,m_bmi,m_bne,m_bpl,m_bvc,m_bvs]) then begin
Remove(ns);
Remove(ns);
end; {if}
@ -1857,12 +1956,16 @@ var
m_tya:
if npeep[ns+1].opcode = m_sta_dir then begin
npeep[ns+1].opcode := m_sty_dir;
Remove(ns);
if ASafe(ns+2) then begin
npeep[ns+1].opcode := m_sty_dir;
Remove(ns);
end; {if}
end {if}
else if npeep[ns+1].opcode = m_sta_abs then begin
npeep[ns+1].opcode := m_sty_abs;
Remove(ns);
if ASafe(ns+2) then begin
npeep[ns+1].opcode := m_sty_abs;
Remove(ns);
end; {if}
end; {else if}
m_tyx:
@ -1876,7 +1979,8 @@ var
Remove(ns);
Remove(ns);
end {if}
else if npeep[ns+1].opcode in [m_ldx_abs,m_ldx_dir] then
else if npeep[ns+1].opcode in
[m_ldx_abs,m_ldx_dir,m_ldy_imm,m_ldy_dir] then
if npeep[ns+2].opcode = m_pla then begin
Remove(ns+2);
Remove(ns);
@ -1910,6 +2014,35 @@ var
if not volatile then
Remove(ns+1);
m_tcd:
if npeep[ns+1].opcode = m_tdc then
Remove(ns+1)
else if npeep[ns+1].opcode in [m_pea,m_stz_dir,m_stz_abs] then
if npeep[ns+2].opcode = m_tdc then
Remove(ns+2);
m_tcs:
if npeep[ns+1].opcode = m_tsx then
if npeep[ns+2].opcode = m_stx_dir then begin
npeep[ns+2].opcode := m_sta_dir;
Remove(ns+1);
end; {if}
m_tsx:
if npeep[ns+1].opcode = m_stx_dir then
if npeep[ns+2].opcode = m_pei_dir then
if npeep[ns+3].opcode = m_tsx then
if npeep[ns+4].opcode = m_stx_dir then
if npeep[ns+1].operand = npeep[ns+2].operand then
if npeep[ns+1].operand = npeep[ns+4].operand then
begin
npeep[ns+1].opcode := m_phx;
npeep[ns+1].mode := implied;
Remove(ns+2);
end; {if}
{extra explicit cases to ensure this case statement uses a jump table}
m_rtl,m_rts,m_jml,m_jsl,m_mvn,m_plp,m_pld,m_txs,
otherwise: ;
end; {case}
@ -1919,7 +2052,7 @@ var
begin {GenNative}
{ writeln('GenNative: ',p_opcode:4, ', mode=', ord(p_mode):1,
' operand=', p_operand:1); {debug}
if npeephole and not (strictVararg and hasVarargsCall) then begin
if npeephole then begin
if (nnextspot = 1) and not (p_opcode in nleadOpcodes) then begin
if p_opcode <> d_end then
if registers then
@ -2166,6 +2299,10 @@ case callNum of
92: sp := @'~DOUBLEPRECISION';
93: sp := @'~COMPPRECISION';
94: sp := @'~CUMUL2';
95: sp := @'~REALFIX';
96: sp := @'~DOUBLEFIX';
97: sp := @'~COMPFIX';
98: sp := @'~CHECKPTRC';
otherwise:
Error(cge1);
end; {case}
@ -2185,6 +2322,18 @@ GenNative(d_lab, gnrlabel, lnum, nil, 0);
end; {GenLab}
procedure GenLabUsedOnce {lnum: integer};
{ generate a label that is only targeted by one branch }
{ }
{ parameters: }
{ lnum - label number }
begin {GenLabUsedOnce}
GenNative(d_lab, gnrlabel, lnum, nil, labelUsedOnce);
end; {GenLabUsedOnce}
procedure InitFile {keepName: gsosOutStringPtr; keepFlag: integer; partial: boolean};
{ Set up the object file }
@ -2223,11 +2372,17 @@ procedure InitFile {keepName: gsosOutStringPtr; keepFlag: integer; partial: bool
{ set up the data bank register }
var
lisJSL: boolean; {saved copy of isJSL}
begin {SetDataBank}
lisJSL := isJSL;
isJSL := false;
CnOut(m_pea);
RefName(@'~GLOBALS', 0, 2, -8);
CnOut(m_plb);
CnOut(m_plb);
isJSL := lisJSL;
end; {SetDataBank}
@ -2237,6 +2392,12 @@ procedure InitFile {keepName: gsosOutStringPtr; keepFlag: integer; partial: bool
fname2.theString.size := length(fname2.theString.theString);
OpenObj(fname2);
{force this to be a static segment}
if (segmentKind & $8000) <> 0 then begin
currentSegment := ' ';
segmentKind := 0;
end; {if}
{write the header}
InitNative;
Header(@'~_ROOT', $4000, 0);
@ -2258,6 +2419,7 @@ procedure InitFile {keepName: gsosOutStringPtr; keepFlag: integer; partial: bool
CnOut(0);
{glue code for calling open routine}
isJSL := true;
CnOut(m_phb);
SetDataBank;
CnOut(m_jsl);
@ -2298,6 +2460,7 @@ procedure InitFile {keepName: gsosOutStringPtr; keepFlag: integer; partial: bool
RefName(initName, 0, 3, 0);
CnOut(m_plb);
CnOut(m_rtl);
isJSL := false;
end
{classic desk accessory initialization}
@ -2315,6 +2478,7 @@ procedure InitFile {keepName: gsosOutStringPtr; keepFlag: integer; partial: bool
RefName(lab, menuLen + dispToCDAClose, 4, 0);
{glue code for calling open routine}
isJSL := true;
CnOut(m_pea);
CnOut2(1);
CnOut(m_jsl);
@ -2341,33 +2505,40 @@ procedure InitFile {keepName: gsosOutStringPtr; keepFlag: integer; partial: bool
RefName(@'~DAID', 0, 3, 0);
CnOut(m_plb);
CnOut(m_rtl);
isJSL := false;
end
{control panel device initialization}
else if isCDev then begin
CnOut(m_pea);
CnOut2(1);
CnOut(m_phb); {save data bank}
SetDataBank; {set data bank}
CnOut(m_plx); {get RTL address & original data bank}
CnOut(m_ply);
CnOut(m_lda_s); CnOut(3); {move CDev parameters}
CnOut(m_pha);
CnOut(m_lda_s); CnOut(3);
CnOut(m_pha);
CnOut(m_lda_s); CnOut(9);
CnOut(m_sta_s); CnOut(5);
CnOut(m_lda_s); CnOut(11);
CnOut(m_sta_s); CnOut(7);
CnOut(m_lda_s); CnOut(13);
CnOut(m_sta_s); CnOut(9);
CnOut(m_sta_s); CnOut(15); {store message in result space}
CnOut(m_lda_long); {store original user ID in result space}
RefName(@'~USER_ID',0,3,0);
CnOut(m_sta_s); CnOut(17);
CnOut(m_txa); {save RTL address & original data bank}
CnOut(m_sta_s); CnOut(11);
CnOut(m_tya);
CnOut(m_sta_s); CnOut(13);
CnOut(m_pea); CnOut2(1); {get user ID}
CnOut(m_jsl);
RefName(@'~DAID', 0, 3, 0);
CnOut(m_phb);
SetDataBank;
CnOut(m_pla);
CnOut(m_sta_s); CnOut(13);
CnOut(m_pla);
CnOut(m_sta_s); CnOut(13);
CnOut(m_jsl);
CnOut(m_jsl); {call CDev main routine}
RefName(openName,0,3,0);
CnOut(m_tay);
CnOut(m_lda_s); CnOut(3);
CnOut(m_pha);
CnOut(m_lda_s); CnOut(3);
CnOut(m_pha);
CnOut(m_txa);
CnOut(m_sta_s); CnOut(7);
CnOut(m_tya);
CnOut(m_sta_s); CnOut(5);
CnOut(m_plb);
CnOut(m_rtl);
CnOut(m_jml); {clean up and return to caller}
RefName(@'~CDEVCLEANUP', 0, 3, 0);
end
{NBA initialization}
@ -2398,6 +2569,7 @@ procedure InitFile {keepName: gsosOutStringPtr; keepFlag: integer; partial: bool
else begin
{write the initial JSL}
isJSL := true;
CnOut(m_jsl);
if rtl then
RefName(@'~_BWSTARTUP4', 0, 3, 0)
@ -2407,6 +2579,17 @@ procedure InitFile {keepName: gsosOutStringPtr; keepFlag: integer; partial: bool
{set the data bank register}
SetDataBank;
{set FPE slot, if using FPE}
if floatCard = 1 then begin
CnOut(m_lda_imm);
if floatSlot in [1..7] then
CnOut2(floatSlot)
else
CnOut2(0);
CnOut(m_jsl);
RefName(@'~INITFLOAT', 0, 3, 0);
end; {if}
{write JSL to main entry point}
CnOut(m_jsl);
if rtl then
@ -2415,7 +2598,8 @@ procedure InitFile {keepName: gsosOutStringPtr; keepFlag: integer; partial: bool
RefName(@'~C_STARTUP', 0, 3, 0);
CnOut(m_jsl);
RefName(@'main', 0, 3, 0);
CnOut(m_jsl);
isJSL := false;
CnOut(m_jml);
if rtl then
RefName(@'~C_SHUTDOWN2', 0, 3, 0)
else
@ -2434,6 +2618,7 @@ procedure InitFile {keepName: gsosOutStringPtr; keepFlag: integer; partial: bool
begin {SetStack}
if stackSize <> 0 then begin
currentSegment := '~_STACK '; {write the header}
segmentKind := 0;
Header(@'~_STACK', $4012, 0);
Out($F1); {write the DS record to reserve space}
Out2(stackSize);
@ -2472,10 +2657,10 @@ xRegister.condition := regUnknown;
yRegister.condition := regUnknown;
lastRegOpcode := 0; {BRK}
nnextspot := 1;
nleadOpcodes := [m_asl_a,m_bcs,m_beq,m_bmi,m_bne,m_bpl,m_brl,m_bvs,m_bcc,
m_dec_abs,m_lda_abs,m_lda_dir,m_lda_imm,m_ldx_imm,m_sta_abs,m_sta_dir,
m_pha,m_plb,m_plx,m_tax,m_tya,m_tyx,m_phy,m_pei_dir,m_ldy_imm,m_rep,
m_ora_dir,m_ora_abs,m_and_imm,m_pea];
nleadOpcodes := [m_asl_a,m_bcc,m_bcs,m_beq,m_bmi,m_bne,m_bpl,m_brl,{m_bvs,}
{m_dec_abs,}m_lda_abs,m_lda_dir,m_lda_imm,m_ldx_imm,m_sta_abs,m_sta_dir,
m_pha,m_plb,{m_plx,}m_tax,m_tya,m_tyx,m_phy,m_pei_dir,m_ldy_imm,m_rep,
m_ora_dir,m_ora_abs,m_and_imm,m_pea,m_tcd];
nstopOpcodes := [d_end,d_pin];
stringSize := 0; {initialize scalars for a new segment}

View File

@ -33,6 +33,7 @@
#define clearAction 0x0009
#define sysClickAction 0x000A
#define optionalCloseAction 0x000B
#define reOpenAction 0x000C
/* SystemEdit Codes */
#define undoEdit 0x0001

View File

@ -35,6 +35,6 @@ int fcntl(int, int, ...);
long lseek(int, long, int);
int open(const char *, int, ...);
int read(int, void *, unsigned);
int write(int, void *, unsigned);
int write(int, const void *, unsigned);
#endif

View File

@ -38,13 +38,13 @@ int __get_flt_rounds(void);
#define DBL_DIG 15
#define LDBL_DIG 18
#define FLT_MIN_EXP -125
#define DBL_MIN_EXP -1021
#define LDBL_MIN_EXP -16382
#define FLT_MIN_EXP (-125)
#define DBL_MIN_EXP (-1021)
#define LDBL_MIN_EXP (-16382)
#define FLT_MIN_10_EXP -37
#define DBL_MIN_10_EXP -307
#define LDBL_MIN_10_EXP -4931
#define FLT_MIN_10_EXP (-37)
#define DBL_MIN_10_EXP (-307)
#define LDBL_MIN_10_EXP (-4931)
#define FLT_MAX_EXP 128
#define DBL_MAX_EXP 1024

View File

@ -14,13 +14,17 @@
#ifndef __GSBUG__
#define __GSBUG__
/* Error Codes */
#define debugUnImpErr 0xFF01
#define debugBadSelErr 0xFF02
#define dgiProgramCounter 0 /* for DebugGetInfo */
extern pascal Word DebugVersion() inline(0x04FF,dispatcher);
extern pascal Word DebugStatus() inline(0x06FF,dispatcher);
extern pascal void DebugStr() inline(0x09FF,dispatcher);
extern pascal void SetMileStone() inline(0x0AFF,dispatcher);
extern pascal void DebugSetHook() inline(0x0BFF,dispatcher);
extern pascal LongWord DebugGetInfo() inline(0x0CFF,dispatcher);
extern pascal Word DebugVersion(void) inline(0x04FF,dispatcher);
extern pascal Word DebugStatus(void) inline(0x06FF,dispatcher);
extern pascal void DebugStr(Pointer) inline(0x09FF,dispatcher);
extern pascal void SetMileStone(Pointer) inline(0x0AFF,dispatcher);
extern pascal void DebugSetHook(VoidProcPtr) inline(0x0BFF,dispatcher);
extern pascal LongWord DebugGetInfo(Word) inline(0x0CFF,dispatcher);
#endif

View File

@ -126,7 +126,7 @@
#define invalidFSTop 0x0065 /* invalid FST operation */
#define fstCaution 0x0066 /* FST handled call, but result is weird */
#define devNameErr 0x0067 /* device exists with same name as replacement name */
#define defListFull 0x0068 /* device list is full */
#define devListFull 0x0068 /* device list is full */
#define supListFull 0x0069 /* supervisor list is full */
#define fstError 0x006a /* generic FST error */
#define resExistsErr 0x0070 /* cannot expand file, resource already exists */

View File

@ -102,6 +102,12 @@ long double cosl(long double);
double cosh(double);
float coshf(float);
long double coshl(long double);
double erf(double);
float erff(float);
long double erfl(long double);
double erfc(double);
float erfcf(float);
long double erfcl(long double);
double exp(double);
float expf(float);
long double expl(long double);
@ -120,6 +126,9 @@ long double fdiml(long double, long double);
double floor(double);
float floorf(float);
long double floorl(long double);
double fma(double, double, double);
float fmaf(float, float, float);
long double fmal(long double, long double, long double);
double fmax(double, double);
float fmaxf(float, float);
long double fmaxl(long double, long double);
@ -141,6 +150,9 @@ int ilogbl(long double);
double ldexp(double, int);
float ldexpf(float, int);
long double ldexpl(long double, int);
double lgamma(double);
float lgammaf(float);
long double lgammal(long double);
#if defined(__ORCAC_HAS_LONG_LONG__) || __STDC_VERSION__ >= 199901L
long long llrint(double);
long long llrintf(float);
@ -221,6 +233,9 @@ long double tanl(long double);
double tanh(double);
float tanhf(float);
long double tanhl(long double);
double tgamma(double);
float tgammaf(float);
long double tgammal(long double);
double trunc(double);
float truncf(float);
long double truncl(long double);

View File

@ -277,9 +277,18 @@
#define sbAlertCaution 0x0054
#define sbScreenBlanking 0x0060
#define sbScreenUnblanking 0x0061
#define sbBeginningLongOperation 0x0070
#define sbYouHaveMail 0x0100
#define sbErrorWindowBase 0x0E00 /* uses $0Exx */
#define sbErrorWindowOther 0x0EFF
#define sbFileTransferred 0x0F80
#define sbRealtimeMessage 0x0F81
#define sbConnectedToService 0x1000
#define sbDisconnectedFromService 0x1001
#define sbEnteredRealtimeChat 0x1002
#define sbLeftRealtimeChat 0x1003
#define sbFeatureEnabled 0x1010
#define sbFeatureDisabled 0x1011
/* StringToText constants */
#define fAllowMouseText 0x8000

View File

@ -53,6 +53,7 @@
#define resConverter 0x0800
#define resMemAttr 0xC31C /* Flags passed to the NewHandle Memory Manager call */
#define systemMap 0x0001
#define fileReadWrite 0x0001
#define mapChanged 0x0002
#define romMap 0x0004
#define resNameOffset 0x10000 /* type holding names */

View File

@ -31,7 +31,7 @@ typedef char *__va_list[2];
typedef __va_list va_list;
#define va_end(ap) __record_va_info(ap)
#define va_start(ap,LastFixedParm) ((void) ((ap)[0] = (char *) (&LastFixedParm + 1), (ap)[1] = (char *)&__orcac_va_info))
#define va_start(ap,LastFixedParm) ((void) ((ap)[0] = (char *)__orcac_va_info[1], (ap)[1] = (char *)&__orcac_va_info))
#define va_arg(ap,type) _Generic(*(type *)0, \
double: (type)((long double *)((ap)[0] += sizeof(long double)))[-1], \
default: ((type *)((ap)[0] += sizeof(type)))[-1])

View File

@ -85,6 +85,9 @@ typedef struct __file {
extern FILE *stderr; /* standard I/O files */
extern FILE *stdin;
extern FILE *stdout;
#define stderr stderr
#define stdin stdin
#define stdout stdout
#define L_tmpnam 26 /* size of a temp name */
#define TMP_MAX 10000 /* # of unique temp names */
@ -125,7 +128,9 @@ long int ftell(FILE *);
size_t fwrite(const void *, size_t, size_t, FILE *);
int getc(FILE *);
int getchar(void);
#if !defined(__KeepNamespacePure__) || __STDC_VERSION__ < 201112L
char *gets(char *);
#endif
void perror(const char *);
int printf(const char *, ...);
int putc(int, FILE *);

View File

@ -23,7 +23,7 @@ typedef unsigned long size_t;
#endif
#ifndef __KeepNamespacePure__
char *c2pstr(char *);
char *c2pstr(const char *);
#endif
void *memchr(const void *, int, size_t);
int memcmp(const void *, const void *, size_t);
@ -31,7 +31,7 @@ void *memcpy(void *, const void *, size_t);
void *memmove(void *, const void *, size_t);
void *memset(void *, int, size_t);
#ifndef __KeepNamespacePure__
char *p2cstr(char *);
char *p2cstr(const char *);
#endif
char *strcat(char *, const char *);
char *strchr(const char *, int);
@ -46,12 +46,12 @@ int strncmp(const char *, const char *, size_t);
char *strncpy(char *, const char *, size_t);
char *strpbrk(const char *, const char *);
#ifndef __KeepNamespacePure__
int strpos(char *, char);
int strpos(const char *, char);
#endif
char *strrchr(const char *, int);
#ifndef __KeepNamespacePure__
char *strrpbrk(char *, char *);
int strrpos(char *, char);
char *strrpbrk(const char *, const char *);
int strrpos(const char *, char);
#endif
size_t strspn(const char *, const char *);
char *strstr(const char *, const char *);

View File

@ -32,6 +32,16 @@
long double: fn##l, \
default: _Generic((y), long double: fn##l, default: fn))((x),(y),(other))
#define __tg_real_x_y_z(fn,x,y,z) _Generic((x), \
float: _Generic((y), \
float: _Generic((z), float: fn##f, long double: fn##l, default: fn), \
long double: fn##l, \
default: _Generic((z), long double: fn##l, default: fn)), \
long double: fn##l, \
default: _Generic((y), \
long double: fn##l, \
default: _Generic((z), long double: fn##l, default: fn)))((x),(y),(z))
#define __tg_x(fn,x) __tg_real_x(fn,(x))
#define __tg_x_y(fn,x,y) __tg_real_x_y(fn,(x),(y))
@ -47,11 +57,14 @@
#define cos(x) __tg_x(cos,(x))
#define cosh(x) __tg_x(cosh,(x))
#define copysign(x,y) __tg_real_x_y(copysign,(x),(y))
#define erf(x) __tg_real_x(erf,(x))
#define erfc(x) __tg_real_x(erfc,(x))
#define exp(x) __tg_x(exp,(x))
#define exp2(x) __tg_real_x(exp2,(x))
#define expm1(x) __tg_real_x(expm1,(x))
#define fabs(x) __tg_real_x(fabs,(x))
#define fdim(x,y) __tg_real_x_y(fdim,(x),(y))
#define fma(x,y,z) __tg_real_x_y_z(fma,(x),(y),(z))
#define fmax(x,y) __tg_real_x_y(fmax,(x),(y))
#define fmin(x,y) __tg_real_x_y(fmin,(x),(y))
#define floor(x) __tg_real_x(floor,(x))
@ -60,6 +73,7 @@
#define hypot(x,y) __tg_real_x_y(hypot,(x),(y))
#define ilogb(x) __tg_real_x(ilogb,(x))
#define ldexp(x,n) __tg_real_x_other(ldexp,(x),(n))
#define lgamma(x) __tg_real_x(lgamma,(x))
#define llrint(x) __tg_real_x(llrint,(x))
#define llround(x) __tg_real_x(llround,(x))
#define log(x) __tg_x(log,(x))
@ -84,6 +98,7 @@
#define sqrt(x) __tg_x(sqrt,(x))
#define tan(x) __tg_x(tan,(x))
#define tanh(x) __tg_x(tanh,(x))
#define tgamma(x) __tg_real_x(tgamma,(x))
#define trunc(x) __tg_real_x(trunc,(x))
#endif

View File

@ -28,12 +28,22 @@ struct tm {
int tm_isdst;
};
#ifndef __struct_timespec__
#define __struct_timespec__
struct timespec {
time_t tv_sec;
long tv_nsec;
};
#endif
clock_t __clocks_per_sec(void);
#ifndef __KeepNamespacePure__
#define CLK_TCK (__clocks_per_sec())
#endif
#define CLOCKS_PER_SEC (__clocks_per_sec())
#define TIME_UTC 1
#ifndef NULL
#define NULL (void *) 0L
#endif
@ -43,6 +53,8 @@ clock_t __clocks_per_sec(void);
typedef unsigned long size_t;
#endif
extern int __useTimeTool;
char *asctime(const struct tm *);
clock_t clock(void);
char *ctime(const time_t *);
@ -52,5 +64,6 @@ struct tm *localtime(const time_t *);
time_t mktime(struct tm *);
size_t strftime(char *, size_t, const char *, const struct tm *);
time_t time(time_t *);
int timespec_get(struct timespec *, int);
#endif

View File

@ -66,6 +66,7 @@
#define tmControlMenu 0x00040000L
#define tmMultiClick 0x00080000L
#define tmIdleEvents 0x00100000L
#define tmNoGetNextEvent 0x00200000L
/* TaskMaster Codes */
#define wNoHit 0x0000 /* retained for back compatibility */

View File

@ -144,23 +144,18 @@ Out start CodeGen
*
OutByte private CodeGen
lda objLen if objLen+segDisp = buffSize then
lda objLen if objLen+segDisp >= buffSize then
clc
adc segDisp
lda objLen+2
adc segDisp+2
and #$FFFE
beq lb2
phx PurgeObjBuffer;
jsl PurgeObjBuffer
and minusBuffSize+2
beq lb2
phx MakeSpaceInObjBuffer;
jsl MakeSpaceInObjBuffer
plx
lda objLen check for segment overflow
clc
adc segDisp
lda objLen+2
adc segDisp+2
and #$FFFE
bne lb2a
lb2 anop carry must be clear
lda objPtr+2 p := pointer(ord4(objPtr)+segDisp);
adc segDisp+2
@ -183,13 +178,6 @@ lb2 anop carry must be clear
adc #4
tcs
rts
lb2a lda #$8000 handle a segment overflow
sta segDisp
stz segDisp+2
ph2 #112
jsl Error
rts
end
****************************************************************
@ -203,25 +191,20 @@ lb2a lda #$8000 handle a segment overflow
*
OutWord private CodeGen
lda objLen if objLen+segDisp+1 = buffSize then
lda objLen if objLen+segDisp+1 >= buffSize then
sec
adc segDisp
lda objLen+2
adc segDisp+2
and #$FFFE
beq lb2
phx PurgeObjBuffer;
jsl PurgeObjBuffer
and minusBuffSize+2
beq lb2
phx MakeSpaceInObjBuffer;
jsl MakeSpaceInObjBuffer
plx
lda objLen check for segment overflow
sec
adc segDisp
lda objLen+2
adc segDisp+2
and #$FFFE
bne lb3
lb2 anop carry must be clear
lda objPtr+2 p := pointer(ord4(objPtr)+segDisp);
clc
lb2 anop carry must be clear
lda objPtr+2 p := pointer(ord4(objPtr)+segDisp);
adc segDisp+2
pha
lda objPtr
@ -240,11 +223,4 @@ lb2 anop carry must be clear
adc #4
tcs
rts
lb3 ph2 #112 flag segment overflow error
jsl Error
lda #$8000
sta segDisp
stz segDisp+2
rts
end

View File

@ -138,9 +138,8 @@ procedure Purge;
implementation
const
{NOTE: OutByte and Outword assume }
{ buffSize is 128K }
buffSize = 131072; {size of the obj buffer}
initialBuffSize = $10000; {initial size of the obj buffer}
{NOTE: must be a power of two >= 64K}
maxCBuffLen = 191; {length of the constant buffer}
OBJ = $B1; {object file type}
@ -217,9 +216,9 @@ var
objLen: longint; {# bytes used in obj buffer}
objHandle: handle; {handle of the obj buffer}
objPtr: ptr; {pointer to the next spot in the obj buffer}
objPtr: ptr; {points to first byte in current segment}
minusBuffSize: longint; {size of obj buffer, negated}
segStart: ptr; {points to first byte in current segment}
spoolRefnum: integer; {reference number for open file}
{---------------------------------------------------------------}
@ -276,7 +275,7 @@ var
begin {InitSpoolFile}
if memoryCompile then {make sure this is a disk-based compile}
TermError(11);
TermError(3);
dsRec.pCount := 1; {destroy any old file}
dsRec.pathname := @objFile.theString;
DestroyGS(dsRec);
@ -303,7 +302,7 @@ begin {PurgeObjBuffer}
if spoolRefnum = 0 then {make sure the spool file exists}
InitSpoolFile;
sPtr := objHandle^; {determine size of completed segments}
len := ord4(segStart) - ord4(sPtr);
len := ord4(objPtr) - ord4(sPtr);
if len <> 0 then begin
wrRec.pcount := 4; {write completed segments}
wrRec.refnum := spoolRefnum;
@ -313,13 +312,38 @@ if len <> 0 then begin
if ToolError <> 0 then {check for write errors}
TermError(9);
objLen := 0; {adjust file pointers}
BlockMove(segStart, sPtr, segDisp);
BlockMove(objPtr, sPtr, segDisp);
objPtr := sPtr;
segStart := sPtr;
end; {if}
end; {PurgeObjBuffer}
procedure MakeSpaceInObjBuffer;
{ Make space in the object buffer (at least two bytes) by }
{ purging or expanding it. }
var
segOffset: longint; {offset into buffer of current segment}
begin {MakeSpaceInObjBuffer}
segOffset := ord4(objPtr) - ord4(objHandle^);
if (segOffset >= 2) and not memoryCompile then
PurgeObjBuffer
else begin
{resize the buffer}
minusBuffSize := minusBuffSize * 2;
HUnLock(objHandle);
SetHandleSize(-minusBuffSize, objHandle);
if ToolError <> 0 then
TermError(5);
HLock(objHandle);
objPtr := ptr(ord4(objHandle^) + segOffset);
end; {if}
end; {MakeSpaceInObjBuffer}
{---------------------------------------------------------------}
procedure CloseObj;
@ -439,10 +463,9 @@ longPtr := pointer(objPtr); {set the block count}
longPtr^ := segDisp;
objLen := objLen + segDisp; {update the length of the obj file}
objPtr := pointer(ord4(objHandle^)+objLen); {set objPtr}
segStart := objPtr;
if objLen = buffSize then
PurgeObjBuffer;
currentSegment := defaultSegment; {revert to default segment name}
segDisp := 0;
currentSegment := defaultSegment; {revert to default segment name & kind}
segmentKind := defaultSegmentKind;
end; {CloseSeg}
@ -526,7 +549,6 @@ procedure OpenSeg;
begin {OpenSeg}
segDisp := 0;
segStart := objPtr;
end; {OpenSeg}
@ -559,12 +581,13 @@ if memoryCompile then begin
end; {if}
{allocate memory for an initial buffer}
objHandle := pointer(NewHandle(buffSize, userID, $8000, nil));
objHandle := pointer(NewHandle(initialBuffSize, userID, $8000, nil));
{set up the buffer variables}
if ToolError = 0 then begin
objLen := 0;
objPtr := objHandle^;
minusBuffSize := -initialBuffSize;
end {if}
else
TermError(5);

2094
Parser.pas

File diff suppressed because it is too large Load Diff

View File

@ -52,7 +52,7 @@ const
feature_ll = true;
feature_s_long = false;
feature_n_size = true;
feature_scanf_ld = false;
feature_scanf_ld = true;
type
length_modifier = (default, h, hh, l, ll, j, z, t, ld);
@ -136,7 +136,7 @@ var
WriteLine;
if s <> nil then begin
Write(' > "');
for i := 1 to s^.length do begin
for i := 1 to s^.length-1 do begin
ch := s^.str[i];
if ch in [' '..'~'] then begin
if ch in ['"','\','?'] then
@ -167,13 +167,13 @@ var
Write(' ');
if offset = 0 then
if s <> nil then begin
offset := s^.length;
offset := s^.length-1;
write(' ');
end; {if}
if offset > 0 then begin
if s <> nil then begin
if offset > s^.length then
offset := s^.length;
if s <> nil then begin
if offset > 0 then begin
if offset > s^.length-1 then
offset := s^.length-1;
for i := 1 to offset do begin
ch := s^.str[i];
if ch in [' '..'~'] then begin

View File

@ -49,4 +49,4 @@ Alternatively, you can keep the LF line endings in your working copy of the Git
[udl]: http://ftp.gno.org/pub/apple2/gs.specific/gno/file.convert/udl.114.shk
In addition to converting the line endings, you will also have to set the files to the appropriate file types before building ORCA/C on a IIGS. The included `settypes` script (for use under the ORCA shell) does this for the sources to the ORCA/C compiler itself, although it does not currently cover the test cases and headers.
In addition to converting the line endings, you will also have to set the files to the appropriate file types before building ORCA/C on a IIGS. The included `settypes` script (for use under the ORCA shell) can be used to do this.

View File

@ -465,7 +465,7 @@ cch equ 13
enum (illegal,ch_special,ch_dash,ch_plus,ch_lt,ch_gt,ch_eq,ch_exc),0
enum (ch_and,ch_bar,ch_dot,ch_white,ch_eol,ch_eof,ch_char,ch_string)
enum (ch_asterisk,ch_slash,ch_percent,ch_carot,ch_pound,ch_colon)
enum (ch_backslash,letter,digit)
enum (ch_backslash,ch_other,letter,digit)
! begin {NextCh}
tsc create stack frame
@ -520,8 +520,10 @@ la2 anop
lda #eolChar
sta ch
brl le2
! CheckConditionals;
la3 jsl CheckConditionals
! ch := chr(eofChar);
la3 stz ch
stz ch
! if needWriteLine then begin {do eol processing}
! WriteLine;
@ -533,7 +535,7 @@ la3 stz ch
beq lb1
jsl WriteLine
stz wroteLine
inc lineNumber
inc4 lineNumber
move4 chPtr,firstPtr
lb1 anop
@ -548,19 +550,26 @@ lb2 anop
brl le2
! else begin
lb3 anop
! {purge the current source file}
! with ffDCBGS do begin
! pCount := 5;
! if not doingFakeFile then begin
lda doingFakeFile
bne lb3a
! {purge the current source file}
! with ffDCBGS do begin
! pCount := 5;
lda #5
sta ffDCBGS
! action := 7;
! action := 7;
lda #7
sta ffDCBGS+2
! name := @includeFileGS.theString
! name := @includeFileGS.theString
lla ffDCBGS+12,includeFileGS+2
! end; {with}
! FastFileGS(ffDCBGS);
! end; {with}
! FastFileGS(ffDCBGS);
FastFileGS ffDCBGS
! end; {if}
lb3a anop
! doingFakeFile := false;
stz doingFakeFile
! fp := fileList; {open the file that included this one}
move4 fileList,fp
! fileList := fp^.next;
@ -589,6 +598,10 @@ lb4 lda [p1],Y
ldy #4+maxPath+4+maxPath+4
lda [fp],Y
sta lineNumber
iny
iny
lda [fp],Y
sta lineNumber+2
! ReadFile;
jsl ReadFile
! eofPtr := pointer(ord4(bofPtr) + ffDCBGS.fileLength);
@ -596,7 +609,7 @@ lb4 lda [p1],Y
! chPtr := pointer(ord4(bofPtr) + fp^.disp);
! includeChPtr := chPtr;
! firstPtr := chPtr;
ldy #4+maxPath+4+maxPath+4+2
ldy #4+maxPath+4+maxPath+4+4
clc
lda bofPtr
adc [fp],Y
@ -617,8 +630,13 @@ lb4 lda [p1],Y
jsl ~Dispose
! includeCount := includeCount + 1;
inc includeCount
! if inhibitHeader then
lda inhibitHeader
beq lb4a
! TermHeader;
jsl TermHeader
! goto 1;
brl lab1
lb4a brl lab1
! end; {if}
! end {if}
@ -641,7 +659,7 @@ lb5 anop
beq lb6
jsl WriteLine
stz wroteLine
inc lineNumber
inc4 lineNumber
move4 chPtr,firstPtr
lb6 anop
! needWriteLine := charKinds[ord(ch)] = ch_eol;
@ -727,11 +745,16 @@ lc2 anop
lda chPtr+2
cmp eofPtr+2
jeq lc5
! else if (cch = '/') and (chPtr^ = return) then begin
! else if (cch = '/') then begin
lc2a lda cch
cmp #'/'
bne lc2b
! if charKinds[ord(ch)] = ch_eol then
! if (charKinds[ord(chPtr^)] = ch_eol)
! and (ptr(ord4(chPtr)-1)^ <> '\')
! and ((ptr(ord4(chPtr)-1)^ <> '/')
! or (ptr(ord4(chPtr)-2)^ <> '?')
! or (ptr(ord4(chPtr)-3)^ <> '?'))
! then
! done := true
! else
! chPtr := pointer(ord4(chPtr)+1);
@ -742,8 +765,19 @@ lc2a lda cch
tax
lda charKinds,X
cmp #ch_eol
jeq lc5
inc4 chPtr
bne lc2aa
dec4 p1
lda [p1]
and #$00FF
cmp #'\'
beq lc2aa
cmp #'/'
jne lc5
sub4 p1,#2
lda [p1]
cmp #'??'
jne lc5
lc2aa inc4 chPtr
bra lc2
! end {else if}
! else begin
@ -765,7 +799,7 @@ lc2b move4 chPtr,p1
bne lc3
jsl WriteLine
stz wroteLine
inc lineNumber
inc4 lineNumber
add4 chPtr,#1,firstPtr
lc3 anop
! chPtr := pointer(ord4(chPtr)+1);

View File

@ -636,3 +636,48 @@
.f
mnote "Missing closing '}'",16
mend
macro
&l sub4 &m1,&m2,&m3
lclb &yistwo
lclc &c
&l ~setm
aif c:&m3,.a
&c amid "&m2",1,1
aif "&c"<>"#",.a
&c amid "&m1",1,1
aif "&c"="{",.a
aif "&c"="[",.a
&c amid "&m2",2,l:&m2-1
aif &c>=65536,.a
sec
~lda &m1
~op sbc,&m2
~sta &m1
bcs ~&SYSCNT
~op.h dec,&m1
~&SYSCNT anop
ago .c
.a
aif c:&m3,.b
lclc &m3
&m3 setc &m1
.b
sec
~lda &m1
~op sbc,&m2
~sta &m3
~lda.h &m1
~op.h sbc,&m2
~sta.h &m3
.c
~restm
mend
macro
&l dec4 &a
&l ~setm
lda &a
bne ~&SYSCNT
dec 2+&a
~&SYSCNT dec &a
~restm
mend

File diff suppressed because it is too large Load Diff

View File

@ -9,11 +9,12 @@
****************************************************************
*
ClearTable private cc
tableSize equ 7026 sizeof(symbolTable)
hashSize2 equ 1753 # hash buckets * 2 - 1
sizeofBuckets equ 4*(hashSize2+1) sizeof(symbolTable.buckets)
subroutine (4:table),0
ldy #tableSize-2
ldy #sizeofBuckets-2
lda #0
lb1 sta [table],Y
dey
@ -22,3 +23,19 @@ lb1 sta [table],Y
return
end
****************************************************************
*
* SaveBF - save a value to a bit-field
*
* Inputs:
* addr - address to copy to
* bitdisp - displacement past the address
* bitsize - number of bits
* val - value to copy
*
****************************************************************
*
SaveBF private cc
jml ~SaveBF call ~SaveBF in ORCALib
end

View File

@ -22,7 +22,6 @@
{ }
{ External Variables: }
{ }
{ noDeclarations - have we declared anything at this level? }
{ table - current symbol table }
{ }
{ charPtr - pointer to the base type for char }
@ -69,17 +68,22 @@ uses CCommon, CGI, MM, Scanner;
{---------------------------------------------------------------}
const
staticNumLen = 5; {length of staticNum name prefix}
type
symbolTablePtr = ^symbolTable;
symbolTable = record {a symbol table}
{NOTE: the array of buckets must come first in the record!}
buckets: array[0..hashSize2] of identPtr; {hash buckets}
next: symbolTablePtr; {next symbol table}
staticNum: packed array[1..6] of char; {staticNum at start of table}
isEmpty: boolean; {is the pool empty (nothing in buckets)?}
case noStatics: boolean of {no statics/staticNum for this table?}
false: (staticNum: packed array[1..6] of char); {staticNum for this table}
true: ();
end;
var
noDeclarations: boolean; {have we declared anything at this level?}
table: symbolTablePtr; {current symbol table}
globalTable: symbolTablePtr; {global symbol table}
functionTable: symbolTablePtr; {table for top level of current function}
@ -102,6 +106,11 @@ procedure CheckStaticFunctions;
{ check for undefined functions }
procedure CheckUnused (tPtr: symbolTablePtr);
{ check for unused variables in symbol table }
function CompTypes (t1, t2: typePtr): boolean;
{ Determine if the two types are compatible }
@ -236,7 +245,8 @@ function Unqualify (tp: typePtr): typePtr;
function NewSymbol (name: stringPtr; itype: typePtr; class: tokenEnum;
space: spaceType; state: stateKind): identPtr;
space: spaceType; state: stateKind; isInline: boolean):
identPtr;
{ insert a new symbol in the symbol table }
{ }
@ -296,35 +306,28 @@ function StringType(prefix: charStrPrefixEnum): typePtr;
implementation
type
{From CGC.pas}
realrec = record {used to convert from real to in-SANE}
itsReal: extended;
inCOMP: packed array[1..8] of byte;
end;
var
staticNum: packed array[1..6] of char; {static variable number}
tablePool: symbolTablePtr; {pool of reusable empty symbol tables}
tablePoolSize: 0..maxint; {number of tables in pool}
tablePoolMaxSize: 0..maxint; {max number of tables in pool}
{- Imported from expression.pas --------------------------------}
{- Imported from CGC.pas ---------------------------------------}
procedure GenerateCode (tree: tokenPtr); extern;
procedure CnvSC (rec: realrec); extern;
{ generate code from a fully formed expression tree }
{ convert a real number to SANE comp format }
{ }
{ parameters: }
{ tree - top of the expression tree to generate code from }
{ }
{ variables: }
{ expressionType - result type of the expression }
function UsualUnaryConversions: baseTypeEnum; extern;
{ performs the usual unary conversions }
{ }
{ inputs: }
{ expressionType - type of the operand }
{ }
{ result: }
{ The base type of the operation to perform is returned. }
{ Any conversion code necessary has been generated. }
{ }
{ outputs: }
{ expressionType - set to result type }
{ rec - record containing the value to convert; also }
{ has space for the result }
{---------------------------------------------------------------}
@ -391,12 +394,26 @@ procedure Purge; extern;
{ write any constant bytes to the output buffer }
{- Imported from IIGS Memory Manager ---------------------------}
function MaxBlock: longint; tool ($02, $1C);
{---------------------------------------------------------------}
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 }
{---------------------------------------------------------------}
@ -416,26 +433,76 @@ for i := 0 to hashSize do begin
while sp <> nil do begin
if sp^.storage = private then
if sp^.itype^.kind = functionType then
if sp^.state <> defined then begin
numErrors := numErrors+1;
new(msg);
msg^ := concat('The static function ', sp^.name^,
' was not defined.');
writeln('*** ', msg^);
if terminalErrors then begin
if enterEditor then
ExitToEditor(msg, ord4(firstPtr)-ord4(bofPtr))
else
TermError(0);
if sp^.state <> defined then
if sp^.used then begin
numErrors := numErrors+1;
new(msg);
msg^ := concat('The static function ', sp^.name^,
' was used but never defined.');
writeln('*** ', msg^);
if terminalErrors then begin
if enterEditor then
ExitToEditor(msg, ord4(firstPtr)-ord4(bofPtr))
else
TermError(0);
end; {if}
liDCBGS.merrf := 16;
end; {if}
liDCBGS.merrf := 16;
end; {if}
sp := sp^.next;
end; {while}
end; {for}
end; {CheckStaticFunctions}
procedure CheckUnused {tPtr: symbolTablePtr};
{ check for unused variables in symbol table }
var
i: integer; {loop variable}
ip: identPtr; {current symbol}
nameStr: stringPtr;
begin {CheckUnused}
if not tPtr^.isEmpty or not tPtr^.noStatics then
for i := 0 to hashSize do begin {loop over all hash buckets}
if not tPtr^.isEmpty then begin
ip := tPtr^.buckets[i]; {trace through non-static symbols}
while ip <> nil do begin
if not ip^.used then
if ip^.itype <> nil then
if not (ip^.itype^.kind in [functionType,enumConst]) then
if ip^.storage in [stackFrame,private] then
if not (ip^.name^[1] in ['~','@']) then begin
new(nameStr);
nameStr^ := ip^.name^;
ErrorWithExtraString(185, nameStr);
end; {if}
ip := ip^.next;
end; {while}
end; {if}
if not tPtr^.noStatics then begin
ip := globalTable^.buckets[i]; {trace through static symbols}
while ip <> nil do begin
if not ip^.used then
if ip^.itype <> nil then
if not (ip^.itype^.kind in [functionType,enumConst]) then
if ip^.storage = private then
if copy(ip^.name^,1,staticNumLen) = tPtr^.staticNum then
if not (ip^.name^[staticNumLen+1] in ['~','@']) then
begin
new(nameStr);
nameStr^ :=
copy(ip^.name^, staticNumLen+1, maxint);
ErrorWithExtraString(185, nameStr);
end; {if}
ip := ip^.next;
end; {while}
end; {if}
end; {for}
end; {CheckUnused}
function CompTypes {t1, t2: typePtr): boolean};
{ Determine if the two types are compatible }
@ -445,8 +512,6 @@ label 1;
var
el1,el2: longint; {array sizes}
kind1,kind2: typeKind; {temp variables (for speed)}
p1, p2: parameterPtr; {for tracing parameter lists}
pt1,pt2: typePtr; {pointer types}
begin {CompTypes}
CompTypes := false; {assume the types are not compatible}
@ -664,6 +729,234 @@ procedure DoGlobals;
{ declare the ~globals and ~arrays segments }
procedure FreeTablePool;
{ free the symbol table pool }
var
tPtr: symbolTablePtr;
begin {FreeTablePool}
while tablePool <> nil do begin
tPtr := tablePool;
tablePool := tPtr^.next;
dispose(tPtr);
end;
end; {FreeTablePool}
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 }
@ -693,43 +986,13 @@ procedure DoGlobals;
currentSegment := ' '
else
currentSegment := '~ARRAYS ';
segmentKind := 0; {this segment is not dynamic!}
Gen2Name(dc_str, $4000, 1, @'~ARRAYS');
didOne := true;
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;
@ -791,17 +1054,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
@ -837,14 +1100,14 @@ begin {DoGlobals}
{if printSymbols then {debug}
{ PrintTable(globalTable); {debug}
{these segments are not dynamic!}
segmentKind := 0;
FreeTablePool; {dispose of unneeded symbol tables}
{declare the ~globals segment, which holds non-array data types}
if smallMemoryModel then
currentSegment := ' '
else
currentSegment := '~GLOBALS ';
segmentKind := 0; {this segment is not dynamic!}
Gen2Name(dc_str, $4000, 0, @'~GLOBALS');
GenGlobals;
Gen0(dc_enp);
@ -870,15 +1133,13 @@ function FindSymbol {var tk: tokenType; class: spaceType; oneLevel: boolean;
{ A pointer to the symbol table entry is returned. If }
{ there is no entry, nil is returned. }
label 1;
label 1,2;
var
doTagSpace: boolean; {do we still need to do the tags?}
hashDisp: longint; {disp into the hash table}
i: integer; {loop variable}
iHandle: ^identPtr; {pointer to start of hash bucket}
iPtr: identPtr; {pointer to the current symbol}
match: boolean; {for comparing substrings}
name: stringPtr; {name to search for}
np: stringPtr; {for searching for static variables}
sPtr: symbolTablePtr; {^ to current symbol table}
@ -888,23 +1149,16 @@ begin {FindSymbol}
staticAllowed := staticAllowed and (staticNum <> '~0000');
name := tk.name; {use a local variable}
hashDisp := Hash(name); {get the disp into the symbol table}
sPtr := table; {initialize the address of the sym. tbl}
FindSymbol := nil; {assume we won't find it}
np := nil; {no string buffer, yet}
{check for the variable}
2:
sPtr := table; {initialize the address of the sym. tbl}
while sPtr <> nil do begin
iHandle := pointer(hashDisp+ord4(sPtr));
if class = tagSpace then
iHandle := pointer(ord4(iHandle) + (hashSize+1)*4);
doTagSpace := class = allSpaces;
iPtr := iHandle^;
if iPtr = nil then
if doTagSpace then begin
iHandle := pointer(ord4(iHandle) + (hashSize+1)*4);
iPtr := iHandle^;
doTagSpace := false;
end; {if}
{scan the hash bucket for a global or auto variable}
while iPtr <> nil do begin
@ -916,16 +1170,10 @@ while sPtr <> nil do begin
goto 1;
end; {if}
iPtr := iPtr^.next;
if iPtr = nil then
if doTagSpace then begin
iHandle := pointer(ord4(iHandle) + (hashSize+1)*4);
iPtr := iHandle^;
doTagSpace := false;
end; {if}
end; {while}
{rescan for a static variable}
if staticAllowed then begin
if staticAllowed and not sPtr^.noStatics then begin
if np = nil then begin {form the static name}
if length(name^) < 251 then begin
new(np);
@ -964,6 +1212,13 @@ while sPtr <> nil do begin
sPtr := sPtr^.next;
end; {while}
{we only get here if a symbol was not found}
if class = allSpaces then begin
class := tagSpace;
goto 2;
end; {if}
FindSymbol := nil;
1:
if np <> nil then
dispose(np);
@ -1010,6 +1265,12 @@ if pp <> nil then begin {prototyped parameters}
size := long(sp^.itype^.size).lsw;
if (size = 1) and (sp^.itype^.kind = scalarType) then
size := 2;
if sp^.itype^.kind = scalarType then
if sp^.itype^.baseType in [cgReal,cgDouble,cgComp] then begin
{convert floating-point parameters to declared type}
Gen1t(pc_fix, pln, sp^.itype^.baseType);
size := cgExtendedSize;
end; {if}
Gen3(dc_prm, pln, size, sp^.pdisp);
end; {else}
sp^.pln := pln;
@ -1036,6 +1297,12 @@ else begin {K&R parameters}
size := long(sp^.itype^.size).lsw;
if (size = 1) and (sp^.itype^.kind = scalarType) then
size := 2;
if sp^.itype^.kind = scalarType then
if sp^.itype^.baseType in [cgReal,cgDouble,cgComp] then begin
{convert floating-point parameters to declared type}
Gen1t(pc_fix, pln, sp^.itype^.baseType);
size := cgExtendedSize;
end; {if}
Gen3(dc_prm, sp^.lln, size, sp^.pdisp);
end; {else}
if first then begin
@ -1276,7 +1543,8 @@ var
if ip = nil then ip := defaultStruct^.fieldList;
while ip <> nil do begin
GenSymbol(ip, none);
if ip^.name^[1] <> '~' then
GenSymbol(ip, none);
ip := ip^.next;
end; {while}
end; {ExpandStructType}
@ -1450,9 +1718,12 @@ var
begin {InitSymbol}
staticNum := '~0000'; {no functions processed}
table := nil; {initialize the global symbol table}
tablePool := nil; {table pool is initially empty}
tablePoolSize := 0;
tablePoolMaxSize := ord(MaxBlock div 150000); {limit size of pool based on RAM}
PushTable;
globalTable := table;
noDeclarations := false;
globalTable^.isEmpty := false; {global table is never treated as empty}
functionTable := nil;
{declare base types}
new(sCharPtr); {signed char}
@ -1981,7 +2252,8 @@ end; {Unqualify}
function NewSymbol {name: stringPtr; itype: typePtr; class: tokenEnum;
space: spaceType; state: stateKind): identPtr};
space: spaceType; state: stateKind; isInline: boolean):
identPtr};
{ insert a new symbol in the symbol table }
{ }
@ -1999,6 +2271,7 @@ var
cs: identPtr; {current symbol}
hashPtr: ^identPtr; {pointer to hash bucket in symbol table}
i: integer; {loop variable}
isFunction: boolean; {is this the symbol for a function?}
isGlobal: boolean; {are we using the global table?}
lUseGlobalPool: boolean; {use the global symbol pool?}
needSymbol: boolean; {do we need to declare it?}
@ -2006,105 +2279,164 @@ var
p: identPtr; {work pointer}
tk: tokenType; {fake token; for FindSymbol}
procedure AllocateStaticNum;
{ Allocate a staticNum value for the current table. }
var
done: boolean; {loop termination}
i: integer; {loop index}
begin {AllocateStaticNum}
i := 5; {increment the static var number}
repeat
staticNum[i] := succ(staticNum[i]);
done := staticNum[i] <> succ('9');
if not done then begin
staticNum[i] := '0';
i := i-1;
done := i = 1;
end; {if}
until done;
table^.staticNum := staticNum; {record the static symbol table number}
end; {AllocateStaticNum}
procedure UnInline;
{ Generate a non-inline definition for a function previously }
{ defined with an (apparent) inline definition. }
var
fName: stringPtr; {name of function}
i: integer; {loop variable}
begin {UnInline}
if cs^.iType^.isPascal then begin
fName := pointer(Malloc(length(name^)+1));
CopyString(pointer(fName), pointer(name));
for i := 1 to length(fName^) do
if fName^[i] in ['a'..'z'] then
fName^[i] := chr(ord(fName^[i]) & $5F);
end {if}
else
fName := name;
Gen2Name(dc_str, 0, 0, fName);
code^.s := m_jml;
code^.q := 0;
code^.r := ord(longabsolute);
new(code^.lab);
code^.lab^ := concat('~inline~',name^);
Gen0(pc_nat);
Gen0(dc_enp);
end; {UnInline}
begin {NewSymbol}
needSymbol := true; {assume we need a symbol}
cs := nil; {no current symbol found}
isGlobal := false; {set up defaults}
isFunction := false;
lUseGlobalPool := useGlobalPool;
tk.name := name;
tk.symbolPtr := nil;
if space <> fieldListSpace then begin {are we defining a function?}
if (itype <> nil) and (itype^.kind = functionType) then begin
isGlobal := true;
useGlobalPool := true;
isFunction := true;
if class in [autosy, ident] then
class := externsy;
if not lUseGlobalPool then begin
np := pointer(Malloc(length(name^)+1));
CopyString(pointer(np), pointer(name));
tk.name := np;
name := np;
end; {if}
cs := FindSymbol(tk, space, false, true);
if cs <> nil then begin
if cs^.state = defined then
if state = defined then
Error(42);
p := cs;
needSymbol := false;
if not itype^.prototyped then begin
itype^.prototyped := cs^.itype^.prototyped;
itype^.parameterList := cs^.itype^.parameterList;
end; {if}
end; {if}
class := externsy
else {If explicit storage class is given,}
isInline := false; {this is not an inline definition. }
end {if}
else if (itype <> nil) and (itype^.kind in [structType,unionType])
and (itype^.fieldList = nil) and doingParameters then begin
useGlobalPool := true;
end; {else if}
if noDeclarations then begin {if we need a symbol table, create it}
if not isGlobal then
noDeclarations := false;
end {if}
else begin {check for duplicates}
cs := FindSymbol(tk, space, true, false);
if cs <> nil then begin
if (not CompTypes(cs^.itype, itype))
or ((cs^.state = initialized) and (state = initialized))
or (globalTable <> table) then
if (not doingParameters) or (cs^.state <> declared) then
Error(42);
cs := FindSymbol(tk, space, true, true); {check for duplicates}
if cs <> nil then begin
if ((itype = nil)
or (cs^.itype = nil)
or (not CompTypes(cs^.itype, itype))
or ((cs^.state = initialized) and (state = initialized))
or ((class = typedefsy) <> (cs^.class = typedefsy))
or ((globalTable <> table)
and (not (class in [externsy,typedefsy])
or not (cs^.class in [externsy,typedefsy]))))
and ((not doingParameters) or (cs^.state <> declared))
then
Error(42)
else begin
itype := MakeCompositeType(cs^.itype, itype);
if class = externsy then
if cs^.class = staticsy then
class := staticsy;
if cs^.storage = external then
if isInline then
isInline := cs^.inlineDefinition
else if cs^.inlineDefinition then
if iType^.kind = functionType then
if cs^.state = defined then
if table = globalTable then
UnInline;
p := cs;
needSymbol := false;
end; {else}
end {if}
else if class = externsy then {check for outer decl of same object/fn}
if table <> globalTable then begin
cs := FindSymbol(tk, space, false, true);
if cs <> nil then
if cs^.name^[1] <> '~' then {exclude block-scope statics}
if cs^.storage in [global,external,private] then begin
if not CompTypes(cs^.itype, itype) then
Error(47);
itype := MakeCompositeType(cs^.itype, itype);
end; {if}
end; {if}
end; {else}
end; {if}
if class = staticsy then {statics go in the global symbol table}
if not isGLobal then
if globalTable <> table then begin
cs := FindSymbol(tk, space, true, true);
if cs <> nil then begin {check for duplicates}
if (not CompTypes(cs^.itype, itype))
or ((cs^.state = defined) and (state <> initialized))
or (cs^.state = initialized) then
Error(42);
p := cs;
needSymbol := false;
end; {if}
isGlobal := true; {note that we will use the global table}
useGlobalPool := true;
np := pointer(GMalloc(length(name^)+6));
np^[0] := chr(5+length(name^));
for i := 1 to 5 do
np^[i] := table^.staticNum[i];
for i := 1 to length(name^) do
np^[i+5] := name^[i];
name := np;
end; {if}
if needSymbol then begin
if class = staticsy then {statics go in the global symbol table}
if not isFunction then
if globalTable <> table then begin
isGlobal := true; {note that we will use the global table}
useGlobalPool := true;
if table^.noStatics then begin
table^.noStatics := false;
AllocateStaticNum;
end; {if}
np := pointer(GMalloc(length(name^)+6)); {form static name}
np^[0] := chr(5+length(name^));
for i := 1 to 5 do
np^[i] := table^.staticNum[i];
for i := 1 to length(name^) do
np^[i+5] := name^[i];
name := np;
end; {if}
p := pointer(Calloc(sizeof(identRecord))); {get space for the record}
{p^.iPtr := nil;} {no initializers, yet}
{p^.saved := 0;} {not saved}
p^.state := state; {set the state}
{p^.isForwardDeclared := false;} {assume no forward declarations are used}
p^.name := name; {record the name}
{p^.next := nil;}
{p^.used := false;} {unused for now}
if space <> fieldListSpace then {insert the symbol in the hash bucket}
begin
if itype = nil then
hashPtr := pointer(ord4(table)+Hash(name))
else if isGlobal then
hashPtr := pointer(ord4(globalTable)+Hash(name))
else
if (itype = nil) or not isGlobal then begin
hashPtr := pointer(ord4(table)+Hash(name));
table^.isEmpty := false;
end {if}
else
hashPtr := pointer(ord4(globalTable)+Hash(name));
if space = tagSpace then
hashPtr := pointer(ord4(hashPtr) + 4*(hashSize+1));
p^.next := hashPtr^;
hashPtr^ := p;
end {if}
else
p^.next := nil;
end; {if}
end; {if}
if class in [autosy,registersy] then {check and set the storage class}
if space = fieldListSpace then {check and set the storage class}
p^.storage := none
else if class in [autosy,registersy] then
begin
if doingFunction or doingParameters then begin
p^.storage := stackFrame;
@ -2123,8 +2455,10 @@ else if class = ident then begin
else
p^.storage := global;
end {else if}
else if class = externsy then
p^.storage := external
else if class = externsy then begin
p^.storage := external;
p^.inlineDefinition := isInline;
end {else if}
else if class = staticsy then
p^.storage := private
else
@ -2147,9 +2481,24 @@ begin {PopTable}
tPtr := table;
{if printSymbols then {debug}
{ PrintTable(tPtr); {debug}
if (lint & lintUnused) <> 0 then
CheckUnused(tPtr);
if tPtr^.next <> nil then begin
table := table^.next;
dispose(tPtr);
if not tPtr^.isEmpty then begin
dispose(tPtr);
if token.kind = ident then
if FindSymbol(token,variableSpace,false,false) <> nil then
if token.symbolPtr^.class = typedefsy then
token.kind := typedef;
end {if}
else if (tablePoolSize = tablePoolMaxSize) then
dispose(tPtr)
else begin
tPtr^.next := tablePool;
tablePool := tPtr;
tablePoolSize := tablePoolSize + 1;
end; {else}
end; {if}
end; {PopTable}
@ -2162,26 +2511,22 @@ procedure PushTable;
{ Create a new symbol table, pushing the old one }
var
done: boolean; {loop termination}
i: integer; {loop index}
tPtr: symbolTablePtr; {work pointer}
begin {PushTable}
i := 5; {increment the static var number}
repeat
staticNum[i] := succ(staticNum[i]);
done := staticNum[i] <> succ('9');
if not done then begin
staticNum[i] := '0';
i := i-1;
done := i = 1;
end; {if}
until done;
new(tPtr); {create a new symbol table}
ClearTable(tPtr^);
if tablePool <> nil then begin {use existing empty table if available}
tPtr := tablePool;
tablePool := tPtr^.next;
tablePoolSize := tablePoolSize - 1;
end {if}
else begin
new(tPtr); {...or create a new symbol table}
ClearTable(tPtr^);
tPtr^.isEmpty := true;
end; {else}
tPtr^.next := table;
table := tPtr;
tPtr^.staticNum := staticNum; {record the static symbol table number}
tPtr^.noStatics := true;
end; {PushTable}

163
Table.asm
View File

@ -19,7 +19,7 @@ charKinds start character set
enum (illegal,ch_special,ch_dash,ch_plus,ch_lt,ch_gt,ch_eq,ch_exc),0
enum (ch_and,ch_bar,ch_dot,ch_white,ch_eol,ch_eof,ch_char,ch_string)
enum (ch_asterisk,ch_slash,ch_percent,ch_carot,ch_pound,ch_colon)
enum (ch_backslash,letter,digit)
enum (ch_backslash,ch_other,letter,digit)
! STANDARD
dc i'ch_eof' nul
@ -57,8 +57,8 @@ charKinds start character set
dc i'ch_white' space
dc i'ch_exc' !
dc i'ch_string' "
dc i'illegal' #
dc i'illegal' $
dc i'ch_pound' #
dc i'ch_other' $
dc i'ch_percent' %
dc i'ch_and' &
dc i'ch_char' '
@ -86,7 +86,7 @@ charKinds start character set
dc i'ch_eq' =
dc i'ch_gt' >
dc i'ch_special' ?
dc i'illegal' @
dc i'ch_other' @
dc i'letter' A
dc i'letter' B
dc i'letter' C
@ -118,7 +118,7 @@ charKinds start character set
dc i'ch_special' ]
dc i'ch_carot' ^
dc i'letter' _
dc i'illegal' `
dc i'ch_other' `
dc i'letter' a
dc i'letter' b
dc i'letter' c
@ -183,24 +183,24 @@ charKinds start character set
dc i'letter' gs
dc i'letter' rs
dc i'letter' us
dc i'illegal' space
dc i'illegal' !
dc i'illegal' "
dc i'illegal' #
dc i'illegal' $
dc i'illegal' %
dc i'illegal' &
dc i'ch_other' space
dc i'ch_other' !
dc i'ch_other' "
dc i'ch_other' #
dc i'ch_other' $
dc i'ch_other' %
dc i'ch_other' &
dc i'letter' '
dc i'illegal' (
dc i'illegal' )
dc i'illegal' *
dc i'illegal' +
dc i'illegal' ,
dc i'ch_other' (
dc i'ch_other' )
dc i'ch_other' *
dc i'ch_other' +
dc i'ch_other' ,
dc i'ch_special' -
dc i'letter' .
dc i'letter' /
dc i'illegal' 0
dc i'illegal' 1
dc i'ch_other' 0
dc i'ch_other' 1
dc i'ch_special' 2
dc i'ch_special' 3
dc i'letter' 4
@ -209,76 +209,76 @@ charKinds start character set
dc i'letter' 7
dc i'letter' 8
dc i'letter' 9
dc i'illegal' :
dc i'ch_other' :
dc i'letter' ;
dc i'letter' <
dc i'letter' =
dc i'letter' >
dc i'letter' ?
dc i'illegal' @
dc i'illegal' A
dc i'illegal' B
dc i'illegal' C
dc i'ch_other' @
dc i'ch_other' A
dc i'ch_other' B
dc i'ch_other' C
dc i'letter' D
dc i'illegal' E
dc i'ch_other' E
dc i'letter' F
dc i'ch_special' G
dc i'ch_special' H
dc i'illegal' I
dc i'ch_other' I
dc i'ch_white' J
dc i'letter' K
dc i'letter' L
dc i'letter' M
dc i'letter' N
dc i'letter' O
dc i'illegal' P
dc i'illegal' Q
dc i'illegal' R
dc i'illegal' S
dc i'illegal' T
dc i'illegal' U
dc i'ch_other' P
dc i'ch_other' Q
dc i'ch_other' R
dc i'ch_other' S
dc i'ch_other' T
dc i'ch_other' U
dc i'ch_special' V
dc i'illegal' W
dc i'ch_other' W
dc i'letter' X
dc i'illegal' Y
dc i'illegal' Z
dc i'illegal' [
dc i'illegal' \
dc i'illegal' ]
dc i'letter' Y
dc i'ch_other' Z
dc i'ch_other' [
dc i'ch_other' \
dc i'ch_other' ]
dc i'letter' ^
dc i'letter' _
dc i'illegal' `
dc i'illegal' a
dc i'illegal' b
dc i'illegal' c
dc i'illegal' d
dc i'illegal' e
dc i'illegal' f
dc i'illegal' g
dc i'illegal' h
dc i'illegal' i
dc i'illegal' j
dc i'illegal' k
dc i'illegal' l
dc i'illegal' m
dc i'illegal' n
dc i'illegal' o
dc i'illegal' p
dc i'illegal' q
dc i'illegal' r
dc i'illegal' s
dc i'illegal' t
dc i'illegal' u
dc i'illegal' v
dc i'illegal' w
dc i'illegal' x
dc i'illegal' y
dc i'illegal' z
dc i'illegal' {
dc i'illegal' |
dc i'illegal' }
dc i'illegal' ~
dc i'illegal' rub
dc i'ch_other' `
dc i'ch_other' a
dc i'ch_other' b
dc i'ch_other' c
dc i'ch_other' d
dc i'letter' e
dc i'letter' f
dc i'letter' g
dc i'letter' h
dc i'letter' i
dc i'letter' j
dc i'letter' k
dc i'letter' l
dc i'letter' m
dc i'letter' n
dc i'letter' o
dc i'ch_other' p
dc i'letter' q
dc i'letter' r
dc i'letter' s
dc i'letter' t
dc i'letter' u
dc i'ch_other' v
dc i'ch_other' w
dc i'ch_other' x
dc i'ch_other' y
dc i'ch_other' z
dc i'ch_other' {
dc i'ch_other' |
dc i'ch_other' }
dc i'ch_other' ~
dc i'ch_other' rub
end
charSym start single character symbols
@ -308,10 +308,13 @@ charSym start single character symbols
enum (lteqop,gteqop,eqeqop,exceqop,andandop)
enum (barbarop,pluseqop,minuseqop,asteriskeqop,slasheqop)
enum (percenteqop,ltlteqop,gtgteqop,andeqop,caroteqop)
enum (bareqop,poundpoundop)
enum (bareqop,poundpoundop,dotdotdotsy)
enum (ppnumber) preprocessing number
enum (otherch) other non-whitespace char
enum (eolsy,eofsy) control characters
enum (typedef) user types
enum (uminus,uand,uasterisk) converted operations
! converted operations
enum (uminus,uplus,uand,uasterisk)
enum (parameteroper,castoper,opplusplus,opminusminus,compoundliteral)
enum (macroParm) macro language
@ -464,10 +467,14 @@ icp start in-coming priority for expression
dc i1'3' caroteqop
dc i1'3' bareqop
dc i1'200' poundpoundop
dc i1'200' dotdotdotsy
dc i1'200' ppnumber
dc i1'200' otherch
dc i1'200' eolsy
dc i1'200' eofsy
dc i1'200' typedef
dc i1'16' uminus
dc i1'16' uplus
dc i1'16' uand
dc i1'16' uasterisk
dc i1'200' parameteroper
@ -639,10 +646,14 @@ isp start in stack priority for expression
dc i1'2' caroteqop
dc i1'2' bareqop
dc i1'0' poundpoundop
dc i1'0' dotdotdotsy
dc i1'0' ppnumber
dc i1'0' otherch
dc i1'0' eolsy
dc i1'0' eofsy
dc i1'0' typedef
dc i1'16' uminus
dc i1'16' uplus
dc i1'16' uand
dc i1'16' uasterisk
dc i1'0' parameteroper
@ -936,6 +947,14 @@ wordHash start reserved word hash table
dc i'shortsy,typedefsy,unionsy,voidsy,whilesy,succwhilesy'
end
stdcVersion start __STDC_VERSION__ values
dc i4'199409' c95
dc i4'199901' c99
dc i4'201112' c11
dc i4'201710' c17
end
macRomanToUCS start
dc i2'$00C4, $00C5, $00C7, $00C9, $00D1, $00D6, $00DC, $00E1'
dc i2'$00E0, $00E2, $00E4, $00E3, $00E5, $00E7, $00E9, $00E8'

View File

@ -22,6 +22,7 @@ var
charSym: array[minChar..maxChar] of tokenEnum; {symbols for single char symbols}
reservedWords: array[_Alignassy..whilesy] of string[14]; {reserved word strings}
wordHash: array[0..25] of tokenEnum; {for hashing reserved words}
stdcVersion: array[c95..c17] of longint; {__STDC_VERSION__ values}
{from ASM.PAS}
{------------}

12
Tech.Support Normal file
View File

@ -0,0 +1,12 @@
As with all Byte Works programs, if you have questions or are
experiencing problems, we want to hear from you. You can contact us
through the channels below.
E-mail: support@byteworks.us
Web Site: https://www.byteworks.us
ORCA/C is now maintained on GitHub by community members. Bug reports
or support requests can be submitted on its issues page:
https://github.com/byteworksinc/ORCA-C/issues

View File

@ -6,18 +6,18 @@
struct foo {
int i;
const j;
volatile k;
int const j;
volatile int k;
} ;
main ()
int main (void)
{
int i,j;
j = 4;
i = (const) j;
i = (volatile) j;
i = (const int) j;
i = (int volatile) j;
printf ("Passed Conformance Test 11.4.2.1\n");
}

View File

@ -3,9 +3,11 @@
#include <stddef.h>
int printf(const char *, ...);
extended e1 [800];
main ()
int main (void)
{
int i [10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int *i1 = i;
@ -28,7 +30,7 @@ main ()
goto Fail;
printf ("Passed Conformance Test 13.1.0.1\n");
return;
return 0;
Fail:
printf ("Failed Conformance Test 13.1.0.1\n");

View File

@ -3,7 +3,9 @@
#include <ctype.h>
main ()
int printf(const char *, ...);
int main (void)
{
int i, j;
char ch;
@ -141,7 +143,7 @@ main ()
}
printf ("Passed Conformance Test 14.1.0.1\n");
return;
return 0;
Fail:
printf ("Failed Conformance Test 14.1.0.1\n");

View File

@ -2,7 +2,9 @@
#include <ctype.h>
main ()
int printf(const char *, ...);
int main (void)
{
int i, j;
char ch;
@ -54,7 +56,7 @@ main ()
goto Fail;
printf ("Passed Conformance Test 14.2.0.1\n");
return;
return 0;
Fail:
printf ("Failed Conformance Test 14.2.0.1\n");

View File

@ -2,7 +2,9 @@
#include <ctype.h>
main ()
int printf(const char *, ...);
int main (void)
{
int i, j;
char ch;
@ -80,7 +82,7 @@ main ()
printf ("Passed Conformance Test 14.3.0.1\n");
return;
return 0;
Fail:
printf ("Failed Conformance Test 14.3.0.1\n");

View File

@ -2,7 +2,9 @@
#include <ctype.h>
main ()
int printf(const char *, ...);
int main (void)
{
int i, j;
char ch;
@ -71,7 +73,7 @@ main ()
goto Fail;
printf ("Passed Conformance Test 14.4.0.1\n");
return;
return 0;
Fail:
printf ("Failed Conformance Test 14.4.0.1\n");

View File

@ -2,7 +2,9 @@
#include <ctype.h>
main ()
int printf(const char *, ...);
int main (void)
{
int i, j;
char ch;
@ -33,7 +35,7 @@ main ()
}
printf ("Passed Conformance Test 14.5.0.1\n");
return;
return 0;
Fail:
printf ("Failed Conformance Test 14.5.0.1\n");

View File

@ -2,7 +2,9 @@
#include <ctype.h>
main ()
int printf(const char *, ...);
int main (void)
{
int i, j;
char ch;
@ -30,7 +32,7 @@ main ()
}
printf ("Passed Conformance Test 14.6.0.1\n");
return;
return 0;
Fail:
printf ("Failed Conformance Test 14.6.0.1\n");

View File

@ -2,7 +2,9 @@
#include <ctype.h>
main ()
int printf(const char *, ...);
int main (void)
{
int i, j;
char ch;
@ -67,7 +69,7 @@ main ()
printf ("Passed Conformance Test 14.7.0.1\n");
return;
return 0;
Fail:
printf ("Failed Conformance Test 14.7.0.1\n");

View File

@ -3,7 +3,7 @@
#include <ctype.h>
#include <stdio.h>
main ()
int main (void)
{
int i, j;
char ch;
@ -42,7 +42,7 @@ main ()
}
printf ("Passed Conformance Test 14.8.0.1\n");
return;
return 0;
Fail:
printf ("Failed Conformance Test 14.8.0.1\n");

Some files were not shown because too many files have changed in this diff Show More