Compare commits

...

64 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
82 changed files with 6219 additions and 472 deletions

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 B7! This is an update release containing
patches from community members (Stephen Heumann and Kelvin Sherlock),
which add new features and fix bugs. 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)

8
CC.rez
View File

@ -4,12 +4,12 @@ resource rVersion(1) {
{
2, /* Major revision */
2, /* Minor revision */
0, /* Bug version */
beta, /* Release stage */
7, /* 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 2023"
"Updated 2024"
};

View File

@ -112,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 B7'; {compiler version}
versionStr = '2.2.1 dev'; {compiler version}
type
{Misc.}
@ -202,6 +202,7 @@ type
barbarop,pluseqop,minuseqop,asteriskeqop,slasheqop,
percenteqop,ltlteqop,gtgteqop,andeqop,caroteqop,
bareqop,poundpoundop,dotdotdotsy,
ppnumber, {preprocessing number (pp-token)}
otherch, {other non-whitespace char (pp-token)}
eolsy,eofsy, {control characters}
typedef, {user types}
@ -225,7 +226,7 @@ type
tokenSet = set of tokenEnum;
tokenClass = (reservedWord,reservedSymbol,identifier,intConstant,longConstant,
longlongConstant,realConstant,stringConstant,otherCharacter,
macroParameter);
preprocessingNumber,macroParameter);
identPtr = ^identRecord; {^ to a symbol table entry}
tokenType = record {a token}
kind: tokenEnum; {kind of token}
@ -243,6 +244,7 @@ type
ispstring: boolean;
prefix: charStrPrefixEnum);
otherCharacter: (ch: char); {used for preprocessing tokens only}
preprocessingNumber: (errCode: integer); {used for pp tokens only}
macroParameter: (pnum: integer);
end;

View File

@ -139,7 +139,7 @@ opt[pc_ckn] := 'ckn';
end; {InitWriteCode}
procedure PrintDAG (tag: stringPtr; code: icptr);
procedure PrintDAG {tag: stringPtr; code: icptr};
{ print a DAG }
{ }

108
CGI.pas
View File

@ -48,6 +48,7 @@ const
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;
@ -292,6 +293,8 @@ type
ccPointer : (pval: longint; pstr: longStringPtr);
end;
codeRef = icptr; {reference to a code location}
{basic blocks}
{------------}
iclist = ^iclistRecord; {used to form lists of records}
@ -657,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 }
@ -666,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 }
@ -1430,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 }

19
DAG.pas
View File

@ -565,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
@ -631,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}

View File

@ -1414,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
@ -1424,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
@ -1570,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
@ -1580,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
@ -1712,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
@ -3294,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}
@ -3306,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);
@ -3429,11 +3453,17 @@ var
while tp <> nil do begin
if tp^.middle <> nil then begin
GenerateCode(tp^.middle);
if expressionType^.kind in [structType,unionType] then begin
if expressionType^.size & $FFFF8000 <> 0 then
Error(61);
Gen1t(pc_ldc, long(expressionType^.size).lsw, cgWord);
Gen0(pc_psh);
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(tType^.size).lsw, cgWord);
Gen0(pc_psh);
end; {if}
end; {if}
if fmt <> fmt_none then begin
new(tfp);
@ -4690,6 +4720,7 @@ case tree^.token.kind of
dotch: begin {.}
LoadAddress(tree^.left, checkNullPointers);
isBitfield := false;
lType := expressionType;
if lType^.kind in [arrayType,pointerType,structType,unionType] then begin
if lType^.kind = arrayType then

525
Gen.pas
View File

@ -321,6 +321,7 @@ case op^.opcode of
loc := LabelToDisp(op^.left^.r) + op^.left^.q;
if (op^.left^.opcode <> pc_lod) or (loc > 255) then
Error(cge1);
offset := offset + op^.q;
if offset = 0 then
GenNative(mop, direct, loc, nil, 0)
else begin
@ -618,7 +619,7 @@ function NeedsCondition (opcode: pcodes): boolean;
begin {NeedsCondition}
NeedsCondition := opcode in
[pc_and,pc_ior,pc_cui,pc_cup,pc_lor,pc_lnd,pc_ldl,pc_lil,pc_lld,
[pc_and,pc_ior,pc_cui,pc_cup,pc_ldl,pc_lil,pc_lld,
pc_lli,pc_gil,pc_gli,pc_gdl,pc_gld,pc_iil,pc_ili,pc_idl,pc_ild,
pc_cop,pc_cpo,pc_cpi,pc_dvi,pc_mpi,pc_adi,pc_sbi,pc_mod,pc_bno,
pc_udi,pc_uim,pc_umi,pc_cnv,pc_rbo,pc_shl,pc_shr,pc_usr,pc_lbf,
@ -1068,8 +1069,22 @@ var
end; {ReverseConditional}
function SimpleLongOp(op: icptr): boolean;
{ Is op an operation on cg(U)Long that can be done using the }
{ addressing modes of CPX? }
begin {SimpleLongOp}
SimpleLongOp :=
(op^.opcode = pc_ldc)
or (op^.opcode = pc_lao)
or ((op^.opcode = pc_lod) and (LabelToDisp(op^.r) + op^.q <= 253))
or ((op^.opcode = pc_ldo) and smallMemoryModel);
end; {SimpleLongOp}
begin {GenCmp}
{To reduct the number of possibilities that must be handled, pc_les }
{To reduce the number of possibilities that must be handled, pc_les }
{and pc_leq compares are reduced to their equivalent pc_grt and }
{pc_geq instructions. }
if op^.opcode = pc_les then begin
@ -1113,15 +1128,16 @@ if (op^.optype in [cgByte,cgUByte,cgWord,cgUWord]) and
if NeedsCondition(op^.left^.opcode) then
GenImpliedForFlags(m_tax);
if (num >= 0) and (num < 3) then begin
if num <> 0 then begin
if num = 0 then
GenNative(m_bpl, relative, lab1, nil, 0)
else begin
lab2 := GenLabel;
GenNative(m_bmi, relative, lab2, nil, 0);
for i := 1 to num do
GenImplied(m_dea);
end; {if}
GenNative(m_bpl, relative, lab1, nil, 0);
if num <> 0 then
GenLab(lab2);
if num = 2 then
GenImplied(m_lsr_a);
GenNative(m_bne, relative, lab1, nil, 0);
GenLabUsedOnce(lab2);
end; {else}
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab1);
end {if (num >= 0) and (num < 3)}
@ -1134,7 +1150,7 @@ if (op^.optype in [cgByte,cgUByte,cgWord,cgUWord]) and
GenNative(m_cmp_imm, immediate, num, nil, 0);
GenNative(m_bcs, relative, lab2, nil, 0);
if num > 0 then begin
GenLab(lab1);
GenLabUsedOnce(lab1);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab2);
end {if}
@ -1147,8 +1163,17 @@ if (op^.optype in [cgByte,cgUByte,cgWord,cgUWord]) and
end {if}
else {if optype in [cgUByte,cgUWord] then} begin
if num <> 0 then begin
GenNative(m_cmp_imm, immediate, num, nil, 0);
GenNative(m_bcs, relative, lab1, nil, 0);
if num in [1,2] then begin
if num = 1 then
GenImpliedForFlags(m_tax)
else
GenImplied(m_lsr_a);
GenNative(m_bne, relative, lab1, nil, 0);
end {if}
else begin
GenNative(m_cmp_imm, immediate, num, nil, 0);
GenNative(m_bcs, relative, lab1, nil, 0);
end; {else}
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab1);
end; {if}
@ -1163,9 +1188,9 @@ if (op^.optype in [cgByte,cgUByte,cgWord,cgUWord]) and
if (num >= 0) and (num < 3) then begin
GenNative(m_bmi, relative, lab1, nil, 0);
if num > 0 then begin
for i := 1 to num do
GenImplied(m_dea);
GenNative(m_bmi, relative, lab1, nil, 0);
if num = 2 then
GenImplied(m_lsr_a);
GenNative(m_beq, relative, lab1, nil, 0);
end; {if}
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab1);
@ -1184,7 +1209,7 @@ if (op^.optype in [cgByte,cgUByte,cgWord,cgUWord]) and
GenLab(lab1);
end {if}
else begin
GenLab(lab1);
GenLabUsedOnce(lab1);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab2);
end; {else}
@ -1192,8 +1217,17 @@ if (op^.optype in [cgByte,cgUByte,cgWord,cgUWord]) and
end {if}
else {if optype in [cgUByte,cgUWord] then} begin
if num <> 0 then begin
GenNative(m_cmp_imm, immediate, num, nil, 0);
GenNative(m_bcc, relative, lab1, nil, 0);
if num in [1,2] then begin
if num = 1 then
GenImpliedForFlags(m_tax)
else
GenImplied(m_lsr_a);
GenNative(m_beq, relative, lab1, nil, 0);
end {if}
else begin
GenNative(m_cmp_imm, immediate, num, nil, 0);
GenNative(m_bcc, relative, lab1, nil, 0);
end; {else}
end; {if}
GenNative(m_brl, longrelative, lb, nil, 0);
if num <> 0 then
@ -1282,7 +1316,7 @@ else
else
GenNative(m_bcs, relative, lab2, nil, 0);
if op^.opcode = pc_grt then
GenLab(lab3);
GenLabUsedOnce(lab3);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab2);
end {if}
@ -1330,50 +1364,134 @@ else
end; {case optype of cgByte,cgUByte,cgWord,cgUWord}
cgULong: begin
gLong.preference := onStack;
GenTree(op^.right);
gLong.preference := A_X;
GenTree(op^.left);
if gLong.where = onStack then begin
GenImplied(m_ply);
GenImplied(m_pla);
lab1 := GenLabel;
lab2 := GenLabel;
simple := false;
if SimpleLongOp(op^.right) then
simple := true
else if rOpcode in [pc_fjp,pc_tjp] then
if SimpleLongOp(op^.left) then begin
ReverseConditional;
simple := true;
end; {if}
if simple then begin
if op^.opcode = pc_grt then begin
if SimpleLongOp(op^.left) then
ReverseConditional;
if op^.opcode = pc_grt then
if op^.right^.opcode = pc_ldc then
if op^.right^.lval <> $ffffffff then begin
op^.right^.lval := op^.right^.lval + 1;
op^.opcode := pc_geq;
end; {if}
end; {if}
gLong.preference := A_X;
GenTree(op^.left);
if gLong.where = onStack then begin
GenImplied(m_pla);
GenImplied(m_plx);
end; {if}
if op^.opcode = pc_grt then
if not (rOpcode in [pc_fjp,pc_tjp]) then
GenNative(m_ldy_imm, immediate, 0, nil, 0);
with op^.right^ do
case opcode of
pc_ldc:
GenNative(m_cpx_imm, immediate, long(lval).msw, nil, 0);
pc_lao:
GenNative(m_cpx_imm, immediate, q, lab, shift16);
pc_lod:
GenNative(m_cpx_dir, direct, LabelToDisp(r)+q+2, nil, 0);
pc_ldo:
GenNative(m_cpx_abs, absolute, q+2, lab, 0);
end; {case}
GenNative(m_bne, relative, lab1, nil, 0);
with op^.right^ do
case opcode of
pc_ldc:
GenNative(m_cmp_imm, immediate, long(lval).lsw, nil, 0);
pc_lao:
GenNative(m_cmp_imm, immediate, q, lab, 0);
pc_lod:
GenNative(m_cmp_dir, direct, LabelToDisp(r)+q, nil, 0);
pc_ldo:
GenNative(m_cmp_abs, absolute, q, lab, 0);
end; {case}
GenLab(lab1);
if rOpcode = pc_fjp then begin
if op^.opcode = pc_grt then begin
lab3 := GenLabel;
GenNative(m_beq, relative, lab3, nil, 0);
end; {if}
GenNative(m_bcs, relative, lab2, nil, 0);
if op^.opcode = pc_grt then
GenLabUsedOnce(lab3);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab2);
end {if}
else if rOpcode = pc_tjp then begin
if op^.opcode = pc_grt then
GenNative(m_beq, relative, lab2, nil, 0);
GenNative(m_bcc, relative, lab2, nil, 0);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab2);
end {else if}
else if op^.opcode = pc_geq then begin
GenNative(m_lda_imm, immediate, 0, nil, 0);
GenImplied(m_rol_a);
end {else if}
else {if op^.opcode = pc_grt then} begin
GenNative(m_beq, relative, lab2, nil, 0);
GenNative(m_bcc, relative, lab2, nil, 0);
GenImplied(m_iny);
GenLab(lab2);
GenImplied(m_tya);
end; {else}
end {if}
else begin
GenImplied(m_tay);
gLong.preference := onStack;
GenTree(op^.right);
gLong.preference := A_X;
GenTree(op^.left);
if gLong.where = onStack then begin
GenImplied(m_ply);
GenImplied(m_pla);
end {if}
else begin
GenImplied(m_tay);
GenImplied(m_txa);
end; {else}
GenNative(m_ldx_imm, immediate, 1, nil, 0);
GenNative(m_cmp_s, direct, 3, nil, 0);
GenNative(m_bne, relative, lab1, nil, 0);
GenImplied(m_tya);
GenNative(m_cmp_s, direct, 1, nil, 0);
GenLab(lab1);
if op^.opcode = pc_grt then begin
lab3 := GenLabel;
GenNative(m_beq, relative, lab3, nil, 0);
end; {if}
GenNative(m_bcs, relative, lab2, nil, 0);
if op^.opcode = pc_grt then
GenLab(lab3);
GenImplied(m_dex);
GenLab(lab2);
GenImplied(m_pla);
GenImplied(m_pla);
GenImplied(m_txa);
if rOpcode = pc_fjp then begin
lab4 := GenLabel;
GenNative(m_bne, relative, lab4, nil, 0);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab4);
end {if}
else if rOpcode = pc_tjp then begin
lab4 := GenLabel;
GenNative(m_beq, relative, lab4, nil, 0);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab4);
end; {else if}
end; {else}
lab1 := GenLabel;
GenNative(m_ldx_imm, immediate, 1, nil, 0);
GenNative(m_cmp_s, direct, 3, nil, 0);
GenNative(m_bne, relative, lab1, nil, 0);
GenImplied(m_tya);
GenNative(m_cmp_s, direct, 1, nil, 0);
GenLab(lab1);
lab2 := GenLabel;
if op^.opcode = pc_grt then begin
lab3 := GenLabel;
GenNative(m_beq, relative, lab3, nil, 0);
end; {if}
GenNative(m_bcs, relative, lab2, nil, 0);
if op^.opcode = pc_grt then
GenLab(lab3);
GenImplied(m_dex);
GenLab(lab2);
GenImplied(m_pla);
GenImplied(m_pla);
GenImplied(m_txa);
if rOpcode = pc_fjp then begin
lab4 := GenLabel;
GenNative(m_bne, relative, lab4, nil, 0);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab4);
end {if}
else if rOpcode = pc_tjp then begin
lab4 := GenLabel;
GenNative(m_beq, relative, lab4, nil, 0);
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab4);
end; {else if}
end;
cgReal,cgDouble,cgComp,cgExtended: begin
@ -2135,10 +2253,14 @@ if (op^.optype in [cgByte,cgUByte,cgWord,cgUWord]) and
num := op^.right^.q;
lab1 := GenLabel;
if opcode in [pc_fjp,pc_tjp] then begin
if num <> 0 then
GenNative(m_cmp_imm, immediate, num, nil, 0)
else if NeedsCondition(leftOp) then
GenImpliedForFlags(m_tay);
if num = 0 then begin
if NeedsCondition(leftOp) then
GenImpliedForFlags(m_tay);
end {if}
else if num = 1 then
GenImplied(m_dea)
else
GenNative(m_cmp_imm, immediate, num, nil, 0);
if opcode = pc_fjp then
GenNative(beq, relative, lab1, nil, 0)
else
@ -2147,12 +2269,20 @@ if (op^.optype in [cgByte,cgUByte,cgWord,cgUWord]) and
GenLab(lab1);
end {if}
else begin
GenNative(m_ldx_imm, immediate, 0, nil, 0);
GenNative(m_cmp_imm, immediate, num, nil, 0);
GenNative(bne, relative, lab1, nil, 0);
GenImplied(m_inx);
GenLab(lab1);
GenImplied(m_txa);
if num <> 0 then
GenNative(m_eor_imm, immediate, num, nil, 0)
else if NeedsCondition(leftOp) then
GenImpliedForFlags(m_tax);
GenNative(m_beq, relative, lab1, nil, 0);
if op^.opcode = pc_equ then begin
GenNative(m_lda_imm, immediate, $ffff, nil, 0);
GenLab(lab1);
GenImplied(m_ina);
end {if}
else begin
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenLab(lab1);
end; {else}
end; {else}
end {if}
else if (op^.optype in [cgLong,cgULong]) and (leftOp in [pc_ldo,pc_lod])
@ -2167,24 +2297,20 @@ else if (op^.optype in [cgLong,cgULong]) and (leftOp in [pc_ldo,pc_lod])
GenNative(m_brl, longrelative, lb, nil, 0);
GenLab(lab1);
end {if}
else if op^.opcode = pc_equ then begin
lab1 := GenLabel;
lab2 := GenLabel;
DoOr(op^.left);
GenNative(bne, relative, lab1, nil, 0);
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenNative(m_bra, relative, lab2, nil, 0);
GenLab(lab1);
GenNative(m_lda_imm, immediate, 0, nil, 0);
GenLab(lab2);
end {else if}
else {if op^.opcode = pc_neq then} begin
else begin
lab1 := GenLabel;
DoOr(op^.left);
GenNative(m_beq, relative, lab1, nil, 0);
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenLab(lab1);
end; {else if}
if op^.opcode = pc_equ then begin
GenNative(m_lda_imm, immediate, $ffff, nil, 0);
GenLab(lab1);
GenImplied(m_ina);
end {if}
else begin
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenLab(lab1);
end; {else}
end; {else}
end {else if}
else if (op^.optype in [cgLong,cgULong]) and (rightOp in [pc_ldo,pc_lod]) then begin
gLong.preference := A_X;
@ -2229,8 +2355,7 @@ else
if Complex(op^.right) or (not (opcode in [pc_fjp,pc_tjp])) then begin
GenImplied(m_pha);
GenTree(op^.right);
GenImplied(m_sec);
GenNative(m_sbc_s, direct, 1, nil, 0);
GenNative(m_eor_s, direct, 1, nil, 0);
GenImplied(m_plx);
GenImplied(m_tax);
if opcode in [pc_fjp,pc_tjp] then begin
@ -2245,10 +2370,15 @@ else
else begin
lab1 := GenLabel;
GenNative(m_beq, relative, lab1, nil, 0);
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenLab(lab1);
if op^.opcode = pc_equ then
GenNative(m_eor_imm, immediate, 1, nil, 0);
if op^.opcode = pc_equ then begin
GenNative(m_lda_imm, immediate, $ffff, nil, 0);
GenLab(lab1);
GenImplied(m_ina);
end {if}
else begin
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenLab(lab1);
end; {else}
end; {else}
end {if}
else begin
@ -2392,10 +2522,15 @@ else
else begin
lab3 := GenLabel;
GenNative(m_beq, relative, lab3, nil, 0);
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenLab(lab3);
if op^.opcode = pc_equ then
GenNative(m_eor_imm, immediate, 1, nil, 0);
if op^.opcode = pc_equ then begin
GenNative(m_lda_imm, immediate, $ffff, nil, 0);
GenLab(lab3);
GenImplied(m_ina);
end {if}
else begin
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenLab(lab3);
end; {else}
end; {else}
end; {case optype of cgQuad,cgUQuad}
@ -3148,81 +3283,44 @@ case optype of
gQuad := lQuad;
gQuad.where := gQuad.preference; {unless overridden later}
if gLong.where = inPointer then begin
if q = 0 then begin
if gLong.fixedDisp then begin
GenNative(m_ldy_imm, immediate, 6, nil, 0);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
StoreWordOfQuad(6);
GenImplied(m_dey);
GenImplied(m_dey);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
StoreWordOfQuad(4);
GenImplied(m_dey);
GenImplied(m_dey);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
StoreWordOfQuad(2);
GenNative(m_lda_indl, direct, gLong.disp, nil, 0);
StoreWordOfQuad(0);
end {if}
if gLong.fixedDisp then begin
GenNative(m_ldy_imm, immediate, q+6, nil, 0);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
StoreWordOfQuad(6);
GenNative(m_ldy_imm, immediate, q+4, nil, 0);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
StoreWordOfQuad(4);
GenNative(m_ldy_imm, immediate, q+2, nil, 0);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
StoreWordOfQuad(2);
if q = 0 then
GenNative(m_lda_indl, direct, gLong.disp, nil, 0)
else begin
GenImplied(m_tya);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, 6, nil, 0);
GenImplied(m_tay);
GenNative(m_ldy_imm, immediate, q, nil, 0);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
StoreWordOfQuad(6);
GenImplied(m_dey);
GenImplied(m_dey);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
StoreWordOfQuad(4);
GenImplied(m_dey);
GenImplied(m_dey);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
StoreWordOfQuad(2);
GenImplied(m_dey);
GenImplied(m_dey);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
StoreWordOfQuad(0);
end; {else}
end {if q = 0}
StoreWordOfQuad(0);
end {if}
else begin
if gLong.fixedDisp then begin
GenNative(m_ldy_imm, immediate, q+6, nil, 0);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
StoreWordOfQuad(6);
GenImplied(m_dey);
GenImplied(m_dey);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
StoreWordOfQuad(4);
GenImplied(m_dey);
GenImplied(m_dey);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
StoreWordOfQuad(2);
GenImplied(m_dey);
GenImplied(m_dey);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
StoreWordOfQuad(0);
end {if}
else begin
GenImplied(m_tya);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, q+6, nil, 0);
GenImplied(m_tay);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
StoreWordOfQuad(6);
GenImplied(m_dey);
GenImplied(m_dey);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
StoreWordOfQuad(4);
GenImplied(m_dey);
GenImplied(m_dey);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
StoreWordOfQuad(2);
GenImplied(m_dey);
GenImplied(m_dey);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
StoreWordOfQuad(0);
end; {else}
gQuad.where := onStack;
GenImplied(m_tya);
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, q+6, nil, 0);
GenImplied(m_tay);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
GenImplied(m_pha);
GenImplied(m_dey);
GenImplied(m_dey);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
GenImplied(m_pha);
GenImplied(m_dey);
GenImplied(m_dey);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
GenImplied(m_pha);
GenImplied(m_dey);
GenImplied(m_dey);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
GenImplied(m_pha);
end; {else}
end {if glong.where = inPointer}
else if gLong.where = localAddress then begin
@ -3617,11 +3715,17 @@ else begin
else begin
if op^.left^.opcode = pc_lao then begin
GenTree(op^.right);
if signed then
GenImplied(m_tay);
GenNative(m_ldx_imm, immediate, op^.left^.q, op^.left^.lab, shift16);
if signed then begin
GenImpliedForFlags(m_tay);
lab2 := GenLabel;
GenNative(m_bpl, relative, lab2, nil, 0);
GenImplied(m_dex);
GenLab(lab2);
signed := false;
end; {if}
GenImplied(m_clc);
GenNative(m_adc_imm, immediate, op^.left^.q, op^.left^.lab, 0);
GenNative(m_ldx_imm, immediate, op^.left^.q, op^.left^.lab, shift16);
end {if}
else begin
gLong.preference := onStack;
@ -3696,7 +3800,7 @@ var
GenNative(m_inc_dirx, direct, 2, nil, 0);
GenLab(lab1);
end {if}
else {if op in [pc_gdl,pc_gld] then} begin
else {if op in [pc_ldl,pc_lld] then} begin
lab1 := GenLabel;
if p = 1 then begin
GenNative(m_lda_dirx, direct, 0, nil, 0);
@ -5493,10 +5597,11 @@ procedure GenTree {op: icptr};
lab1: integer;
operandIsBoolean: boolean;
begin {GenntNgiNot}
begin {GenBntNgiNot}
if op^.opcode = pc_not then
operandIsBoolean := op^.left^.opcode in
[pc_and,pc_ior,pc_neq,pc_equ,pc_geq,pc_leq,pc_les,pc_grt,pc_not];
[pc_and,pc_ior,pc_lnd,pc_lor,pc_not,pc_neq,pc_equ,pc_geq,pc_leq,
pc_les,pc_grt];
GenTree(op^.left);
case op^.opcode of
pc_bnt:
@ -5507,16 +5612,17 @@ procedure GenTree {op: icptr};
GenImplied(m_ina);
end; {case pc_ngi}
pc_not: begin
pc_not:
if not operandIsBoolean then begin
lab1 := GenLabel;
GenImpliedForFlags(m_tax);
GenNative(m_beq, relative, lab1, nil, 0);
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenNative(m_lda_imm, immediate, $ffff, nil, 0);
GenLab(lab1);
end; {if}
GenNative(m_eor_imm, immediate, 1, nil, 0);
end; {if}
GenImplied(m_ina);
end {if}
else
GenNative(m_eor_imm, immediate, 1, nil, 0);
end; {case}
end; {GenBntNgiNot}
@ -6504,49 +6610,50 @@ procedure GenTree {op: icptr};
{ Generate code for a pc_lor or pc_lnd }
var
lab1,lab2: integer; {label}
opc: pcodes; {operation code}
procedure DoOra;
{ do some common oring operations to reduce space }
begin {DoOra}
if gLong.where = onStack then begin
GenImplied(m_pla);
GenNative(m_sta_dir, direct, dworkLoc, nil, 0);
GenImplied(m_pla);
end {if}
else
GenNative(m_stx_dir, direct, dworkLoc, nil, 0);
GenNative(m_ora_dir, direct, dworkLoc, nil, 0);
end; {DoOra}
lab1,lab2,lab3,lab4: integer; {labels}
begin {GenLorLnd}
opc := op^.opcode;
lab1 := GenLabel;
lab3 := GenLabel;
lab4 := GenLabel;
gLong.preference := A_X;
GenTree(op^.left);
DoOra;
lab2 := GenLabel;
if opc = pc_lnd then
GenNative(m_bne, relative, lab2, nil, 0)
if glong.where = A_X then
GenImpliedForFlags(m_tay)
else begin
GenNative(m_beq, relative, lab2, nil, 0);
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenImplied(m_plx);
GenImplied(m_pla);
end; {else}
GenNative(m_brl, longrelative, lab1, nil, 0);
GenLab(lab2);
GenNative(m_bne, relative, lab1, nil, 0);
GenImplied(m_txa);
if op^.opcode = pc_lor then begin
lab2 := GenLabel;
GenNative(m_beq, relative, lab2, nil, 0);
GenLabUsedOnce(lab1);
GenNative(m_brl, longrelative, lab3, nil, 0);
GenLab(lab2);
end {if}
else begin
GenNative(m_bne, relative, lab1, nil, 0);
GenNative(m_brl, longrelative, lab4, nil, 0);
GenLab(lab1);
end; {if}
gLong.preference := A_X;
GenTree(op^.right);
DoOra;
GenNative(m_beq, relative, lab1, nil, 0);
if glong.where = A_X then
GenImpliedForFlags(m_tay)
else begin
GenImplied(m_plx);
GenImplied(m_pla);
end; {else}
GenNative(m_bne, relative, lab3, nil, 0);
GenImplied(m_txa);
GenNative(m_beq, relative, lab4, nil, 0);
GenLab(lab3);
GenNative(m_lda_imm, immediate, 1, nil, 0);
GenLab(lab1);
GenLab(lab4);
end; {GenLorLnd}
@ -7723,7 +7830,7 @@ var
localSize := localSize + size;
end {else if}
else if opcode in
[pc_les,pc_leq,pc_grt,pc_geq,pc_sto,pc_cpi,pc_ind,pc_lor,pc_lnd,
[pc_les,pc_leq,pc_grt,pc_geq,pc_sto,pc_cpi,pc_ind,
pc_ili,pc_iil,pc_idl,pc_ild,pc_ixa]
then begin
if dworkLoc = 0 then begin

View File

@ -18,7 +18,7 @@ uses CCommon, MM, Scanner, Symbol, CGI;
{$segment 'HEADER'}
const
symFileVersion = 40; {version number of .sym file format}
symFileVersion = 44; {version number of .sym file format}
var
inhibitHeader: boolean; {should .sym includes be blocked?}
@ -722,6 +722,7 @@ procedure EndInclude {chPtr: ptr};
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
@ -1392,6 +1393,7 @@ var
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

BIN
Manual.docx Normal file

Binary file not shown.

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 }
@ -1637,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
@ -1674,8 +1682,20 @@ var
opcode := m_bmi;
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
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
@ -1700,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
@ -2301,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 }
@ -2546,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
@ -2614,7 +2658,7 @@ yRegister.condition := regUnknown;
lastRegOpcode := 0; {BRK}
nnextspot := 1;
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_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];

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

@ -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

@ -150,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);

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

@ -73,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))

View File

@ -122,13 +122,6 @@ type
val: longlong; {switch value}
end;
{token stack}
{-----------}
tokenStackPtr = ^tokenStackRecord;
tokenStackRecord = record
next: tokenStackPtr;
token: tokenType;
end;
{statement stack}
{---------------}
statementPtr = ^statementRecord;
@ -157,7 +150,7 @@ type
);
forSt: (
forLoop: integer; {branch here to loop}
e3List: tokenStackPtr; {tokens for last expression}
e3Code: codeRef; {code for last expression}
);
switchSt: (
maxVal: longint; {max switch value}
@ -690,11 +683,9 @@ var
{ handle a for statement }
var
errorFound: boolean; {did we find an error?}
e3Start: codeRef; {ref to start of code for expression 3}
forLoop, continueLab, breakLab: integer; {branch points}
parencount: integer; {number of unmatched '(' chars}
stPtr: statementPtr; {work pointer}
tl,tk: tokenStackPtr; {for forming expression list}
begin {ForStatement}
NextToken; {skip the 'for' token}
@ -733,29 +724,12 @@ var
end; {if}
Match(semicolonch,22);
tl := nil; {collect the tokens for the last expression}
parencount := 0;
errorFound := false;
while (token.kind <> eofsy)
and ((token.kind <> rparench) or (parencount <> 0))
and (token.kind <> semicolonch) do begin
new(tk); {place the token in the list}
tk^.next := tl;
tl := tk;
tk^.token := token;
if token.kind = lparench then {allow parens in the expression}
parencount := parencount+1
else if token.kind = rparench then
parencount := parencount-1;
NextToken; {next token}
end; {while}
if errorFound then {if an error was found, dump the list}
while tl <> nil do begin
tk := tl;
tl := tl^.next;
dispose(tk);
end; {while}
stPtr^.e3List := tl; {save the list}
e3Start := GetCodeLocation; {generate and save code for expression 3}
if token.kind <> rparench then begin
Expression(normalExpression, [rparench]);
Gen0t(pc_pop, UsualUnaryConversions);
end; {if}
stPtr^.e3Code := RemoveCode(e3Start);
Match(rparench,12); {get the closing for loop paren}
if c99Scope then PushTable;
@ -1128,37 +1102,13 @@ procedure EndForStatement;
{ finish off a for statement }
var
ltoken: tokenType; {for putting ; on stack}
stPtr: statementPtr; {work pointer}
tl,tk: tokenStackPtr; {for forming expression list}
lSuppressMacroExpansions: boolean; {local copy of suppressMacroExpansions}
begin {EndForStatement}
if c99Scope then PopTable;
stPtr := statementList;
Gen1(dc_lab, stPtr^.continueLab); {define the continue label}
tl := stPtr^.e3List; {place the expression back in the list}
if tl <> nil then begin
PutBackToken(token, false, false);
ltoken.kind := semicolonch;
ltoken.class := reservedSymbol;
PutBackToken(ltoken, false, false);
while tl <> nil do begin
PutBackToken(tl^.token, false, false);
tk := tl;
tl := tl^.next;
dispose(tk);
end; {while}
lSuppressMacroExpansions := suppressMacroExpansions; {inhibit token echo}
suppressMacroExpansions := true;
NextToken; {evaluate the expression}
Expression(normalExpression, [semicolonch]);
Gen0t(pc_pop, UsualUnaryConversions);
NextToken; {skip the semicolon}
suppressMacroExpansions := lSuppressMacroExpansions;
end; {if}
InsertCode(stPtr^.e3Code); {insert code for expression 3}
Gen1(pc_ujp, stPtr^.forLoop); {loop to the test}
Gen1(dc_lab, stPtr^.breakLab); {create the exit label}
statementList := stPtr^.next; {pop the statement record}

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);

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

@ -741,7 +741,7 @@ if list or (numErr <> 0) then begin
122: msg := @'arithmetic is not allowed on a pointer to an incomplete or function type';
123: msg := @'array element type may not be an incomplete or function type';
124: msg := @'lint: invalid format string or arguments';
125: msg := @'lint: format string is not a string literal';
{125: msg := @'lint: format string is not a string literal';}
126: msg := @'scope rules may not be changed within a function';
127: msg := @'illegal storage class for declaration in for loop';
128: msg := @'lint: integer overflow in expression';
@ -756,7 +756,7 @@ if list or (numErr <> 0) then begin
137: msg := @'atomic types are not supported by ORCA/C';
138: msg := @'unsupported alignment';
{139: msg := @'thread-local storage is not supported by ORCA/C';}
140: msg := @'unexpected token';
{140: msg := @'unexpected token';}
141: msg := @'_Noreturn specifier is only allowed on functions';
142: msg := @'_Alignas may not be used in this declaration or type name';
143: msg := @'only object pointer types may be restrict-qualified';
@ -805,6 +805,7 @@ if list or (numErr <> 0) then begin
186: msg := @'lint: implicit conversion changes value of constant';
187: msg := @'expression has incomplete struct or union type';
188: msg := @'local variable used in asm statement is out of range for addressing mode';
189: msg := @'malformed numeric constant';
end; {case}
if extraStr <> nil then begin
extraStr^ := concat(msg^,extraStr^);
@ -1097,6 +1098,8 @@ case token.kind of
dotdotdotsy: write('...');
otherch: write(token.ch);
ppNumber: write(token.numString^);
macroParm: write('$', token.pnum:1);
@ -1118,16 +1121,11 @@ procedure CheckIdentifier; forward;
{ See if an identifier is a reserved word, macro or typedef }
procedure DoNumber (scanWork: boolean); forward;
procedure DoNumber; forward;
{ The current character starts a number - scan it }
{ }
{ Parameters: }
{ scanWork - get characters from workString? }
{ Scan a number from workString }
{ }
{ Globals: }
{ ch - first character in sequence; set to first char }
{ after sequence }
{ workString - string to take numbers from }
@ -1311,6 +1309,7 @@ var
class1,class2: tokenClass; {token classes}
i: integer; {loop variable}
kind1,kind2: tokenEnum; {token kinds}
lsaveNumber: boolean; {local copy of saveNumber}
lt: tokenType; {local copy of token}
str1,str2: stringPtr; {identifier strings}
@ -1373,27 +1372,37 @@ else if class1 in numericConstants then begin
str2 := @reservedWords[kind2]
else if kind2 = dotch then
str2 := @'.'
else if (kind2 = plusch)
and (tk1.numString^[length(tk1.numString^)] in ['e','E','p','P']) then
str2 := @'+'
else if (kind2 = minusch)
and (tk1.numString^[length(tk1.numString^)] in ['e','E','p','P']) then
str2 := @'-'
else begin
Error(63);
goto 1;
end; {else}
workString := concat(tk1.numString^, str2^);
lt := token;
DoNumber(true);
lsaveNumber := saveNumber;
saveNumber := true;
DoNumber;
saveNumber := lsaveNumber;
tk1 := token;
token := lt;
goto 1;
end {else if class1 in numericConstants}
else if kind1 = dotch then begin
if class2 in numericConstants then begin
workString := concat(tk1.numString^, tk2.numString^);
lt := token;
DoNumber(true);
tk1 := token;
token := lt;
goto 1;
end; {if}
if class2 in numericConstants then
if charKinds[ord(tk2.numString^[1])] = digit then begin
workString := concat('.', tk2.numString^);
lt := token;
DoNumber;
tk1 := token;
token := lt;
goto 1;
end; {if}
end {else if class1 in numericConstants}
else if kind1 = poundch then begin
@ -1878,6 +1887,8 @@ procedure Expand (macro: macroRecordPtr);
{ Globals: }
{ macroList - scanner putback buffer }
label 1;
type
parameterPtr = ^parameterRecord;
parameterRecord = record {parameter list element}
@ -2156,8 +2167,10 @@ else begin
tcPtr := pptr^.tokens;
if tcPtr = nil then begin
if tlPtr^.next <> nil then
if tlPtr^.next^.token.kind = poundpoundop then
tlPtr^.next := tlPtr^.next^.next;
if tlPtr^.next^.token.kind = poundpoundop then begin
tlPtr := tlPtr^.next;
goto 1;
end; {if}
if lastPtr <> nil then
if lastPtr^.token.kind = poundpoundop then
if tokenList <> nil then
@ -2179,7 +2192,7 @@ else begin
if not tcPtr^.expandEnabled then
inhibit := true;
if tcPtr = pptr^.tokens then
if (mPtr <> nil) and (mPtr^.parameters > 0) then
if (mPtr <> nil) and (mPtr^.parameters >= 0) then
inhibit := true;
if (mPtr <> nil) and (not inhibit) then
Expand(mPtr)
@ -2209,7 +2222,7 @@ else begin
tokenEnd := tlPtr^.tokenEnd;
PutBackToken(tlPtr^.token, expandEnabled, false);
end; {else}
lastPtr := tlPtr;
1: lastPtr := tlPtr;
tlPtr := tlPtr^.next;
end; {while}
end; {else}
@ -2786,8 +2799,12 @@ var
ple: stringListPtr; {pointer to the last element in parameterList}
pnum: integer; {for counting parameters}
tPtr,tk1,tk2: tokenListRecordPtr; {pointer to a token}
luseGlobalPool: boolean; {local copy of useGlobalPool}
begin {DoDefine}
lUseGlobalPool := useGlobalPool;
useGlobalPool := true; {use global memory for defines}
expandMacros := false; {block expansions}
saveNumber := true; {save characters in numeric tokens}
parameterList := nil; {no parameters yet}
@ -2969,6 +2986,9 @@ var
tk2^.token.sval^.str[i] then
goto 3;
end;
preprocessingNumber:
if tk1^.token.numString^ <> tk2^.token.numString^ then
goto 3;
macroParameter:
if tk1^.token.pnum <> tk2^.token.pnum then
goto 3;
@ -2999,6 +3019,7 @@ var
dispose(np);
end; {while}
saveNumber := false; {stop saving numeric strings}
useGlobalPool := lUseGlobalPool;
end; {DoDefine}
@ -3148,9 +3169,11 @@ var
else
Error(18);
if token.kind in [intconst,uintconst,ushortconst] then begin
floatSlot := $C080 | (token.ival << 4);
floatSlot := token.ival;
NextToken;
end {if}
else if token.kind = eolsy then
floatSlot := 0
else
Error(18);
end; {DoFloat}
@ -3493,7 +3516,9 @@ if ch in ['a','d','e','i','l','p','u','w'] then begin
expandMacros := false;
NextToken;
expandMacros := true;
if token.class <> identifier then begin
if token.kind = floatsy then
token.name := @'float'
else if token.class <> identifier then begin
if (lint & lintPragmas) <> 0 then
Error(110);
goto 2;
@ -3849,22 +3874,19 @@ Error(err);
end; {Error2}
procedure DoNumber {scanWork: boolean};
procedure DoNumber;
{ The current character starts a number - scan it }
{ }
{ Parameters: }
{ scanWork - get characters from workString? }
{ Scan a number from workString }
{ }
{ Globals: }
{ ch - first character in sequence; set to first char }
{ after sequence }
{ workString - string to take numbers from }
label 1,2;
var
atEnd: boolean; {at end of workString?}
c2: char; {next character to process}
err: integer; {error code}
i: integer; {loop index}
isBin: boolean; {is the value a binary number?}
isHex: boolean; {is the value a hex number?}
@ -3887,17 +3909,13 @@ var
{ Return the next character that is a part of the number }
begin {NextChar}
if scanWork then begin
if ord(workString[0]) <> numIndex then begin
numIndex := numIndex+1;
c2 := workString[numIndex];
end {if}
else
c2 := ' ';
if ord(workString[0]) <> numIndex then begin
numIndex := numIndex+1;
c2 := workString[numIndex];
end {if}
else begin
NextCh;
c2 := ch;
atEnd := true;
c2 := ' ';
end; {else}
end; {NextChar}
@ -3909,8 +3927,10 @@ var
{ code never actually get converted to numeric constants. }
begin {FlagError}
if not skipping then
Error(errCode);
if err = 0 then
err := errCode
else if err <> errCode then
err := 189;
end; {FlagError}
@ -3957,6 +3977,7 @@ var
begin {DoNumber}
atEnd := false; {not at end}
isBin := false; {assume it's not binary}
isHex := false; {assume it's not hex}
isReal := false; {assume it's an integer}
@ -3964,13 +3985,10 @@ isLong := false; {assume a short integer}
isLongLong := false;
isFloat := false;
unsigned := false; {assume signed numbers}
err := 0; {no error so far}
stringIndex := 0; {no digits so far...}
if scanWork then begin {set up the scanner}
numIndex := 0;
NextChar;
end {if}
else
c2 := ch;
numIndex := 0; {set up the scanner}
NextChar;
if c2 = '.' then begin {handle the case of no leading digits}
stringIndex := 1;
numString[1] := '0';
@ -4039,6 +4057,8 @@ while c2 in ['l','u','L','U'] do {check for long or unsigned}
if c2 = c1 then begin
NextChar;
isLongLong := true;
if isReal then
FlagError(156);
end {if}
else
isLong := true;
@ -4052,10 +4072,6 @@ while c2 in ['l','u','L','U'] do {check for long or unsigned}
unsigned := true;
end; {else}
if c2 in ['f','F'] then begin {allow F designator on reals}
if unsigned then
FlagError(91);
if isLongLong then
FlagError(156);
if not isReal then begin
FlagError(100);
isReal := true;
@ -4134,6 +4150,8 @@ else begin {hex, octal, & binary}
token.qval.hi := 0;
if isHex then begin
i := 3;
if length(numString) < 3 then
FlagError(189);
while i <= length(numString) do begin
if token.qval.hi & $F0000000 <> 0 then begin
i := maxint;
@ -4152,6 +4170,8 @@ else begin {hex, octal, & binary}
end {if}
else if isBin then begin
i := 3;
if length(numString) < 3 then
FlagError(189);
while i <= length(numString) do begin
if token.qval.hi & $80000000 <> 0 then begin
i := maxint;
@ -4167,7 +4187,7 @@ else begin {hex, octal, & binary}
end; {while}
end {if}
else begin
i := 1;
i := 2;
while i <= length(numString) do begin
if token.qval.hi & $E0000000 <> 0 then begin
i := maxint;
@ -4212,14 +4232,18 @@ else begin {hex, octal, & binary}
token.class := intConstant;
end; {else}
end; {else}
if saveNumber then begin
sp := pointer(GMalloc(length(numString)+1));
CopyString(pointer(sp), @numString);
if not atEnd then {make sure we read all characters}
FlagError(189);
if err <> 0 then begin {handle unconvertible pp-numbers}
token.class := preprocessingNumber;
token.kind := ppnumber;
token.errCode := err;
end; {if}
if saveNumber or (err <> 0) then begin
sp := pointer(GMalloc(length(workString)+1));
CopyString(pointer(sp), @workString);
token.numString := sp;
end; {if}
if scanWork then {make sure we read all characters}
if ord(workString[0]) <> numIndex then
Error(63);
end; {DoNumber}
@ -4556,7 +4580,8 @@ lintErrors :=
spaceStr := ' '; {strings used in stringization}
quoteStr := '"';
{set of classes for numeric constants}
numericConstants := [intConstant,longConstant,longlongConstant,realConstant];
numericConstants :=
[intConstant,longConstant,longlongConstant,realConstant,preprocessingNumber];
new(mp); {__LINE__}
mp^.name := @'__LINE__';
@ -4787,7 +4812,7 @@ repeat
else if lch in ['.','0'..'9'] then begin
token.name := GetWord;
saveNumber := true;
DoNumber(true);
DoNumber;
saveNumber := false;
end {else if}
else if lch = '"' then
@ -5311,6 +5336,44 @@ var
end; {ConcatenateTokenString}
procedure Number;
{ Scan a preprocessing number token. It is converted to an }
{ integer or floating constant if it matches the syntax for }
{ one of those, or left as a preprocessing number if not. }
var
numLen: 1..maxint;
lastCh: char;
begin {Number}
numLen := 0;
lastCh := chr(0);
while (charKinds[ord(ch)] in [digit,letter,ch_dot])
or ((lastCh in ['e','E','p','P'])
and (charKinds[ord(ch)] in [ch_plus,ch_dash])) do
begin
if numLen < 255 then begin
numLen := numLen + 1;
workString[numLen] := ch;
end {if}
else
numLen := 256;
lastCh := ch;
NextCh;
end; {while}
if numLen = 256 then begin
if not skipping then
Error(131);
numLen := 1;
workString[1] := '0';
end; {if}
workString[0] := chr(numLen);
DoNumber;
end; {Number}
begin {NextToken}
if ifList = nil then {do pending EndInclude calls}
while includeCount <> 0 do begin
@ -5644,7 +5707,7 @@ case charKinds[ord(ch)] of
ch_dot : begin {tokens that start with '.'}
if charKinds[ord(PeekCh)] = digit then
DoNumber(false)
Number
else begin
NextCh;
if (ch = '.') and (PeekCh = '.') then begin
@ -5857,7 +5920,7 @@ case charKinds[ord(ch)] of
end;
digit : {numeric constants}
DoNumber(false);
Number;
ch_other: begin {other non-whitespace char (pp-token)}
token.kind := otherch;
@ -5915,10 +5978,20 @@ if printMacroExpansions then
if not suppressMacroExpansions then
if not suppressPrint then
PrintToken(token); {print the token stream}
if token.kind = otherch then
if token.kind = otherch then begin
if not (skipping or preprocessing or suppressMacroExpansions)
or doingPPExpression then
Error(1);
end {if}
else if token.kind = ppNumber then
if not (skipping or preprocessing or suppressMacroExpansions)
or doingPPExpression then begin
Error(token.errCode);
token.kind := intconst;
token.class := intConstant;
token.ival := 0;
token.numString := @'0';
end; {if}
end; {NextToken}

View File

@ -309,6 +309,8 @@ charSym start single character symbols
enum (barbarop,pluseqop,minuseqop,asteriskeqop,slasheqop)
enum (percenteqop,ltlteqop,gtgteqop,andeqop,caroteqop)
enum (bareqop,poundpoundop,dotdotdotsy)
enum (ppnumber) preprocessing number
enum (otherch) other non-whitespace char
enum (eolsy,eofsy) control characters
enum (typedef) user types
! converted operations
@ -466,6 +468,7 @@ icp start in-coming priority for expression
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
@ -644,6 +647,7 @@ isp start in stack priority for expression
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

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

@ -34,7 +34,7 @@ second string argument!"))
goto Fail;
strcpy(s1, "this is the first string argument");
strcpy(s1, strncat (s1, s2, -5));
strcpy(s1, strncat (s1, s2, 0));
if (strcmp (s1, "this is the first string argument"))
goto Fail;

View File

@ -29,7 +29,7 @@ int main (void)
if (i != 0)
goto Fail;
i = strncmp (s1, s2, -90L); /* should just return 0 */
i = strncmp (s1, s2, 0L); /* should just return 0 */
if (i != 0)
goto Fail;

View File

@ -54,7 +54,7 @@ int main (void)
if (i != 1)
goto Fail3;
string [41] = '\0';
if (strcmp (string, " +009. -0001.23456E-18 9876543210 G"))
if (strcmp (string, " +009. -1.23456E-18 9876543210 G"))
goto Fail;
rewind (stdout);
@ -62,10 +62,10 @@ int main (void)
if (i != 1)
goto Fail3;
string [41] = '\0';
if (strcmp (string, " +009. -0001.23456E-18 9876543210 G"))
if (strcmp (string, " +009. -1.23456E-18 9876543210 G"))
goto Fail;
if (strcmp (sstring, " +009. -0001.23456E-18 9876543210 G\n"))
if (strcmp (sstring, " +009. -1.23456E-18 9876543210 G\n"))
goto Fail;

View File

@ -35,37 +35,37 @@ int main (void)
/* Write formatted output as string to the output files and sstring. */
i = fprintf (f1, " %0+*.*Le %- 15E %#0 .e E\n", i1, i2, e1, d1, fl1);
if (i != 54)
if (i != 55)
goto Fail;
i = printf (" %0+*.*Le %- 15E %#0 .e E\n", i1, i2, e1, d1, fl1);
if (i != 54)
if (i != 55)
goto Fail;
i = sprintf (sstring, " %0+*.*Le %- 15E %#0 .e E\n", i1, i2, e1, d1, fl1);
if (i != 54)
if (i != 55)
goto Fail;
/* Check the string written. */
rewind (f1);
i = fscanf (f1, "%53c", string);
i = fscanf (f1, "%54c", string);
if (i != 1)
goto Fail3;
string [53] = '\0';
if (strcmp (string, " +1.2345600000000000e-203 -4.700000E+00 5e+00 E"))
string [54] = '\0';
if (strcmp (string, " +1.2345600000000000e-203 -4.700000E+00 5.e+00 E"))
goto Fail;
rewind (stdout);
i = fscanf (stdout, "%53c", string);
i = fscanf (stdout, "%54c", string);
if (i != 1)
goto Fail3;
string [53] = '\0';
if (strcmp (string, " +1.2345600000000000e-203 -4.700000E+00 5e+00 E"))
string [54] = '\0';
if (strcmp (string, " +1.2345600000000000e-203 -4.700000E+00 5.e+00 E"))
goto Fail;
if (strcmp (sstring, " +1.2345600000000000e-203 -4.700000E+00 5e+00 E\n"))
if (strcmp (sstring, " +1.2345600000000000e-203 -4.700000E+00 5.e+00 E\n"))
goto Fail;

View File

@ -5,7 +5,7 @@
int main (void)
{
char sstr [] = " 23 -3.8E20 - e- +25e- 00002.00008e000049.9 ";
char sstr [] = " 23 -3.8E20 -0 0e-9 +25e-0 00002.00008e000049.9 ";
float f1, f2, f3, f4;
double d1, d2, d3;
int i;

View File

@ -16,7 +16,7 @@ int main (void)
f = fopen ("3/tmp", "wb+"); /* open input file for test */
if (f == NULL)
goto Fail1;
fprintf(f, "23 -3.8E20 - e- +25e- 00002.00008e000049.9");
fprintf(f, "23 -3.8E20 -0 0e-0 +25e-0 00002.00008e000049.9");
fclose(f);
stdin = freopen ("3/tmp", "r", stdin);

View File

@ -14,7 +14,7 @@ int main (void)
f = fopen ("3/tmp", "wb+"); /* open input file for test */
if (f == NULL)
goto Fail1;
fprintf(f, "23 -3.8E20 - e- +25e- 00002.00008e000049.9");
fprintf(f, "23 -3.8E20 -0 0e-0 +25e-0 00002.00008e000049.9");
rewind(f);
f1 = f2 = f3 = f4 = 1.0;

View File

@ -26,6 +26,9 @@
{1} c99pragma.c
{1} c99inline.c
{1} c99desinit.c
{1} c99printfa.c
{1} c99strtold.c
{1} c99ppnum.c
{1} c11generic.c
{1} c11align.c
{1} c11noret.c

View File

@ -155,15 +155,13 @@ int main(void) {
expect_exact(cosh(+INFINITY), +INFINITY);
expect_exact(coshf(-INFINITY), +INFINITY);
expect_overflow(coshl(LDBL_MAX), +INFINITY);
feclearexcept(FE_ALL_EXCEPT); // ORCA/C cosh bug workaround
expect_approx(coshl(1.0), 1.543080634815243778546L);
feclearexcept(FE_ALL_EXCEPT); // ORCA/C cosh bug workaround
expect_approx(coshl(-10.0), 11013.23292010332313939L);
expect_exact(sinh(+0.0), +0.0);
expect_exact(sinhf(-0.0), -0.0);
//expect_exact(sinh(+INFINITY), +INFINITY); // ORCA/C gives a NAN
//expect_exact(sinhf(-INFINITY), -INFINITY); // ORCA/C gives a NAN
expect_exact(sinh(+INFINITY), +INFINITY);
expect_exact(sinhf(-INFINITY), -INFINITY);
expect_approx(sinhl(1.25), 1.601919080300825637951L);
expect_approx(sinhl(-20.0), -242582597.704895138042L);
@ -365,6 +363,34 @@ int main(void) {
expect_approx(erfcl(9.99L), 2.553157649309533e-45L);
expect_approx(erfcl(105.0L), 4.300838032791244e-4791L);
expect_exact(lgamma(1.0), +0.0);
expect_exact(lgammaf(2.0), -0.0);
expect_pole_error(lgammal(0.0), +INFINITY);
expect_pole_error(lgammal(-0.0), +INFINITY);
expect_pole_error(lgammal(-1.0), +INFINITY);
expect_pole_error(lgammal(-2.0), +INFINITY);
expect_pole_error(lgammal(-3.0), +INFINITY);
expect_pole_error(lgammal(-1e50), +INFINITY);
expect_pole_error(lgammal(-LDBL_MAX), +INFINITY);
expect_exact(lgamma(-INFINITY), +INFINITY);
expect_exact(lgammaf(+INFINITY), +INFINITY);
expect_approx(lgammal(1e-50L), 1.151292546497022842e+02L);
expect_approx(lgammal(0.5L), 5.723649429247000870e-01L);
expect_approx(lgammal(0.99L), 5.854806764709776173e-03L);
expect_approx(lgammal(1.00000000001L), -5.772156625868682203e-12L);
expect_approx(lgammal(1.25L), -9.827183642181316143e-02L);
expect_approx(lgammal(1.9999999999L), -4.227843352103923846e-11L);
expect_approx(lgammal(2.125L), 5.775985153034387160e-02L);
expect_approx(lgammal(3.5L), 1.200973602347074225e+00L);
expect_approx(lgammal(1200.75L), 7.310783651998328589e+03L);
expect_approx(lgammal(1e4928L), 1.134613933827465713e+4932L);
expect_approx(lgammal(-0.00000000001L), 2.532843602294027468e+01L);
expect_approx(lgammal(-0.99L), 4.609530213895523164e+00L);
expect_approx(lgammal(-1.5L), 8.600470153764810144e-01L);
expect_approx(lgammal(-2.000000953674316L), 1.316979555107021760e+01L);
expect_approx(lgammal(-5.75L), -4.624612415302172588e+00L);
expect_approx(lgammal(-1000000000000.5L), -2.663102111595595344e+13L);
expect_pole_error(tgamma(+0.0), +INFINITY);
expect_pole_error(tgammaf(-0.0), -INFINITY);
expect_domain_error(tgammal(-2.0));
@ -507,14 +533,14 @@ int main(void) {
expect_exact(fmod(+0.0, 10.0), +0.0);
expect_exact(fmodf(-0.0, 10.0), -0.0);
//expect_domain_error(fmodl(INFINITY, 10.0)); // no "invalid" in ORCA/C
expect_domain_error(fmodl(INFINITY, 10.0));
expect_nan(fmodl(INFINITY, 10.0));
//expect_domain_error(fmod(1.0, 0.0)); // gives 1 in ORCA/C
expect_domain_error(fmod(1.0, 0.0));
//expect_exact(fmodl(1.25, +INFINITY), 1.25); //gives NAN in ORCA/C
expect_exact(fmodl(11.5, 3.0), 2.5);
expect_exact(fmodl(-11.5, 3.0), -2.5);
//expect_exact(fmodl(11.5, -3.0), 2.5); // gives -0.5 in ORCA/C
//expect_exact(fmodl(-11.5, -3.0), -2.5); // gives -0.5 in ORCA/C
expect_exact(fmodl(11.5, -3.0), 2.5);
expect_exact(fmodl(-11.5, -3.0), -2.5);
expect_exact(remainder(+0.0, 10.0), +0.0);
expect_exact(remainderf(-0.0, 10.0), -0.0);
@ -606,10 +632,10 @@ int main(void) {
expect_exact(strtod("-1.25e+3x", &p), -1250.0); expect_exact(*p, 'x');
expect_exact(strtold("-InFin", &p), -INFINITY); expect_exact(*p, 'i');
expect_exact(strtof("INFiniTy", &p), INFINITY); //expect_exact(*p, 0);
expect_exact(strtof("INFiniTy", &p), INFINITY); expect_exact(*p, 0);
expect_nan(strtod("nAN", NULL));
expect_nan(strtof("-naN(50)", NULL));
//expect_exact(strtold("0xa.8p+2", NULL), 42.0);
expect_exact(strtold("0xa.8p+2", NULL), 42.0);
printf ("Passed Conformance Test c99math\n");
return 0;

View File

@ -0,0 +1,36 @@
/*
* Test handling of preprocessing numbers.
*
* Most of this applies to C89, but hex float and long long are specific to
* C99 and later.
*/
#include <stdio.h>
#include <string.h>
#define COMBINE3(a,b,c) a##b##c
#define STRINGIZE(x) #x
int main(void) {
if (COMBINE3(123,.,456) != 123.456)
goto Fail;
if (COMBINE3(1.,08,999999999999999999999999999999999)
!= 1.08999999999999999999999999999999999)
goto Fail;
if (COMBINE3(0x,AB,09) != 0xAB09)
goto Fail;
if (strcmp(STRINGIZE(.1xyzp+), ".1xyzp+") != 0)
goto Fail;
if (strcmp(STRINGIZE(0xaBcD), "0xaBcD") != 0)
goto Fail;
if (strcmp(STRINGIZE(089ae-.), "089ae-.") != 0)
goto Fail;
if (sizeof(COMBINE3(123,L,L)) < sizeof(long long))
goto Fail;
printf ("Passed Conformance Test c99ppnum\n");
return 0;
Fail:
printf ("Failed Conformance Test c99ppnum\n");
}

View File

@ -0,0 +1,143 @@
/*
* Test 'a' and 'A' conversions in printf (C99).
*
* This makes certain assumptions about implementation-defined
* behavior like the positioning of bits in hex float output.
*/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <float.h>
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
int main(void) {
char buf[100];
snprintf(buf, sizeof(buf), "%.15La %0.10LA", 123.0L, -234.0L);
if (strcmp(buf, "0xf.600000000000000p+3 -0XE.A000000000P+4"))
goto Fail;
snprintf(buf, sizeof(buf), "% 10.15La", 123.0L);
if (strcmp(buf, " 0xf.600000000000000p+3"))
goto Fail;
snprintf(buf, sizeof(buf), "%+ 25.15La", 123.0L);
if (strcmp(buf, " +0xf.600000000000000p+3"))
goto Fail;
snprintf(buf, sizeof(buf), "%.0La %#.0La", 123.0L, 123.0L);
if (strcmp(buf, "0xfp+3 0xf.p+3"))
goto Fail;
snprintf(buf, sizeof(buf), "%10.0La", 123.0L);
if (strcmp(buf, " 0xfp+3"))
goto Fail;
snprintf(buf, sizeof(buf), "%0#10.0La", 123.0L);
if (strcmp(buf, "0x000f.p+3"))
goto Fail;
snprintf(buf, sizeof(buf), "%-010.0La", 123.0L);
if (strcmp(buf, "0xfp+3 "))
goto Fail;
snprintf(buf, sizeof(buf), "%La", 0xf.abcdef012345678p-16000L);
if (strcmp(buf, "0xf.abcdef012345678p-16000"))
goto Fail;
snprintf(buf, sizeof(buf), "%30La", -0xf.abcdef012345678p+16000L);
if (strcmp(buf, " -0xf.abcdef012345678p+16000"))
goto Fail;
snprintf(buf, sizeof(buf), "%.15A", -0.0);
if (strcmp(buf, "-0X0.000000000000000P+0"))
goto Fail;
snprintf(buf, sizeof(buf), "%010A", -INFINITY);
if (strcmp(buf, " -INF"))
goto Fail;
snprintf(buf, sizeof(buf), "%A", NAN);
if (!strstr(buf, "NAN"))
goto Fail;
snprintf(buf, sizeof(buf), "%LA", (long double)LDBL_MAX);
if (strcmp(buf, "0XF.FFFFFFFFFFFFFFFP+16380"))
goto Fail;
#ifdef __ORCAC__
snprintf(buf, sizeof(buf), "%.10LA", -(long double)LDBL_MAX);
if (strcmp(buf, "-0X8.0000000000P+16381"))
goto Fail;
snprintf(buf, sizeof(buf), "%.14LA", (long double)LDBL_MAX);
if (strcmp(buf, "0X8.00000000000000P+16381"))
goto Fail;
snprintf(buf, sizeof(buf), "%.14LA", 0XF.FFFFFFFFFFFFFF8P+16380L);
if (strcmp(buf, "0X8.00000000000000P+16381"))
goto Fail;
snprintf(buf, sizeof(buf), "%.14LA", 0XF.FFFFFFFFFFFFFF7P+16380L);
if (strcmp(buf, "0XF.FFFFFFFFFFFFFFP+16380"))
goto Fail;
snprintf(buf, sizeof(buf), "%.6LA", 0XF.1234567p-50L);
if (strcmp(buf, "0XF.123456P-50"))
goto Fail;
snprintf(buf, sizeof(buf), "%.6LA", 0XF.1234568p+500L);
if (strcmp(buf, "0XF.123456P+500"))
goto Fail;
snprintf(buf, sizeof(buf), "%.6LA", -0XF.1234569p+5000L);
if (strcmp(buf, "-0XF.123457P+5000"))
goto Fail;
fesetround(FE_UPWARD);
snprintf(buf, sizeof(buf), "%.14LA", 0XF.FFFFFFFFFFFFFF7P+16380L);
if (strcmp(buf, "0X8.00000000000000P+16381"))
goto Fail;
snprintf(buf, sizeof(buf), "%.14LA", -0XF.FFFFFFFFFFFFFF7P+16380L);
if (strcmp(buf, "-0XF.FFFFFFFFFFFFFFP+16380"))
goto Fail;
fesetround(FE_DOWNWARD);
snprintf(buf, sizeof(buf), "%.14LA", -0XF.FFFFFFFFFFFFFF7P+16380L);
if (strcmp(buf, "-0X8.00000000000000P+16381"))
goto Fail;
snprintf(buf, sizeof(buf), "%.14LA", 0XF.FFFFFFFFFFFFFF7P+16380L);
if (strcmp(buf, "0XF.FFFFFFFFFFFFFFP+16380"))
goto Fail;
fesetround(FE_TOWARDZERO);
snprintf(buf, sizeof(buf), "%.14LA", -0XF.FFFFFFFFFFFFFF7P+16380L);
if (strcmp(buf, "-0XF.FFFFFFFFFFFFFFP+16380"))
goto Fail;
snprintf(buf, sizeof(buf), "%.14LA", 0XF.FFFFFFFFFFFFFF7P+16380L);
if (strcmp(buf, "0XF.FFFFFFFFFFFFFFP+16380"))
goto Fail;
fesetround(FE_TONEAREST);
snprintf(buf, sizeof(buf), "%La", (long double)0x1p-16445);
if (strcmp(buf, "0x0.000000000000002p-16386"))
goto Fail;
#endif
printf ("Passed Conformance Test c99printfa\n");
return 0;
Fail:
printf ("Failed Conformance Test c99printfa\n");
}

View File

@ -0,0 +1,113 @@
/*
* Test strtold function (C99).
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <math.h>
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
void fail(void) {
printf ("Failed Conformance Test c99strtold\n");
exit(0);
}
void test(const char *str, long double val, size_t len, int err) {
char *endptr;
long double result;
errno = 0;
result = strtold(str, &endptr);
if (err >= 0 && errno != err)
fail();
if (endptr-str != len)
fail();
if (!isnan(val)) {
if (result != val || !!signbit(result) != !!signbit(val))
fail();
} else {
if (!isnan(result))
fail();
}
}
int main(void) {
test("1", 1.0L, 1, 0);
test("-2.25E-7", -2.25E-7L, 8, 0);
test("InfiniTy", +INFINITY, 8, 0);
test("-inFinitx", -INFINITY, 4, 0);
test("NaN", NAN, 3, 0);
test(" -nan(123)", NAN, 10, 0);
test("nan(abC_123)", NAN, 12, 0);
test("nan(abC_123-)", NAN, 3, 0);
test("nan(123", NAN, 3, 0);
test("\t+Nan()", NAN, 7, 0);
test("-0xF.8p-1", -7.75L, 9, 0);
test(" +0XAB4fp2", 175420.0L, 10, 0);
test("0X.23423p-1", 0X.23423p-1L, 11, 0);
test("0x4353.p+7", 2206080.0L, 10, 0);
test("0xabcdef0012345678ffffffffffffp123",
3.7054705751091077761e+70L, 34, 0);
test("0xabcdef0012345678000000000000p123",
3.7054705751091077758e+70L, 34, 0);
test("0x0.0000000000000000000000012345aP50",
1.61688425235478883124e-14L, 36, 0);
test("0x1324124.abcd23p-3000", 1.63145601325652579262e-896L, 22, 0);
test("0x0000000000.000000p1234567890123456789012345678901234567890",
0.0, 60, 0);
test("0X1p17000", INFINITY, 9, ERANGE);
test("0x1.fffffffffffffffep16383",
1.18973149535723176502e+4932L, 26, 0);
test("0x1.ffffffffffffffffp16383", INFINITY, 26, ERANGE);
test("0X1p-16400L", 1.28254056667789211512e-4937L, 10, -1);
test("0x3abd.232323p-16390", 1.97485962609712244075e-4930L, 20, 0);
test("0x7.7p-17000", 0.0, 12, -1);
test("+0x1.8p+", 1.5L, 6, 0);
test(" \t\f\n\r\v1.25---", 1.25, 10, 0);
test("0x.p50", 0.0, 1, 0);
test(" +abc", 0.0, 0, -1);
test("-0", -0.0, 2, 0);
test("-0x0p123", -0.0, 8, 0);
fesetround(FE_UPWARD);
test("0x8.0000000000000008", 0x8.000000000000001p0L, 20, 0);
test("0x8.0000000000000009", 0x8.000000000000001p0L, 20, 0);
test("0x8.0000000000000018", 0x8.000000000000002p0L, 20, 0);
test("-0x8.0000000000000008", -0x8.000000000000000p0L, 21, 0);
test("-0x8.0000000000000009", -0x8.000000000000000p0L, 21, 0);
test("-0x8.0000000000000018", -0x8.000000000000001p0L, 21, 0);
test("0x8.00000000000000080001", 0x8.000000000000001p0L, 24, 0);
fesetround(FE_DOWNWARD);
test("0x8.0000000000000008", 0x8.000000000000000p0L, 20, 0);
test("0x8.0000000000000009", 0x8.000000000000000p0L, 20, 0);
test("0x8.0000000000000018", 0x8.000000000000001p0L, 20, 0);
test("-0x8.0000000000000008", -0x8.000000000000001p0L, 21, 0);
test("-0x8.0000000000000009", -0x8.000000000000001p0L, 21, 0);
test("-0x8.0000000000000018", -0x8.000000000000002p0L, 21, 0);
test("0x8.00000000000000080001", 0x8.000000000000000p0L, 24, 0);
fesetround(FE_TOWARDZERO);
test("0x8.0000000000000008", 0x8.000000000000000p0L, 20, 0);
test("0x8.0000000000000009", 0x8.000000000000000p0L, 20, 0);
test("0x8.0000000000000018", 0x8.000000000000001p0L, 20, 0);
test("-0x8.0000000000000008", -0x8.000000000000000p0L, 21, 0);
test("-0x8.0000000000000009", -0x8.000000000000000p0L, 21, 0);
test("-0x8.0000000000000018", -0x8.000000000000001p0L, 21, 0);
test("0x8.00000000000000080001", 0x8.000000000000000p0L, 24, 0);
fesetround(FE_TONEAREST);
test("0x8.0000000000000008", 0x8.000000000000000p0L, 20, 0);
test("0x8.0000000000000009", 0x8.000000000000001p0L, 20, 0);
test("0x8.0000000000000018", 0x8.000000000000002p0L, 20, 0);
test("-0x8.0000000000000008", -0x8.000000000000000p0L, 21, 0);
test("-0x8.0000000000000009", -0x8.000000000000001p0L, 21, 0);
test("-0x8.0000000000000018", -0x8.000000000000002p0L, 21, 0);
test("0x8.00000000000000080001", 0x8.000000000000001p0L, 24, 0);
printf ("Passed Conformance Test c99strtold\n");
return 0;
}

View File

@ -5,9 +5,7 @@
void main(void)
{
int i;
i = 4/0;
static int i = 4/0;
printf("Failed Deviance Test 7.6.1.2\n");
}

View File

@ -5,9 +5,7 @@
void main(void)
{
int i;
i = 4%0;
static int i = 4%0;
printf("Failed Deviance Test 7.6.1.3\n");
}

177
cc.notes
View File

@ -1,10 +1,14 @@
ORCA/C 2.2.0 B7
ORCA/C 2.2.1
Copyright 1997, Byte Works Inc.
Updated by Stephen Heumann and Kelvin Sherlock, 2017-2023
Updated by Stephen Heumann and Kelvin Sherlock, 2017-2024
These release notes document the changes between ORCA/C 2.0 and ORCA/C 2.2.1. They are intended mainly for users familiar with earlier versions of ORCA/C. New users should refer to the ORCA/C 2.2 manual, which has been fully updated to document the new features and other changes in ORCA/C 2.2.
-- Change List --------------------------------------------------------------
2.2.0 B7 1. Bugs squashed. See bug notes, below.
2.2.1 1. Bugs squashed. See bug notes, below.
2.2.0 1. Bugs squashed. See bug notes, below.
2. New language features added (mainly features from C99 and C11).
See "New Language Features," below.
@ -58,6 +62,8 @@ Updated by Stephen Heumann and Kelvin Sherlock, 2017-2023
19. The code generated for certain operations has been improved.
20. The slot parameter to #pragma float now sets the FPE slot.
2.1.1 B3 1. Bugs squashed. See bug notes, below.
2.1.0 1. Bugs squashed. See bug notes, below.
@ -82,7 +88,9 @@ Updated by Stephen Heumann and Kelvin Sherlock, 2017-2023
2.0.1 1. Bugs squashed. See bug notes, below.
-- Manual Errata ------------------------------------------------------------
-- Manual Errata in the ORCA/C 2.0 Manual -----------------------------------
(These errata have been corrected in the ORCA/C 2.2 manual.)
p. 40
@ -197,6 +205,8 @@ If precompiled headers are being used, #pragma expand will not print the tokens
p. 258
The slot parameter to #pragma float is now optional, and if present is used to set the FPE slot. See "Changes to #pragma float," below.
The #pragma ignore directive supports several new bits.
Bit 1 affects the interpretation of multi-character character constants. See "Multi-Character Character Constants," below.
@ -317,10 +327,6 @@ p. 352
If a dup() call is successful, it actually returns the new file ID (a non-negative integer).
p. 355
If an fcntl() call using F_DUPFD is successful, it actually returns the new file ID (a non-negative integer).
p. 353
All error numbers used by errno are defined in <errno.h>, not <math.h>.
@ -331,6 +337,10 @@ p. 354
The discussion of abort() should note that it will call raise(SIGABRT) before exiting. Accordingly, if a SIGABRT handler was previously registered via a call to signal(), it will be executed.
p. 355
If an fcntl() call using F_DUPFD is successful, it actually returns the new file ID (a non-negative integer).
p. 356
fgetpos() and fsetpos() actually set errno to EIO if there is an error.
@ -545,7 +555,7 @@ The CX_LIMITED_RANGE pragma relates to complex arithmetic, which ORCA/C does not
type-name ':' assignment-expression |
default ':' assignment-expression
The generic-assoc-list provides a list of associations of types with expressions (and optionally a default association). If the type of the the initial expression is compatible with one of those in the generic-assoc-list, the generic selection expression evaluates to the expression specified in that association. If there is no compatible type but there is a default association, the expression specified there is used. It is an error if there is no suitable association. Only the expression from the selected association is evaluated and becomes the value of the overall generic selection expression; the initial expression and all those in other associations are not evaluated.
The generic-assoc-list provides a list of associations of types with expressions (and optionally a default association). If the type of the initial expression is compatible with one of those in the generic-assoc-list, the generic selection expression evaluates to the expression specified in that association. If there is no compatible type but there is a default association, the expression specified there is used. It is an error if there is no suitable association. Only the expression from the selected association is evaluated and becomes the value of the overall generic selection expression; the initial expression and all those in other associations are not evaluated.
As an example, this expression evaluates to 2 because the type of 1+2 is int:
@ -555,7 +565,9 @@ Generic selection expressions are primarily useful within macros, which can give
23. (C11) Character constants and string literals may now have prefixes indicating they should use Unicode encodings. The prefixes u8, u, and U indicate UTF-8, UTF-16, and UTF-32 encodings, respectively. The u8 prefix may only be used on string literals. The U and u prefixes may be used on string literals or character constants. U- and u-prefixed character constants have the types char32_t and char16_t (as defined in <uchar.h>); U- and u-prefixed string literals are treated as arrays of those types. For example, the string literal U"abc" designates an array with four members of type char32_t: the three letters encoded in UTF-32, plus a null terminator.
24. (C99) Floating-point constants may now be expressed in a hexadecimal format. These consist of a leading 0X or 0x, followed by a sequence of hexadecimal digits optionally containing a period, then P or p, then an exponent expressed as a sequence of decimal digits optionally preceded by + or -. These designate the number given by the hexadecimal digit sequence (with any digits after the period being the fractional part) multiplied by 2 raised to the specified exponent. For example, the constant 0xF.8p-1 is equivalent to 7.75. Note that ORCA/C currently only supports this hexadecimal floating-point format in C source code, not as an input or output format for any library functions.
24. (C99) Floating-point constants may now be expressed in a hexadecimal format. These consist of a leading 0X or 0x, followed by a sequence of hexadecimal digits optionally containing a period, then P or p, then an exponent expressed as a sequence of decimal digits optionally preceded by + or -. These designate the number given by the hexadecimal digit sequence (with any digits after the period being the fractional part) multiplied by 2 raised to the specified exponent. For example, the constant 0xF.8p-1 is equivalent to 7.75.
Note that the fprintf family of functions also support output in this hexadecimal floating-point format using the 'A' and 'a' conversion specifiers, described below. The strtod, strtold, and strtof functions can also accept numbers in this format as input.
25. (C99) When a function parameter is declared with an array type, type qualifiers and/or the keyword "static" may be included within the angle brackets that designate the array type. For example, a function may be defined as:
@ -678,6 +690,14 @@ ORCA/C can perform certain optimizations on floating-point computations based on
A new #pragma optimize bit has now been introduced to control this behavior. Setting bit 7 (a value of 128) allows floating-point math optimizations that may violate the IEEE standard. It currently only has an effect if #pragma optimize bit 0 or bit 4 is also set. If bit 7 is not set, these floating-point optimizations will not be performed. This allows most aspects of intermediate code peephole optimization and common subexpression elimination to be used while preserving IEEE floating-point behavior.
Changes to #pragma float
------------------------
The second numeric parameter to #pragma float is now optional. If it is provided, it specifies the slot number of the FPE card. If it is not provided or is not in the range 1-7, the FPE card is auto-detected instead. With these changes, it is generally no longer necessary to call setfpeslot() in programs that use the FPE card.
If you use #pragma float in any of the special types of programs that can be created using other pragmas, the slot parameter will be ignored and the FPE will not be auto-detected. In those cases, the program will still need to call setfpeslot() to set the slot number before doing any floating-point operations.
Additions to #pragma ignore
---------------------------
@ -913,7 +933,7 @@ int vsnprintf(char * restrict s, size_t n, const char * restrict format,
These are equivalent to sprintf and vsprintf, except that they take an additional argument giving the maximum number of characters to be written. If n is 0, no characters are written. Otherwise, at most n-1 characters are written based on the format string, followed by a terminating null character. They return the number of characters (not including the terminating null character) that would have been written if there was no size limit.
3. (C99) The vscanf(), vfscanf(), anf vsscanf() functions have been added:
3. (C99) The vscanf(), vfscanf(), and vsscanf() functions have been added:
#include <stdarg.h>
#include <stdio.h>
@ -927,7 +947,11 @@ These functions are equivalent to scanf, fscanf, and sscanf, except that the var
The length modifiers 'z', 't', 'j', 'hh', and 'll' are now allowed in the format strings for the fprintf and fscanf families of functions. They may be used with the 'd', 'i', 'o', 'u', 'x', 'X', or 'n' conversion specifiers. These each correspond to integer types, as follows: 'z' to size_t or the corresponding signed integer type, 't' to ptrdiff_t or the corresponding unsigned integer type, 'j' to intmax_t or uintmax_t, 'hh' to signed char or unsigned char, and 'll' to long long or unsigned long long. The corresponding argument must be an integer of an appropriate type, or a pointer to such an integer, as appropriate for the function and conversion specifier.
The conversion specifiers 'F', 'a', and 'A' are now allowed in the format strings for the fscanf family of functions. These are all equivalent to 'f' (but none of them accept numbers in the hexadecimal format allowed by C99). The 'F' conversion specifier is also now allowed in the format strings for the fprintf family of functions. It is equivalent to 'f', except that "INF" and "NAN" are guaranteed to be printed in upper case. The conversion specifiers 'a' and 'A' (both also used with floating-point numbers) are also recognized in the format strings for the fprintf family of functions, but they do not currently print the numbers in the hexadecimal format required by the C99 standard.
The conversion specifiers 'a' and 'A' are now allowed in the format strings for the fprintf family of functions. The 'a' specifier consumes an argument of type double or long double and writes the value in a hexadecimal exponential format. It consists of a leading sign (if negative or required by the flags used), then '0x', then a number in hexadecimal format (with one hexadecimal digit for the integer part, then a dot and fractional digits), then 'p', then a signed decimal number giving the exponent of 2. If a precision is specified, it gives the number of digits after the dot; if not, enough digits are used to exactly represent the number. If the precision is 0 and the '#' flag is not used, no dot is printed. The 'A' specifier is equivalent to 'a', except that all letters are output in upper case.
The conversion specifier 'F' is now allowed in the format strings for the fprintf family of functions. It is equivalent to 'f', except that "INF" and "NAN" are guaranteed to be printed in upper case.
The conversion specifiers 'F', 'a', and 'A' are also allowed in the format strings for the fscanf family of functions. These are all equivalent to 'f' (but none of them accept numbers in the hexadecimal format described above).
The ORCA/C-specific conversion specifier 'P' is now allowed in the format strings for the fprintf and fscanf families of functions. This works exactly the same as the existing 'b' conversion specifier, printing or reading input to a string with a leading length byte (a p-string). This new specifier was introduced because the 'b' specifier may be used for a different purpose in future C standards. For the time being, the 'b' specifier is still available with its existing meaning, but it is considered deprecated. Code should be migrated to use the 'P' conversion specifier instead.
@ -1252,6 +1276,13 @@ int ilogbl(long double x);
These functions extract the binary exponent of x as an integer value, treating denormalized numbers as if they were normalized. If x is 0, infinite, or NaN, they return the macro values FP_ILOGB0, INT_MAX, or FP_ILOGBNAN, respectively.
#include <math.h>
double lgamma(double x);
float lgammaf(float x);
long double lgammal(long double x);
These functions compute the natural logarithm of the absolute value of the gamma function of x.
#include <math.h>
double log1p(double x);
float log1pf(float x);
@ -1410,14 +1441,6 @@ long double tanhl(long double x);
These functions are equivalent to the existing un-suffixed versions, apart from their argument and return types. In ORCA/C, most of them actually behave identically to the un-suffixed versions. An exception is the modf family of functions, which differ in the type of the location in which the integer part of the value is stored.
Similarly, there are float and long double analogs of the string conversion function strtod:
#include <stdlib.h>
float strtof(const char * restrict str, char ** restrict ptr);
long double strtold(const char * restrict str, char ** restrict ptr);
As currently implemented in ORCA/C, strtof and strtold behave identically to strtod, all giving values with the precision and range of long double.
20. Several <time.h> functions can now use the Time Tool Set by Geoff Weiss to determine the time zone. This behavior is controlled by a new variable:
#include <time.h>
@ -1448,6 +1471,18 @@ The only time base supported by ORCA/C is TIME_UTC. This gives the time in seco
Although struct timespec can represent a time with nanosecond resolution, ORCA/C currently only reports the time with a resolution of one second, so ts->tv_nsec is always set to 0.
22. (C99) The strtod function can now accept strings in a hexadecimal floating-point format, in addition to the normal decimal format. The hexadecimal format consists of an optional leading + or - sign, then 0X or 0x, then a sequence of hexadecimal digits optionally containing a period, then an optional exponent part consisting of a P or p character followed by a decimal number optionally preceded by + or -. A string in this format designates the number given by the sign (if present) and the hexadecimal digit sequence (with any digits after the period being the fractional part) multiplied by 2 raised to the specified exponent (if it is present). For example, "0xF.8p-1" designates the number 7.75.
The strtod function also accepts the string "INFINITY" (without regard to case, and optionally preceded by + or -) to designate an infinity. This is equivalent to the string "INF", which was already accepted in earlier versions of ORCA/C.
Also, there are now float and long double analogs of the strtod function:
#include <stdlib.h>
float strtof(const char * restrict str, char ** restrict ptr);
long double strtold(const char * restrict str, char ** restrict ptr);
As currently implemented in ORCA/C, strtof and strtold behave identically to strtod, all giving values with the precision and range of long double.
-- Compiler changes introduced in C 2.1.0 -----------------------------------
The Default .h File
@ -1549,6 +1584,50 @@ Turning this optimization on means ORCA/C is no longer strictly in compliance wi
If you use #pragma debug 0x0010 to enable stack check debug code, the compiler will still flag variable argument functions that do not consume all arguments as a run-time error, even though ANSI C does allow them.
-- Bugs from C 2.2.0 that have been fixed in C 2.2.1 ------------------------
1. If there was a #define directive immediately after the opening brace of a function body, and the macro defined there was used after the end of that function or was used in the initializer for a static variable, incorrect code might be generated or spurious errors might be reported.
(Kelvin Sherlock)
2. In <gsbug.h>, the declarations of the pseudo tool calls provided by GSBug did not include prototypes. Now they do.
(Kelvin Sherlock)
3. In <gsos.h>, the error code devListFull was misspelled as defListFull.
4. Code that divides an integer constant by zero (e.g. 1/0) will no longer always produce an error. Such code will produce undefined behavior if it is executed, but since the compiler cannot always determine whether the code will be executed at run time, this is no longer treated as an error that prevents compilation. If #pragma lint bit 5 is set, a lint message about the division by zero will still be produced. An error will also still be reported for division by zero in constant expressions that need to be evaluated at compile time.
5. In some obscure circumstances, ORCA/C might behave incorrectly when the postfix ++ or -- operators were used on an expression of pointer type. This would typically result in "compiler error" messages, but could potentially also cause incorrect code to be generated without any errors being reported.
6. If the first string passed to strcat() or strncat() crossed a bank boundary, those functions would generally behave incorrectly and corrupt memory.
7. In certain situations where the third argument to strncat() was 0x8000 or greater, it could behave incorrectly.
8. If strncmp() was called with a third argument of 0x1000000 or greater, it could sometimes incorrectly return 0. (Note that such size values exceed the address space of the 65816, so under ORCA/C they effectively impose no limit on the number of characters to be compared. The behavior of strncmp() should therefore be the same as strcmp() in these cases.)
9. If an error was encountered when trying to write out buffered data in fclose(), the stream would not actually be closed, and the buffer allocated for it would not be freed. Now the stream will be closed (disassociated from the file) and the buffer will be freed even if an error is encountered.
10. If an error was encountered when trying to write out buffered data to a file when exiting the program, it could hang and never actually quit.
11. If fclose() was called on a file created by tmpfile() at a time when there was very little free memory available, it could corrupt memory and cause a crash. (This will no longer happen, but the file still may not be deleted if there is insufficient memory available when fclose() is called.)
12. If a numeric token formed using a ## preprocessor operator was an operand for another ## preprocessor operator, the resulting token would be incorrect.
13. If an empty argument was passed for a macro parameter that was used as an operand of the ## preprocessing operator, the result would likely be incorrect, and subsequent uses of the same macro also might not be expanded correctly.
14. If a struct, union, or enum type name appeared within the third expression in a for loop statement (e.g. in a cast or as the argument to sizeof), ORCA/C could behave incorrectly. It could report a spurious error if a semicolon occurred within the type name as part of a structure or union member declaration. Also, any tags or enumeration constants declared by such a type name should be in scope within the loop body, but they were not.
15. Native code peephole optimization might produce invalid code in some obscure circumstances where one element of a global or static array was decremented and then another element of the same array was accessed immediately thereafter.
16. When an expression of const- or volatile-qualified struct or union type was passed as a function parameter, incorrect code would be generated. This could lead to incorrect program behavior or crashes.
17. Incorrect code could be generated in certain circumstances where a long long or unsigned long long member of a structure or array was accessed via a pointer.
18. The ORCA/C preprocessor now allows for preprocessing number tokens that do not match the syntax of an integer or floating constant (e.g. 08Ae-.x). If any such tokens remain after preprocessing, an error will still be reported. Note that this means that code like 0x3e+1 is now treated as a single token that is invalid if it remains after preprocessing, rather than as three tokens that form a valid expression; if you want it to be interpreted as three tokens, you must include whitespace before the +.
19. When numeric tokens beginning with . were used as operands to the ## preprocessing operator, they behaved as if they started with a leading 0, which could lead to an incorrect result (e.g. 123##.456 became 1230.456).
-- Bugs from C 2.1.1 B3 that have been fixed in C 2.2.0 ---------------------
1. There were various bugs that could cause incorrect code to be generated in certain cases. Some of these were specific to certain optimization passes, alone or in combination.
@ -2162,6 +2241,64 @@ int foo(int[42]);
241. When using the large memory model, functions registered with atexit() (or at_quick_exit(), in ORCA/C 2.2 betas) might be called with the data bank set incorrectly, potentially causing memory corruption or other incorrect behavior.
(Bug fixes below here were added in the final release of ORCA/C 2.2.0.)
242. In the fprintf() family of functions, the '0' flag should be ignored if '-' was also specified.
243. In the fprintf() family of functions, when a conversion specification like "%#.0o" is used with the value 0, it should print "0" (rather than nothing).
244. Calls to malloc(), calloc(), or realloc() with a requested allocation size of 2 GB or greater could sometimes return a non-null pointer. Such calls should always fail and return NULL, since the IIGS does not have that much memory.
245. Programs using #pragma rtl would not return the proper value if run from the shell. (This did not affect the usual use of #pragma rtl for a PIF or TIF.)
246. The difftime() function would return incorrect values if the two times were at least 2^31 seconds (about 68 years) apart.
247. Floating-point conversions in the scanf() family of functions should scan to a long double if the L modifier is used, but this did not work properly.
(Kelvin Sherlock)
248. If the low-order 16 bits of the size passed realloc() were 0x0001, it would fail to deallocate the memory at the old address. This might cause the system to run out of memory.
249. In certain obscure circumstances, realloc() might access soft switches or slot I/O locations, which could cause strange behavior or crashes.
250. When using the E conversion specifier in the fprintf() family of functions, INF or NAN values might not be printed correctly. The output for them could have incorrect padding and/or extraneous characters at the end.
251. When a conversion specification like %#.0E or %#.0e is used in the fprintf() family of functions, the printed number should include a decimal point.
252. When using the g or G conversion specifiers in the fprintf() family of functions, slightly incorrect limits were used for determining whether to print the value in a decimal or exponential format.
253. When using the g or G conversion specifiers in the fprintf() family of functions, too many or too few digits might be printed in some circumstances, or a trailing decimal point might be printed when it should not be.
(Devin Reade)
254. The strtod() function should be able to skip over line feed, form feed, carriage return, and vertical tab characters (as well as space and horizontal tab) as part of the whitespace that may precede the number.
255. The strtod() function should return 0 if the string is empty or is not in the expected format.
(Dave Tribby)
256. In the fscanf() family of functions, floating-point conversions like %f could match certain character sequences that were not in the proper format, e.g. because they contained no digits.
257. In the fscanf() family of functions, an input failure caused by encountering EOF should cause any subsequent directives to be skipped and not executed, even if they are directives like %n that require no input.
258. If scanf() was called with a format string that was empty or contained only %n directives, it might pause awaiting a line of input from the console. It should not do this, because it should not try to read any characters for such calls.
259. If an error was encountered when processing a floating-point conversion directive with assignment suppressed, the scanf() family of functions might not return the correct value.
260. When using the g or G conversion specifiers in the fprintf() family of functions, the number zero could sometimes be printed in an exponential format like "0e+00". It should be printed in a non-exponential format like "0".
261. Several <math.h> functions could set errno inappropriately, based on a previous floating-point math operation rather than the current operation.
262. If a domain or range error had occurred in any previous floating-point operation, sinh() and cosh() calls might return the wrong values.
(William K. Watts, Jr.)
263. The sqrt() function would set errno to ERANGE if its argument was negative. This is a domain error, so it should set errno to EDOM in this case.
(William K. Watts, Jr.)
264. The fmod() function could return the wrong value when the second argument was negative.
-- Bugs from C 2.1.0 that have been fixed -----------------------------------
1. In some situations, fread() reread the first 1K or so of the file.

View File

@ -1,20 +1,61 @@
filetype = src
change =.rez rez
change =.pas pascal
change =.Comments pascal
change =.Debug pascal
change =.Print pascal
change =.asm asm65816
change =.macros asm65816
change make= exec
change linkit= linker
change smake exec
change count exec
change backup exec
change settypes exec
filetype =.notes txt
filetype =.md txt
filetype -p =.rez= src; change -p =.rez= rez
filetype -p =.pas src; change -p =.pas pascal
filetype CGI.Comments src; change CGI.Comments pascal
filetype CGI.Debug src; change -p CGI.Debug pascal
filetype Scanner.debug src; change -p Scanner.debug pascal
filetype Symbol.Print src; change Symbol.Print pascal
filetype -p =.asm src; change -p =.asm asm65816
filetype -p =.macros src; change -p =.macros asm65816
filetype -p make= src; change -p make= exec
filetype -p linkit= src; change -p linkit= linker
filetype smake src; change smake exec
filetype count src; change count exec
filetype backup src; change backup exec
filetype settypes src; change settypes exec
filetype cc.notes txt
filetype -p =.md txt
filetype LICENSE txt
filetype C.Read.Me txt
filetype C.Update.ReadMe txt
filetype Tech.Support txt
filetype Manual.docx $00
filetype obj:README.txt txt
filetype -p ORCACDefs:=.h src; change -p ORCACDefs:=.h cc
filetype -p C.Samples:Benchmarks:=.cc src; change -p C.Samples:Benchmarks:=.cc cc
filetype -p C.Samples:CDA.Samples:=.cc src; change -p C.Samples:CDA.Samples:=.cc cc
filetype -p C.Samples:CDev.Samples:=.cc src; change -p C.Samples:CDev.Samples:=.cc cc
filetype -p C.Samples:CDev.Samples:=.rez src; change -p C.Samples:CDev.Samples:=.rez rez
filetype -p C.Samples:CDev.Samples:=.make src; change -p C.Samples:CDev.Samples:=.make exec
filetype -p C.Samples:Desktop.Samples:=.cc src; change -p C.Samples:Desktop.Samples:=.cc cc
filetype -p C.Samples:Graphic.Samples:=.cc src; change -p C.Samples:Graphic.Samples:=.cc cc
filetype -p C.Samples:HyperCard:=.cc src; change -p C.Samples:HyperCard:=.cc cc
filetype -p C.Samples:HyperCard:=.rez src; change -p C.Samples:HyperCard:=.rez rez
filetype -p C.Samples:HyperCard:=.make src; change -p C.Samples:HyperCard:=.make exec
filetype -p C.Samples:HyperStudio:=.cc src; change -p C.Samples:HyperStudio:=.cc cc
filetype -p C.Samples:HyperStudio:=.rez src; change -p C.Samples:HyperStudio:=.rez rez
filetype -p C.Samples:HyperStudio:=.make src; change -p C.Samples:HyperStudio:=.make exec
filetype -p C.Samples:Text.Samples:=.cc src; change -p C.Samples:Text.Samples:=.cc cc
filetype -p C.Samples:Text.Samples:=.h src; change -p C.Samples:Text.Samples:=.h cc
filetype C.Samples:Text.Samples:Key2.Funcs src; change C.Samples:Text.Samples:Key2.Funcs cc
filetype -p C.Samples:Text.Samples:=.asm src; change -p C.Samples:Text.Samples:=.asm asm65816
filetype -p C.Samples:Text.Samples:=.Build src; change -p C.Samples:Text.Samples:=.Build exec
filetype -p Tests:Conformance:=.c src; change -p Tests:Conformance:=.c cc
filetype -p Tests:Conformance:=.CC src; change -p Tests:Conformance:=.CC cc
filetype -p Tests:Conformance:DOIT= src; change -p Tests:Conformance:DOIT= exec
filetype -p Tests:Conformance:TEST= src; change -p Tests:Conformance:TEST= exec
filetype -p Tests:Deviance:=.CC src; change -p Tests:Deviance:=.CC cc
filetype Tests:Deviance:D3401.DATA src; change Tests:Deviance:D3401.DATA cc
filetype Tests:Deviance:DOIT src; change Tests:Deviance:DOIT exec
filetype Tests:Deviance:RUN.DEVIANCE src; change Tests:Deviance:RUN.DEVIANCE exec
filetype -p Tests:Deviance:TEST= src; change -p Tests:Deviance:TEST= exec
filetype -p Tests:Spec.Conform:=.CC src; change -p Tests:Spec.Conform:=.CC cc
filetype -p Tests:Spec.Conform:=.H src; change -p Tests:Spec.Conform:=.H cc
filetype -p Tests:Spec.Conform:SPC3402= src; change -p Tests:Spec.Conform:SPC3402= cc
filetype -p Tests:Spec.Conform:=FILE= src; change -p Tests:Spec.Conform:=FILE= cc
filetype -p Tests:Spec.Conform:=.EXEC src; change -p Tests:Spec.Conform:=.EXEC exec
filetype -p Tests:Spec.Deviance:=.CC src; change -p Tests:Spec.Deviance:=.CC cc
filetype Tests:Spec.Deviance:DOIT src; change Tests:Spec.Deviance:DOIT exec
filetype Tests:Spec.Deviance:TEST src; change Tests:Spec.Deviance:TEST exec
* Install udl and uncomment this to also convert to CR line endings.
* udl -g =