ORCA-C/CCommon.pas
Stephen Heumann 99e268e3b9 Implement support for anonymous structures and unions (C11).
Note that this implementation allows anonymous structures and unions to participate in initialization. That is, you can have a braced initializer list corresponding to an anonymous structure or union. Also, anonymous structures within unions follow the initialization rules for structures (and vice versa).

I think the better interpretation of the standard text is that anonymous structures and unions cannot participate in initialization as such, and instead their members are treated as members of the containing structure or union for purposes of initialization. However, all other compilers I am aware of allow anonymous structures and unions to participate in initialization, so I have implemented it that way too.
2022-10-16 18:44:19 -05:00

1032 lines
40 KiB
ObjectPascal

{$optimize 7}
{---------------------------------------------------------------}
{ }
{ CCommon }
{ }
{ Common declarations and global data for the compiler. }
{ }
{ Variables: }
{ }
{ bofPtr - pointer to the start of sourceFile }
{ chPtr - pointer to the next character in the file }
{ codegenStarted - have we started the code generator? }
{ debugType - line number debug types }
{ doingFunction - true if processing a function }
{ doingParameters - are we processing parm definitions? }
{ doingPartial - are we doing a partial compile? }
{ enterEditor - enter editor on terminal errors? }
{ expandMacros - should macros be expanded? }
{ firstPtr - points to first char in current line }
{ gotoList - list of goto labels }
{ includeFile - include file name (for return from includes) }
{ infoString - language specific command line info }
{ lastLine - last line number used by pc_nam }
{ liDCB - get/set LInfo DCB }
{ lineNumber - source line number }
{ lint - lint flags }
{ list - generate source listing? }
{ memoryCompile - memory based compile? }
{ nameFound - has a pc_nam been generated? }
{ numErrors - number of errors in the program }
{ objFile - object file name }
{ oldincludeFile - previous includeFile value }
{ partialFile - partial compile list }
{ sourceFile - source file name }
{ terminalErrors - are all errors terminal? }
{ traceBack - generate traceback code? }
{ useGlobalPool - use global (or local) string pool? }
{ wait - wait for keypress after errors? }
{ }
{ doDispose - dispose of the expression tree as we go? }
{ expressionValue - the expression evaluator returns the }
{ value of constant expressions in this variable }
{ expressionType - the type of the expression }
{ expressionTree - for non-constant initializers }
{ isConstant - is the initializer expression constant? }
{ typeSpec - type given by the last declaration specifiers, }
{ specifier-qualifier list, or type name evaluated }
{ }
{ External Subroutines: }
{ }
{ CheckGotoList - Make sure all labels have been defined }
{ ClearHourGlass - Erase the hourglass from the screen }
{ CopyLongString - copy a long string }
{ CopyString - copy a string }
{ DrawHourGlass - Draw the hourglass on the screen }
{ ExitToEditor - do an error exit to the editor }
{ GetLocalLabel - get the next local label number }
{ Hash - find hash displacement }
{ InitCCommon - Initialize this module }
{ ReadFile - read a file }
{ Spin - Spin the spinner }
{ StopSpin - Stop the spinner }
{ SystemError - intercept run time compiler errors }
{ TermError - flag a terminal error }
{ }
{---------------------------------------------------------------}
unit CCommon;
interface
{$segment 'CC'}
const
{hashsize appears in CCOMMON.ASM}
hashSize = 876; {# hash buckets - 1}
hashSize2 = 1753; {# hash buckets * 2 - 1}
maxLine = 255; {max length of a line}
maxPath = 255; {max length of a path name}
{NOTE: maxPath is used in Scanner.asm}
longstringlen = 32760; {max length of a string constant}
minChar = 0; {min ordinal value of source character}
maxChar = 255; {max ordinal value of source character}
{lint masks}
{----------}
lintUndefFn = $0001; {flag use of undefined functions}
lintNoFnType = $0002; {flag functions with no type}
lintNotPrototyped = $0004; {flag functions with no prototypes}
lintPragmas = $0008; {flag unknown pragmas}
lintPrintf = $0010; {check printf/scanf format flags}
lintOverflow = $0020; {check for overflows}
lintC99Syntax = $0040; {check for syntax that C99 disallows}
lintReturn = $0080; {flag issues with how functions return}
{bit masks for GetLInfo flags}
{----------------------------}
flag_d = $10000000; {generate debug code?}
flag_e = $08000000; {abort to editor on terminal error?}
flag_f = $04000000; {print filenames in error messages?}
flag_i = $00800000; {ignore symbol files?}
flag_l = $00100000; {list source lines?}
flag_m = $00080000; {memory based compile?}
flag_o = $00020000; {optimize?}
flag_p = $00010000; {print progress info?}
flag_r = $00004000; {rebuild symbol files?}
flag_s = $00002000; {list symbol tables?}
flag_t = $00001000; {treat all errors as terminal?}
flag_w = $00000200; {wait when an error is found?}
versionStr = '2.2.0 B7 dev'; {compiler version}
type
{Misc.}
{-----}
long = record lsw,msw: integer; end; {for extracting words from longints}
longlong = record lo,hi: longint; end; {64-bit integer representation}
cString = packed array [1..256] of char; {null terminated string}
cStringPtr = ^cString;
longString = record {long null terminated string}
length: integer;
str: packed array [1..longstringlen] of char;
end;
longStringPtr = ^longString;
pString = packed array [0..maxLine] of char; {length string}
stringPtr = ^pString;
ptr = ^byte; {general purpose pointer}
handle = ^ptr; {general purpose handle}
gsosInString = record
size: integer;
theString: packed array [1..maxPath] of char;
end;
gsosInStringPtr = ^gsosInString;
{GS/OS class 1 output string}
gsosOutString = record
maxSize: integer;
theString: gsosInString;
end;
gsosOutStringPtr = ^gsosOutString;
{ The base types include two main categories. The values starting }
{ with cg are defined in the code generator, and may be passed to the }
{ code generator for resolution. The cc types are used internally in }
{ the compiler. Any values whose type is cc must be resolved to one }
{ of the cg types before the code generator is called. }
baseTypeEnum = (cgByte,cgUByte,cgWord,cgUWord,cgLong,cgULong,
cgReal,cgDouble,cgComp,cgExtended,cgString,
cgVoid,cgQuad,cgUQuad,ccPointer);
{ Basic types (plus the void type) as defined by the C language. }
{ This differs from baseTypeEnum in that different types with the }
{ same representation are distinguished from each other. }
{ (ctInt32/ctUInt32 are 32-bit int types when using #pragma unix 1.) }
cTypeEnum = (ctChar, ctSChar, ctUChar, ctShort, ctUShort, ctInt, ctUInt,
ctLong, ctULong, ctFloat, ctDouble, ctLongDouble, ctComp,
ctVoid, ctInt32, ctUInt32, ctBool, ctLongLong, ctULongLong);
{tokens}
{------}
{Note: tokenEnum is duplicated in }
{ Table.asm }
tokenEnum = ( {enumeration of the tokens}
ident, {identifiers}
{constants}
{Note: compconst and charconst, etc. }
{ are not found in program code. }
{ They are created only by casts. }
intconst,uintconst,longconst,ulongconst,longlongconst,
ulonglongconst,floatconst,doubleconst,extendedconst,compconst,
charconst,scharconst,ucharconst,ushortconst,stringconst,
{reserved words}
_Alignassy,_Alignofsy,_Atomicsy,_Boolsy,_Complexsy,
_Genericsy,_Imaginarysy,_Noreturnsy,_Static_assertsy,_Thread_localsy,
autosy,asmsy,breaksy,casesy,charsy,
continuesy,constsy,compsy,defaultsy,dosy,
doublesy,elsesy,enumsy,externsy,extendedsy,
floatsy,forsy,gotosy,ifsy,intsy,
inlinesy,longsy,pascalsy,registersy,restrictsy,
returnsy,shortsy,sizeofsy,staticsy,structsy,
switchsy,segmentsy,signedsy,typedefsy,unionsy,
unsignedsy,voidsy,volatilesy,whilesy,
{reserved symbols}
excch,percentch,carotch,andch,asteriskch,
minusch,plusch,eqch,tildech,barch,
dotch,ltch,gtch,slashch,questionch,
lparench,rparench,lbrackch,rbrackch,lbracech,
rbracech,commach,semicolonch,colonch,poundch,
minusgtop,plusplusop,minusminusop,ltltop,gtgtop,
lteqop,gteqop,eqeqop,exceqop,andandop,
barbarop,pluseqop,minuseqop,asteriskeqop,slasheqop,
percenteqop,ltlteqop,gtgteqop,andeqop,caroteqop,
bareqop,poundpoundop,dotdotdotsy,
eolsy,eofsy, {control characters}
typedef, {user types}
uminus,uand,uasterisk, {converted operations}
parameteroper,castoper,opplusplus,opminusminus,compoundliteral,
macroParm); {macro language}
{Note: this enumeration also }
{ appears in TABLE.ASM, }
{ SCANNER.asm }
charEnum = {character kinds}
(illegal,ch_special,ch_dash,ch_plus,ch_lt,ch_gt,ch_eq,ch_exc,
ch_and,ch_bar,ch_dot,ch_white,ch_eol,ch_eof,ch_char,ch_string,
ch_asterisk,ch_slash,ch_percent,ch_carot,ch_pound,ch_colon,
ch_backslash,letter,digit);
{prefixes of a character/string literal}
charStrPrefixEnum = (prefix_none,prefix_L,prefix_u16,prefix_U32,prefix_u8);
tokenSet = set of tokenEnum;
tokenClass = (reservedWord,reservedSymbol,identifier,intConstant,longConstant,
longlongConstant,realConstant,stringConstant,macroParameter);
identPtr = ^identRecord; {^ to a symbol table entry}
tokenType = record {a token}
kind: tokenEnum; {kind of token}
numString: stringPtr; {chars in number (macros only)}
case class: tokenClass of {token info}
reservedWord : ();
reservedSymbol: (isDigraph: boolean);
identifier : (name: stringPtr;
symbolPtr: identPtr);
intConstant : (ival: integer);
longConstant : (lval: longint);
longlongConstant: (qval: longlong);
realConstant : (rval: extended);
stringConstant: (sval: longstringPtr;
ispstring: boolean;
prefix: charStrPrefixEnum);
macroParameter: (pnum: integer);
end;
{expressions}
{-----------}
expressionKind = ( {kinds of expressions}
preprocessorExpression, {used by preprocessor commands}
arrayExpression, {array subscripts, case labels,
bit-field lengths, enum values}
initializerExpression, {static variable initializers}
autoInitializerExpression, {auto variable initializers}
normalExpression); {for run-time evaluation}
typePtr = ^typeRecord;
tokenPtr = ^tokenRecord;
tokenRecord = record {for operation, operand stacks}
next: tokenPtr; {next token on the stack}
left,middle,right: tokenPtr; {operand paths for operations}
token: tokenType; {token at this node/leaf}
case boolean of
true : (id: identPtr;); {^symbol table entry for this operand}
false: (castType: typePtr;); {cast type (for type casts only)}
end;
{goto label list}
{---------------}
gotoPtr = ^gotoRecord;
gotoRecord = record
{Note: if the size changes, see gotoSize}
next: gotoPtr;
name: stringPtr;
lab: integer;
defined: boolean;
end;
{symbol tables}
{-------------}
{classes of variables in the sym. tbl}
spaceType = (tagSpace,variableSpace,allSpaces,fieldListSpace);
parameterPtr = ^parameterRecord; {prototype parameter list}
parameterRecord = record
next: parameterPtr;
parameter: identPtr;
parameterType: typePtr;
end;
typeQualifierEnum = (tqConst, tqVolatile, tqRestrict);
typeQualifierSet = set of typeQualifierEnum;
typeKind = (scalarType,arrayType,pointerType,functionType,enumType,
enumConst,structType,unionType,definedType);
typeRecord = record {type}
size: longint; {size of the type in bytes}
qualifiers: typeQualifierSet; {type qualifiers}
saveDisp: longint; {disp in symbol file}
case kind: typeKind of {NOTE: aType,pType and fType must overlap}
scalarType : (baseType: baseTypeEnum; {our internal type representation}
cType: cTypeEnum); {type in the C type system}
arrayType : (aType: typePtr;
elements: longint;
);
pointerType : (pType: typePtr;);
functionType: (fType: typePtr; {return type}
varargs, {are there a variable # of args?}
prototyped: boolean; {is it prototyped?}
overrideKR: boolean; {K&R overrides to prototypes?}
parameterList: parameterPtr; {prototyped parameter list}
isPascal: boolean; {pascal parameters?}
toolNum: integer; {non-zero for tool functions}
dispatcher: longint; {dispatch addr}
);
enumConst : (eval: integer;);
enumType : ();
definedType : (dType: typePtr;);
structType,
unionType : (fieldList: identPtr; {field list}
sName: stringPtr; {struct name; for forward refs}
constMember: boolean; {does it have a const member?}
flexibleArrayMember: boolean; {does it have a FAM?}
);
end;
initializerPtr = ^initializerRecord; {initializers}
initializerRecord = record
next: initializerPtr; {next record in the chain}
count: integer; {# of duplicate records}
bitdisp: integer; {disp in byte (field lists only)}
bitsize: integer; {width in bits; 0 for byte sizes}
isStructOrUnion: boolean; {is this a struct or union initializer?}
case isConstant: boolean of {is this a constant initializer?}
false: (iTree: tokenPtr);
true : ( {Note: qVal.lo must overlap iVal}
case itype: baseTypeEnum of
cgByte,
cgUByte,
cgWord,
cgUWord,
cgLong,
cgULong : (iVal: longint);
cgQuad,
cgUQuad : (qVal: longlong);
cgString : (sVal: longstringPtr);
cgReal,
cgDouble,
cgComp,
cgExtended: (rVal: extended);
cgVoid,
ccPointer: (
pVal: longint;
pPlus: boolean;
case isName: boolean of
true : (pName: stringPtr);
false: (pStr : longstringPtr);
);
);
end;
storageType = (stackFrame,parameter,external,global,none,private);
stateKind = (declared,defined,initialized);
identRecord = record {identifier}
next: identPtr; {next symbol in this hash bucket}
saved: boolean; {has the symbol been saved (hashed) in the symbol file?}
name: stringPtr; {symbol name}
itype: typePtr; {symbol type}
disp: longint; {disp past start of struct (field lists only)}
bitDisp: integer; {disp in byte (field lists only)}
{parameter number (K&R parms only)}
bitsize: integer; {width in bits; 0 for byte sizes}
state: stateKind; {state of the definition}
iPtr: initializerPtr; {pointer to the first initializer}
isForwardDeclared: boolean; {does this var use a forward declared type?}
class: tokenEnum; {storage class}
case storage: storageType of
stackFrame: (lln: integer; {local label #}
clnext: identPtr); {next compound literal}
parameter: (pln: integer; {paramater label #}
pdisp: integer; {disp of parameter}
pnext: identPtr); {next parameter}
external: ();
global,private: ();
none: (anonMemberField: boolean); {field from an anonymous struct/union member?}
end;
{mini-assembler}
{--------------}
{opcodes}
opcode = (o_adc,o_and,o_asl,o_bit,o_cmp,o_cop,o_cpx,o_cpy,o_dec,o_eor,
o_inc,o_jml,o_jmp,o_jsl,o_jsr,o_lda,o_ldx,o_ldy,o_lsr,o_ora,
o_pea,o_pei,o_rep,o_rol,o_ror,o_sbc,o_sep,o_sta,o_stx,o_sty,
o_stz,o_trb,o_tsb,
o_dcb,o_dcw,o_dcl,
o_brk,o_wdm,
o_mvn,o_mvp,
o_bcc,o_bcs,o_beq,o_bmi,o_bne,o_bpl,o_bra,o_brl,o_per,o_bvc,
o_bvs,
o_clc,o_cld,o_cli,o_clv,o_dex,o_dey,o_inx,o_iny,o_nop,o_pha,
o_phb,o_phd,o_phk,o_php,o_phx,o_phy,o_pla,o_plb,o_pld,o_plp,
o_plx,o_ply,o_rti,o_rtl,o_rts,o_sec,o_sed,o_sei,o_stp,o_tax,
o_tay,o_tcd,o_tcs,o_tdc,o_tsc,o_tsx,o_txa,o_txs,o_txy,o_tya,
o_tyx,o_wai,o_xba,o_xce);
{addressing modes}
operands = (acc,imm,dp,dp_x,dp_y,op,op_x,op_y,i_dp_x,i_dp_y,dp_s,li_dp,la,
i_dp,i_op,i_la,i_op_x,i_dp_s_y,li_dp_y,long_x);
{work variables}
{--------------}
tempPtr = ^tempRecord;
tempRecord = record
last,next: tempPtr; {doubly linked list}
labelNum: integer; {label number}
size: integer; {size of the variable}
end;
{ORCA Shell and ProDOS}
{---------------------}
timeField = array[1..8] of byte;
optionListRecord = record
totalSize: integer;
requiredSize: integer;
fileSysID: integer;
theData: packed array [1..100] of char;
end;
optionListPtr = ^optionListRecord;
fastFileDCBGS = record
pcount: integer;
action: integer;
index: integer;
flags: integer;
fileHandle: handle;
pathName: gsosInStringPtr;
access: integer;
fileType: integer;
auxType: longint;
storageType: integer;
createDate: timeField;
modDate: timeField;
option: optionListPtr;
fileLength: longint;
blocksUsed: longint;
end;
getLInfoDCBGS = record
pcount: integer;
sFile: gsosOutStringPtr;
dFile: gsosOutStringPtr;
namesList: gsosOutStringPtr;
iString: gsosOutStringPtr;
merr: byte;
merrf: byte;
lops: byte;
kFlag: byte;
mFlags: longint;
pFlags: longint;
org: longint;
end;
getPrefixOSDCB = record
pcount: integer;
prefixNum: integer;
prefix: gsosOutStringPtr;
end;
versionDCBGS = record
pcount: integer;
version: packed array[1..4] of char;
end;
{---------------------------------------------------------------}
var
{misc}
{----}
bofPtr: ptr; {pointer to the start of sourceFile}
chPtr: ptr; {pointer to the next character in the file}
changedSourceFile: boolean; {source file changed in function?}
debugSourceFileGS: gsosOutString; {debug source file name}
{debugType is also in SCANNER.ASM}
debugType: (stop,break,autogo); {line number debug types}
doingParameters: boolean; {are we processing parm definitions?}
expandMacros: boolean; {should macros be expanded?}
ffDCBGS: fastFileDCBGS; {fast file DCB}
firstPtr: ptr; {points to first char in current line}
gotoList: gotoPtr; {list of goto labels}
includeFileGS: gsosOutString; {include file name (for return from includes)}
infoStringGS: gsosOutString; {language specific command line info}
intLabel: integer; {last used label number}
languageNumber: integer; {our language number}
lastLine: 0..maxint; {last line number used by pc_nam}
liDCBGS: getLInfoDCBGS; {get/set LInfo DCB}
lineNumber: 0..maxint; {source line number}
nameFound: boolean; {has a pc_nam been generated?}
nextLocalLabel: integer; {next available local data label number}
numErrors: integer; {number of errors in the program}
objFile: gsosOutString; {object file name}
oldincludeFileGS: gsosOutString; {previous includeFile value}
outFileGS: gsosOutString; {keep file name}
partialFileGS: gsosOutString; {partial compile list}
pragmaKeepFile: gsosOutStringPtr; {filename specified in #pragma keep}
sourceFileGS: gsosOutString; {presumed source file name}
tempList: tempPtr; {list of temp work variables}
longlong0: longlong; {the value 0 as a longlong}
longlong1: longlong; {the value 1 as a longlong}
{expression results}
{------------------}
doDispose: boolean; {dispose of the expression tree as we go?}
realExpressionValue: extended; {value of the last real constant expression}
llExpressionValue: longlong; {value of the last long long constant expression}
expressionValue: longint; {value of the last constant expression}
expressionType: typePtr; {the type of the expression}
initializerTree: tokenPtr; {for non-constant initializers}
isConstant: boolean; {is the initializer expression constant?}
expressionIsLongLong: boolean; {is the last constant expression long long?}
{flags}
{-----}
codegenStarted: boolean; {have we started the code generator?}
doingFunction: boolean; {are we processing a function?}
doingPartial: boolean; {are we doing a partial compile?}
enterEditor: boolean; {enter editor on terminal errors?}
filenamesInErrors: boolean; {print filenames in error messages?}
foundFunction: boolean; {has a function been found?}
lint: integer; {lint flags}
list: boolean; {generate source listing?}
ignoreSymbols: boolean; {ignore .sym file?}
memoryCompile: boolean; {memory based compile?}
printSymbols: boolean; {+s flag set?}
progress: boolean; {write progress info?}
rebuildSymbols: boolean; {rebuild .sym file?}
switchLanguages: boolean; {switch languages on exit?}
terminalErrors: boolean; {are all errors terminal?}
traceBack: boolean; {generate traceback code?}
unix_1: boolean; {is int 32 bits? (or 16 bits)}
useGlobalPool: boolean; {use global (or local) string pool?}
wait: boolean; {wait for keypress after errors?}
lintIsError: boolean; {treat lint messages as errors?}
fIsNoreturn: boolean; {is the current function _Noreturn?}
doingMain: boolean; {are we processing the main function?}
fenvAccess: boolean; {is the FENV_ACCESS pragma on?}
fenvAccessInFunction: boolean; {was FENV_ACCESS on anywhere in current function?}
{syntactic classes of tokens}
{---------------------------}
specifierQualifierListElement: tokenSet;
topLevelDeclarationStart: tokenSet;
{---------------------------------------------------------------}
{ORCA Shell and ProDOS}
{---------------------}
procedure GetLInfoGS (var parms: getLInfoDCBGS); prodos ($0141);
procedure FastFileGS (var parms: fastFileDCBGS); prodos ($014E);
procedure SetLInfoGS (var parms: getLInfoDCBGS); prodos ($0142);
procedure GetPrefixGS (var parms: getPrefixOSDCB); prodos ($200A);
procedure VersionGS (var parms: versionDCBGS); prodos ($0147);
{---------------------------------------------------------------}
procedure CheckGotoList;
{ Make sure all labels have been defined }
procedure ClearHourGlass;
{ Erase the hourglass from the screen }
procedure CopyLongString (toPtr, fromPtr: longStringptr);
{ copy a long string }
{ }
{ parameters: }
{ toPtr - location to copy to }
{ fromPtr - location to copy from }
procedure CopyString (toPtr, fromPtr: ptr); extern;
{ copy a string }
{ }
{ parameters: }
{ toPtr - location to copy to }
{ fromPtr - location to copy from }
procedure DrawHourGlass;
{ Draw the hourglass on the screen }
procedure ExitToEditor (msg: stringPtr; disp: longint);
{ do an error exit to the editor }
{ }
{ parameters: }
{ msg - pointer to the error message }
{ disp - displacement into the error file }
{ }
{ variables: }
{ includeFile - source file name }
function GenLabel: integer;
{ generate the next local label, checking for too many }
function GetLocalLabel: integer;
{ get the next local label number }
function Hash (sPtr: stringPtr): integer; extern;
{ find hash displacement }
{ }
{ Finds the displacement into an array of pointers using a }
{ hash function. }
{ }
{ parameters: }
{ sPtr - points to string to find hash for }
procedure InitCCommon;
{ Initialize this module }
procedure ReadFile;
{ read a file }
{ }
{ variables: }
{ bofPtr - pointer to the start of the file }
{ ffDCB.file_length - length of the file }
{ includeFile - source file name }
procedure Spin;
{ Spin the spinner }
{ }
{ Notes: Starts the spinner if it is not already in use }
procedure StopSpin;
{ Stop the spinner }
{ }
{ Notes: The call is safe, and ignored, if the spinner is }
procedure SystemError (errNo: integer);
{ intercept run time compiler errors }
procedure TermError (errnum: integer);
{ flag a terminal error }
{---------------------------------------------------------------}
implementation
const
{Note: maxLabel is also defined in cgi.pas}
{Note: maxlabel is also defined in CGC.asm}
maxLabel = 3275; {max # compiler generated labels}
{spinner}
{-------}
spinSpeed = 8; {calls before one spinner move}
type
consoleOutDCBGS = record
pcount: integer;
ch: char;
end;
var
{spinner}
{-------}
spinning: boolean; {are we spinning now?}
spinDisp: integer; {disp to the spinner character}
spinCount: integer; {spin loop counter}
spinner: array[0..3] of char; {spinner characters}
procedure Error (err: integer); extern; {in scanner.pas}
{ flag an error }
{ }
{ err - error number }
{procedure Error2 (loc, err: integer); extern; {debug} {in scanner.pas}
{ flag an error }
{ }
{ loc - error location }
{ err - error number }
procedure MMQuit; extern; {in mm.pas}
{ Dispose of memory allocated with private user IDs }
procedure ConsoleOutGS (var parms: consoleOutDCBGS); prodos ($015A);
{---------------------------------------------------------------}
procedure CheckGotoList;
{ Make sure all labels have been defined }
var
gt: gotoPtr; {work pointer}
msg: stringPtr; {work string}
begin {CheckGotoList}
gt := gotoList;
while gt <> nil do begin
if not gt^.defined then begin
numErrors := numErrors+1;
new(msg);
msg^ := concat('Undefined label: ', gt^.name^);
writeln(msg^);
if terminalErrors then begin
if enterEditor then
ExitToEditor(msg, ord4(firstPtr)-ord4(bofPtr))
else
TermError(0);
end; {if}
dispose(msg);
end; {if}
gt := gt^.next;
end; {while}
end; {CheckGotoList}
procedure ClearHourGlass;
{ Erase the hourglass from the screen }
var
coRec: consoleOutDCBGS; {Console out record}
begin {ClearHourGlass}
coRec.pcount := 1;
coRec.ch := ' '; ConsoleOutGS(coRec);
coRec.ch := chr(8); ConsoleOutGS(coRec);
end; {ClearHourGlass}
procedure CopyLongString {toPtr, fromPtr: longStringPtr};
{ copy a long string }
{ }
{ parameters: }
{ toPtr - location to copy to }
{ fromPtr - location to copy from }
var
i: integer; {loop variable}
begin {CopyLongString}
toPtr^.length := fromPtr^.length; {set the length}
for i := 1 to fromPtr^.length do
toPtr^.str[i] := fromPtr^.str[i];
end; {CopyLongString}
procedure DrawHourGlass;
{ Draw the hourglass on the screen }
var
coRec: consoleOutDCBGS; {Console out record}
begin {DrawHourGlass}
coRec.pcount := 1;
coRec.ch := chr(27); ConsoleOutGS(coRec);
coRec.ch := chr(15); ConsoleOutGS(coRec);
coRec.ch := 'C'; ConsoleOutGS(coRec);
coRec.ch := chr(24); ConsoleOutGS(coRec);
coRec.ch := chr(14); ConsoleOutGS(coRec);
coRec.ch := chr(8); ConsoleOutGS(coRec);
end; {DrawHourGlass}
procedure ExitToEditor {msg: stringPtr; disp: longint};
{ do an error exit to the editor }
{ }
{ parameters: }
{ msg - pointer to the error message }
{ disp - displacement into the error file }
{ }
{ variables: }
{ includeFile - source file name }
var
msgGS: gsosInString; {message}
begin {ExitToEditor}
msgGS.size := length(msg^); {set up the error message}
msgGS.theString := msg^;
liDCBGS.org := disp; {mark the error}
liDCBGS.namesList := @msgGS;
liDCBGS.lops := 0; {prevent re-entry}
liDCBGS.merrf := 255;
with liDCBGS do begin
sFile := pointer(ord4(sFile)+2);
dFile := pointer(ord4(dFile)+2);
iString := pointer(ord4(iString)+2);
end; {with}
SetLInfoGS(liDCBGS);
StopSpin; {stop the spinner}
MMQuit; {dispose of the memory pools}
halt(-1); {return to the shell}
end; {ExitToEditor}
function GenLabel{: integer};
{ generate the next local label, checking for too many }
begin {GenLabel}
if intLabel < maxLabel then
intLabel := intLabel+1
else begin
intLabel := 0;
Error(58);
end;
GenLabel := intLabel;
end; {GenLabel}
function GetLocalLabel{: integer};
{ get the next local label number }
begin {GetLocalLabel}
GetLocalLabel := nextLocalLabel;
nextLocalLabel := nextLocalLabel+1;
end; {GetLocalLabel}
procedure InitCCommon;
{ Initialize this module }
begin {InitCCommon}
spinning := false; {not spinning the spinner}
spinDisp := 0; {start spinning with the first character}
spinner[0] := '|'; {set up the spinner characters}
spinner[1] := '/';
spinner[2] := '-';
spinner[3] := '\';
longlong0.hi := 0;
longlong0.lo := 0;
longlong1.hi := 0;
longlong1.lo := 1;
end; {InitCCommon}
procedure ReadFile;
{ read a file }
{ }
{ variables: }
{ bofPtr - pointer to the start of the file }
{ ffDCB.file_length - length of the file }
{ includeFile - source file name }
const
SRC = $B0; {source file type}
begin {ReadFile}
with ffDCBGS do begin {read the source file}
pCount := 14;
action := 0;
flags := $C000;
pathName := @includeFileGS.theString;
end; {with}
FastFileGS(ffDCBGS);
if ToolError <> 0 then begin
sourceFileGS := includeFileGS;
includeFileGS := oldincludeFileGS;
TermError(1);
end; {if}
if ffDCBGS.fileType <> SRC then begin
includeFileGS := oldincludeFileGS;
TermError(6);
end; {if}
bofPtr := ffDCBGS.fileHandle^; {set beginning of file pointer}
end; {ReadFile}
procedure Spin;
{ Spin the spinner }
{ }
{ Notes: Starts the spinner if it is not already in use }
var
coRec: consoleOutDCBGS; {Console out record}
begin {Spin}
if not spinning then begin
spinning := true;
spinCount := spinSpeed;
end; {if}
spinCount := spinCount - 1;
if spinCount = 0 then begin
spinCount := spinSpeed;
spinDisp := spinDisp - 1;
if spinDisp < 0 then
spinDisp := 3;
coRec.pcount := 1;
coRec.ch := spinner[spinDisp];
ConsoleOutGS(coRec);
coRec.ch := chr(8);
ConsoleOutGS(coRec);
end; {if}
end; {Spin}
procedure StopSpin;
{ Stop the spinner }
{ }
{ Notes: The call is safe, and ignored, if the spinner is }
{ inactive. }
var
coRec: consoleOutDCBGS; {Console out record}
begin {StopSpin}
if spinning then begin
spinning := false;
coRec.pcount := 1;
coRec.ch := ' ';
ConsoleOutGS(coRec);
coRec.ch := chr(8);
ConsoleOutGS(coRec);
end; {if}
end; {StopSpin}
procedure SystemError {errNo: integer};
{ intercept run time compiler errors }
begin {SystemError}
if errNo = 5 then
TermError(5)
else
TermError(3);
end; {SystemError}
procedure TermError {errnum: integer};
{ flag a terminal error }
var
msg: pString; {terminal error message}
begin {TermError}
case errnum of {print the error}
0 : msg := '' ;
1 : msg := concat('Error reading ', sourceFileGS.theString.theString);
2 : msg := concat('Error purging ', sourceFileGS.theString.theString);
3 : msg := 'terminal compiler error';
4 : msg := 'user termination';
5 : msg := 'out of memory';
6 : msg := 'source files must have a file type of SRC';
7 : msg := 'you cannot change languages with an include directive';
8 : msg := 'you cannot change languages from an included file';
9 : msg := concat('Error writing ', objFile.theString.theString);
10: msg := 'ORCA/C requires version 2.0 or later of the shell';
11: msg := 'The program is too large to compile to memory -- use Compile to Disk';
12: msg := 'Invalid sym file detected. Re-run ORCA/C to proceed.';
13: msg := 'file name or command-line parameter is too long';
otherwise: begin
msg := '';
Error(57);
end;
end; {case}
with ffDCBGS do begin {purge the source file}
pCount := 5;
action := 7;
pathName := @includeFileGS.theString;
end; {with}
FastFileGS(ffDCBGS);
writeln('Terminal error: ', msg); {write the error to stdout}
if enterEditor then {error exit to editor}
ExitToEditor(@msg, ord4(chPtr) - ord4(bofPtr))
else begin
liDCBGS.lops := 0; {prevent re-entry}
liDCBGS.merrf := 127;
with liDCBGS do begin
sFile := pointer(ord4(sFile)+2);
dFile := pointer(ord4(dFile)+2);
namesList := pointer(ord4(namesList)+2);
iString := pointer(ord4(iString)+2);
end; {with}
SetLInfoGS(liDCBGS);
StopSpin; {stop the spinner}
MMQuit; {dispose of the memory pools}
halt(-1); {return to the shell}
end; {else}
end; {TermError}
end.
{$append 'ccommon.asm'}