/* compile.c * Written by B. Cameron Lesiuk, 1995 * Written for use with Crimson2 MUD (written/copyright Ryan Haksi 1995). * This source is proprietary. Use of this code without permission from * Ryan Haksi or Cam Lesiuk is strictly prohibited. * * (wi961@freenet.victoria.bc.ca) */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "crimson2.h" #include "macro.h" #include "log.h" #include "mem.h" #include "str.h" #include "ini.h" #include "send.h" #include "extra.h" #include "thing.h" #include "index.h" #include "code.h" #include "codestuf.h" #include "interp.h" #include "function.h" #include "compile.h" /** Define Statments **/ /* compile-time options */ /* Compile defaults */ #define CSTACK_SIZE (1<<12) /* size of stack */ #define CSTACK_FRAME (CSTACK_SIZE>>1) /* # stack frames */ #define CCODE_SIZE (1<<12) /* size of compiled code buffer */ /* These statements are the return codes for CompileReadNext (CRN) */ #define CRN_EOF 0x01 #define CRN_OPERATOR 0x02 #define CRN_COMMENT 0x03 #define CRN_COMMA 0x04 #define CRN_PERIOD 0x05 #define CRN_OSBRAC 0x06 /* [ bracket set (Square bracket) */ #define CRN_CSBRAC 0x07 #define CRN_OBRAC 0x08 /* { brace set (bracket) */ #define CRN_CBRAC 0x09 #define CRN_ORBRAC 0x0A /* ( parenthesis set (Round bracket) */ #define CRN_CRBRAC 0x0B #define CRN_STRING 0x0C /* string */ #define CRN_SEMI 0x0D /* semicolon */ #define CRN_NUMBER 0x0E /* numerical constant */ #define CRN_LABEL 0x0F /* Label - this is further divided, but not in CRN */ /* CRN_LABEL is interpreted into the following: */ #define CRN_RESWRD 0x10 /* reserved word (if, while, int) */ #define CRN_FUNCT 0x11 /* function */ #define CRN_VAR 0x12 /* variable */ #define CRN_UNDEF 0x13 /* undefined label */ /* Compile uses these flags in cValidMask to determine which ops are valid */ /* NOTE: the value must correspond to the CRN return codes defined above */ #define CV_EOF (1<<CRN_EOF) #define CV_OPERATOR (1<<CRN_OPERATOR) #define CV_COMMENT (1<<CRN_COMMENT) #define CV_COMMA (1<<CRN_COMMA) #define CV_PERIOD (1<<CRN_PERIOD) #define CV_OSBRAC (1<<CRN_OSBRAC) #define CV_CSBRAC (1<<CRN_CSBRAC) #define CV_OBRAC (1<<CRN_OBRAC) #define CV_CBRAC (1<<CRN_CBRAC) #define CV_ORBRAC (1<<CRN_ORBRAC) #define CV_CRBRAC (1<<CRN_CRBRAC) #define CV_STRING (1<<CRN_STRING) #define CV_SEMI (1<<CRN_SEMI) #define CV_NUMBER (1<<CRN_NUMBER) #define CV_LABEL (1<<CRN_LABEL) #define CV_RESWRD (1<<CRN_RESWRD) #define CV_FUNCT (1<<CRN_FUNCT) #define CV_VAR (1<<CRN_VAR) #define CV_UNDEF (1<<CRN_UNDEF) /* return codes for CompileReadNext */ #define CRN_RC_OK 0 #define CRN_RC_EOF 1 #define CRN_RC_SYNTAX 2 /* Compile State machine- major state codes */ #define CS_END 0xFFFFF000 /* end of program (looking for EOF) */ #define CS_START 0x00000100 /* start of program (looking for { ) */ #define CS_MAIN 0x00010000 /* Main State Machine Loop */ #define CS_VAR 0x00018000 /* Variable declarations */ #define CS_IF 0x00020000 /* Reserved word "if" expr handler */ #define CS_WHILE 0x00030000 /* Reserved word "while" expr handler */ #define CS_STOP 0x00040000 /* Reserved word "stop" expr handler */ #define CS_GET_EXP 0x00050000 /* Get Expression state machine loop */ #define CS_FUNCTION 0x00060000 /* handles function calls etc. */ #define CS_GET_NEXT 0x00070000 /* gets next Var or Function */ /* Compile state machine - expression type flag values * Confused? Here, let me explain: * In the following example: * a=b+c; * `a' is an lvalue. lvalues must be variables. `1=b+c' is invalid!!! * `b+c' is an rvalue. rvalues can be variables, functions, constants, etc. * `a=b+c' is an expression. It can also be used as an rvalue. * * In the following example: * function(a,b+c); * `a' is a rvalue. Functions must be passed rvalues. Don't worry though, * just about everything can be used as an rvalue. * `b+c' is also an rvalue. * `function' is a function call. It's also an rvalue. * * Got it? */ #define CEFLAG_EXP 1<<0 /* expression */ #define CEFLAG_RVALUE 1<<1 /* rvalue */ #define CEFLAG_LVALUE 1<<2 /* lvalue */ #define CEFLAG_FUNCT 1<<3 /* function */ /* Compile state machine - data type flag values */ #define CDFLAG_UNDEF (1<<CDT_UNDEF) #define CDFLAG_NULL (1<<CDT_NULL) #define CDFLAG_STR (1<<CDT_STR) #define CDFLAG_INT (1<<CDT_INT) #define CDFLAG_THING (1<<CDT_THING) #define CDFLAG_EXTRA (1<<CDT_EXTRA) #define CDFLAG_EXIT (1<<CDT_EXIT) /* Structures and unions */ typedef union CompileUnion { UWORD cuPointer; /* pointer to a variable, function, string, etc */ SBYTE cuSByte; /* signed byte */ WORD cuSWord; /* signed word */ LWORD cuSLWord; /* 32-bit signed data */ ULWORD cuUnsigned; /* 32-bit unsigned data */ ULWORD cuState; /* state for state machine */ ULWORD cuValid; /* valid flags for state machine */ UWORD cuFunction; /* function being called */ UWORD cuVar; /* variable being referenced */ BYTE cuParamType; /* parameter type for functions */ ULWORD cuVarFlag; /* Data Type flag */ ULWORD cuExpFlag; /* Expression Type Flag */ UWORD cuOffset; /* Offset - a saved location in program */ void *cuPtr; /* pointer data - used for things like COP_PUSHPT */ } COMPILEUNION; typedef struct CompileData { /* this type is used for the stack, for */ BYTE cInstruction; /* parameter passing, etc. etc. etc. */ COMPILEUNION cData; } COMPILEDATA; typedef struct CharMark { /* used by CompileReadNext */ BYTE *SCMstr; WORD SCMoperation; } CHARMARK; typedef struct CompileVarTableType { /* variable table */ BYTE cText[CVAR_NAME_LENGTH]; /* variable name */ WORD cType; /* variable type */ WORD cDomain; /* variable domain */ ULWORD cOffset; /* location in variable table specified by cDomain */ } COMPILEVARTABLETYPE; typedef struct CompileReservedWord { /* table entry for reserved words */ BYTE cText[10]; /* reserved word name */ } COMPILERESERVEDWORD; /* Globals - used everywhere in compile.c */ WORD cComp; /* pointer to where we are in the compiled code */ BYTE *cCompBuf;/* compile buffer */ LWORD cCompBufSizeByte; BYTE *cSrc; /* pointer to where we are in the soure (text) code */ BYTE *cSrcTop; /* pointer to top of soure (text) code */ BYTE *cLastSrc;/* pointer to the last place we were in the source code */ BYTE *cNextSrc;/* pointer to the next place in source code - if we know it. */ COMPILEDATA *cStack; /* stack used by all compile routines */ COMPILEDATA *cStackP; /* pointer to current stack - used to access stack */ LWORD cStackSizeByte; /* current stack size in bytes */ WORD cSP; /* current stack pointer */ WORD cSF; /* current stack frame */ WORD *cSFP; /* stack frame base position pointer*/ LWORD cSFPSizeByte; /* current stack frame size in bytes */ THING *cThing; /* thing to report stuff (like errors) to */ WORD cRc; /* return code - use everywhere */ UWORD cCurVar; /* current variable we're at in the variable table */ COMPILEVARTABLETYPE cVarTable[CMAX_VAR]; /* variable table */ LWORD cReqStackSize; /* size of required Interp.c stack required. */ LWORD cReqStackSizeMax; /* Max value of cReqStackSize */ LWORD cReqParameter; /* Max parameters required by Interp */ /* Macros - used everywhere in compile.c */ #define COMPILE_GETLASTSRC() \ do { \ if ((cRc=CompileGetLastSrc())) \ return (cRc); \ } while(0) #define COMPILE_ADDBYTE(byte) \ do { \ if ((cRc=CompileAddByte(byte))) \ return (cRc); \ } while(0) #define COMPILE_STRING(ptr) \ do { \ if ((cRc=CompileString(ptr))) \ return (cRc); \ } while(0) #define COMPILE_PUSH(ptr) \ do { \ if ((cRc=CompilePush(ptr))) \ return (cRc); \ } while(0) #define COMPILE_PULL(ptr) \ do { \ if ((cRc=CompilePull(ptr))) \ return (cRc); \ } while(0) #define COMPILE_UPSTACK() \ do { \ if ((cRc=CompileUpStack())) \ return (cRc); \ } while(0) #define COMPILE_DOWNSTACK() \ do { \ if ((cRc=CompileDownStack())) \ return (cRc); \ } while(0) #define COMPILE_COMPILE(ptr) \ do { \ if ((cRc=CompileCompile(ptr))) \ return (cRc); \ } while(0) #define COMPILE_COMPILESTACK() \ do { \ if ((cRc=CompileCompileStack())) \ return (cRc); \ } while(0) #define COMPILE_COMPILECOMMENT(ptr) \ do { \ if ((cRc=CompileComment(ptr))) \ return (cRc); \ } while(0) #define COMPILE_ADDPOINTER(ptr) \ do { \ if ((cRc=CompileAddPointer(ptr))) \ return (cRc); \ } while(0) /* This routine is called by the compiler if a warning occurs. This routine */ /* should pass the warning message etc. on to the appropriate place. */ void CompileWarningReport(BYTE *cError) { if (cThing) { SendThing("^a",cThing); SendThing(cError,cThing); } } /* This routine is called by the compiler if an error occurs. This routine */ /* should pass the error message etc. on to the appropriate place. */ void CompileErrorReport(BYTE *cError) { BYTE temp,temp2,buf[40]; BYTE *cP,*cSP,*cNP; /* pointer, start pointer, Next pointer */ ULWORD cLine; if (cThing) { /* First, count lines, and find "line before" error */ cLine=1; for (cP=cSP=cNP=cSrcTop;(*cP)&&(cP!=cSrc);cP++) { if ((*cP)=='\n') { cLine++; cSP=cNP; cNP=cP+1; } } /* Increment past error to "line after" error */ if (*cP) cP++; for (;(*cP)&&((*cP)!='\n');cP++); if (*cP) cP++; for (;(*cP)&&((*cP)!='\n');cP++); temp=*cSrc; temp2=*cP; *cSrc=*cP=0; sprintf(buf,"^wError at line %li:\n",cLine); SendThing(buf,cThing); SendThing("^a",cThing); SendThing(cSP,cThing); SendThing(" ^r<<*ERROR*\n^a",cThing); *cSrc=temp; SendThing(cSrc,cThing); SendThing("\n",cThing); *cP=temp2; SendThing("^w",cThing); SendThing(cError,cThing); SendThing("^a",cThing); } } /* This procedure sets cSrc to a new point and keeps track of cLastSrc */ void CompileSetSrc(BYTE *newpoint) { cLastSrc=cSrc; cSrc=newpoint; cNextSrc=NULL; } WORD CompileGetLastSrc() { /* retrieves last cSrc pointer */ if (cLastSrc==NULL) { /* If this happens, the state machine is screwed up. FIX IT! */ /* We are only allowed to go 'back' one step! */ CompileErrorReport("internal error (compile.c): cLastSrc is NULL. This should not happen.\nRecord this message and your program, and notify your Sys Admin.\n"); return(COMPILE_INTERNAL_ERROR); } else { cNextSrc=cSrc; cSrc=cLastSrc; cLastSrc=NULL; return(0); } } WORD CompileGetNextSrc() { /* oposite of CompileGetLastSrc */ if (cNextSrc==NULL) { /* If this happens, the state machine is screwed up. FIX IT! */ /* We are only allowed to go 'back' one step! */ CompileErrorReport("internal error (compile.c): cNextSrc is NULL. This should not happen.\nRecord this message and your program, and notify your Sys Admin.\n"); return(COMPILE_INTERNAL_ERROR); } else { cLastSrc=cSrc; cSrc=cNextSrc; cNextSrc=NULL; return(0); } } /** Stack Functions **/ WORD CompileInitStack() { cSP=0; /* zero'th stack position in the... */ cSF=0; /* zero'th stack frame, which starts at... */ cSFP[cSF]=0; /* zero'th position in the stack */ cStackP=&cStack[cSFP[cSF]]; /* set up pointer to this stack frame */ return(0); } WORD CompileUpStack() { /* go up one stack frame */ cSF++; REALLOC("WARNING! compile.c stack frame overflow... resizing\n", cSFP,WORD,(cSF+1),cSFPSizeByte); cSFP[cSF]=cSFP[cSF-1]+cSP; /* set new stack frame */ cSP=0; /* zero'th position in new stack frame */ cStackP=&cStack[cSFP[cSF]]; /* set up pointer to this stack frame */ return(0); } WORD CompileDownStack() { /* go down one stack frame */ BYTE error[300]; if (cSP) { /* send WARNING message, not error, that stack is non-empty. */ /* HOPEFULLY, if this code is modified correctly and runs */ /* smoothly, this condition will never happen. HOWEVER, the */ /* whole idea behind a stack frame is that each section of */ /* code gets its own stack, and can't screw up other peoples */ /* stacks. (peoples? well, I guess we could consider states */ /* of a state machine as people. :) */ if (cSP==1) { sprintf(error,"internal warning (compile.c): %i datum on stack lost with CompileDownStack().\nThis may cause your program to compile incorrectly. Notify your Sys Admin.\n",cSP); } else { sprintf(error,"internal warning (compile.c): %i data on stack lost with CompileDownStack().\nThis may cause your program to compile incorrectly. Notify your Sys Admin.\n",cSP); } CompileWarningReport(error); } if (cSF<=0) { CompileErrorReport("compile error: stack frame underflow\n"); return(COMPILE_INTERNAL_ERROR); } cSP=cSFP[cSF]-cSFP[cSF-1]; cSF--; cStackP=&cStack[cSFP[cSF]]; /* set up pointer to this stack frame */ return(0); } WORD CompilePush(COMPILEDATA *data) { REALLOC("WARNING! compile.c stack overflow... resizing\n", cStack,COMPILEDATA,(cSP+cSFP[cSF]+1),cStackSizeByte); /* if we've just REALLOC'ed, our cStackP pointer is no longer valid. * Instead of checking for a changed cStack, I'm just going to * ALWAYS re-load cStackP from cStack */ cStackP=&cStack[cSFP[cSF]]; /* set up pointer to this stack frame */ cStackP[cSP].cInstruction = data->cInstruction; /* copy instruction */ cStackP[cSP].cData.cuUnsigned=data->cData.cuUnsigned; /* copy data. ALL the data should be copied using the Unsigned */ cSP++; return(0); } WORD CompilePull(COMPILEDATA *data) { if (!cSP) { CompileErrorReport("compile error: stack underflow\n"); return(COMPILE_INTERNAL_ERROR); } cSP--; data->cInstruction=cStackP[cSP].cInstruction; data->cData.cuUnsigned=cStackP[cSP].cData.cuUnsigned; return(0); } /** Compile Functions **/ WORD CompileAddByte(BYTE data) { REALLOC("WARNING! compile.c buffer overflow... resizing\n", cCompBuf,BYTE,(cComp+1),cCompBufSizeByte); cCompBuf[cComp++]=data; return(0); } /* This procedure adds a pointer to the compiled code */ WORD CompileAddPointer(void *ptr) { ULWORD i; REALLOC("WARNING! compile.c buffer overflow... resizing\n", cCompBuf,BYTE,(cComp+CODE_PT_SIZE+1),cCompBufSizeByte); /* the following doesn't work on Solaris for some reason */ /* *((void**)(&(cCompBuf[cComp])))=(void *)ptr; */ /* alternate */ for (i=0;i<CODE_PT_SIZE;i++) cCompBuf[cComp+i]=((((unsigned long)(ptr))>>(8*i))&0x0FF); cComp+=CODE_PT_SIZE; return(0); } /* this compiles, as a comment, the string passed to it */ WORD CompileComment(BYTE *comment) { /* compiles a comment into code */ BYTE *pointer; if (BIT(codeSet,CODE_SAVECOMMENT)) { COMPILE_ADDBYTE(COP_COMMENT); pointer=comment; pointer--; do { pointer++; COMPILE_ADDBYTE(*pointer); } while(*pointer); } else { CompileWarningReport("compile warning: comments are turf'd.\n"); } return(0); } /* CompileComment */ /* this function appends a string onto the compiled program */ WORD CompileString(BYTE *string) { /* compiles a string into code */ BYTE *pointer; pointer=string; pointer--; do { pointer++; COMPILE_ADDBYTE(*pointer); } while(*pointer); return(0); } /* CompileString */ /* this fuction takes `data' and adds it on to the compiled program. */ WORD CompileCompile(COMPILEDATA *instruction) { LWORD temp; static LWORD cLastPush; /* optimize space useage by evaluating the generic COP_PUSHV and replacing */ /* it with PUSHV1 (1-byte), PUSHV2 (2-bytes), or PUSHV4 (4-bytes). */ if (instruction->cInstruction==COP_PUSHV) { temp=instruction->cData.cuSLWord; if ((-128<=temp)&&(temp<=127)) { instruction->cInstruction=COP_PUSHV1; instruction->cData.cuSByte=temp; } else if ((-32768<=temp)&&(temp<=32767)) { instruction->cInstruction=COP_PUSHV2; instruction->cData.cuSWord=temp; } else { instruction->cInstruction=COP_PUSHV4; instruction->cData.cuSLWord=temp; } } /* if instruction of variety PUSHV */ switch (instruction->cInstruction) { /* These operations decrement by 1 the stack pointer */ case COP_EQUSR: case COP_EQUSL: case COP_EQUOR: case COP_EQUXOR: case COP_EQUAND: case COP_EQUSUB: case COP_EQUADD: case COP_EQUMOD: case COP_EQUDIV: case COP_EQUMULT: case COP_EQU: case COP_BOR: case COP_BAND: case COP_OR: case COP_XOR: case COP_AND: case COP_BEQU: case COP_BNEQU: case COP_GEQ: case COP_GR: case COP_LEQ: case COP_LS: case COP_SR: case COP_SL: case COP_SUB: case COP_ADD: case COP_MOD: case COP_DIV: case COP_MULT: case COP_POP: cReqStackSize--; /* These operations don't affect the stack pointer */ case COP_BSUB: case COP_BADD: case COP_ASUB: case COP_AADD: case COP_COMP: case COP_NOT: case COP_NEG: case COP_TERM: COMPILE_ADDBYTE(instruction->cInstruction); break; /* These operations affect the stack in different ways */ case COP_EXEC: case COP_EXECR: cReqStackSize-=cLastPush; if (cLastPush>cReqParameter) /* get max # parameters required */ cReqParameter=cLastPush; COMPILE_ADDBYTE(instruction->cInstruction); COMPILE_ADDBYTE((instruction->cData.cuPointer&0x00ff)); COMPILE_ADDBYTE((instruction->cData.cuPointer&0xff00)>>8); break; case COP_PUSHL: case COP_PUSHG: case COP_PUSHP: cReqStackSize++; COMPILE_ADDBYTE(instruction->cInstruction); COMPILE_ADDBYTE((instruction->cData.cuPointer&0x00ff)); COMPILE_ADDBYTE((instruction->cData.cuPointer&0xff00)>>8); break; case COP_IFZ: case COP_WHILEZ: cReqStackSize--; case COP_GOTO: case COP_COMMENT: COMPILE_ADDBYTE(instruction->cInstruction); COMPILE_ADDBYTE((instruction->cData.cuPointer&0x00ff)); COMPILE_ADDBYTE((instruction->cData.cuPointer&0xff00)>>8); break; case COP_PUSHV1: cLastPush=(LWORD)(instruction->cData.cuSByte); cReqStackSize++; COMPILE_ADDBYTE(instruction->cInstruction); COMPILE_ADDBYTE(instruction->cData.cuSByte&0xff); break; case COP_PUSHV2: cLastPush=(LWORD)(instruction->cData.cuSWord); cReqStackSize++; COMPILE_ADDBYTE(instruction->cInstruction); COMPILE_ADDBYTE(instruction->cData.cuSWord&0x00ff); COMPILE_ADDBYTE((instruction->cData.cuSWord&0xff00)>>8); break; case COP_PUSHV: case COP_PUSHV4: cLastPush=(LWORD)(instruction->cData.cuSLWord); cReqStackSize++; COMPILE_ADDBYTE(instruction->cInstruction); COMPILE_ADDBYTE(instruction->cData.cuSLWord&0x000000ff); COMPILE_ADDBYTE((instruction->cData.cuSLWord&0x0000ff00)>>8); COMPILE_ADDBYTE((instruction->cData.cuSLWord&0x00ff0000)>>16); COMPILE_ADDBYTE((instruction->cData.cuSLWord&0xff000000)>>24); break; case COP_PUSHPT: cReqStackSize++; COMPILE_ADDBYTE(instruction->cInstruction); COMPILE_ADDPOINTER(instruction->cData.cuPtr); break; case COP_NULL: default: CompileWarningReport("internal warning (compile.c): compiler passed illegal instruction.\nThis may cause your program to compile incorrectly. Notify your Sys Admin.\n"); break; } if (cReqStackSize>cReqStackSizeMax) cReqStackSizeMax=cReqStackSize; return(0); } /* This pulls the top instruction off the stack and compiles it */ WORD CompileCompileStack() { COMPILEDATA instruction; COMPILE_PULL(&instruction); COMPILE_COMPILE(&instruction); return(0); } LWORD CompileStrToNum(BYTE *string) { /* converts string to LWORD */ BYTE *pointer; LWORD num; num=0; pointer=string; while(*pointer) { num=(num*10)+(*pointer-'0'); pointer++; } return(num); } /** Parser Functions **/ /* CompileReadNext () ** *c_label - returns: text of label, comment, string, whatever ** *c_operation - 1 WORD code as defined by the #define statements ** starting with CRN_ ** returns COMPILE_CRN_RC_OK if operation ok, errorcode otherwise: ** (*label=errorcode) ** CRN_RC_EOF - EOF reached unexpectedly ** CRN_RC_SYNTAX - syntactical error ** ** This procedure reads the next 'bit' of code which is of importance ** to the compiler. It doesn't read very far, and it's up to the compiler ** to keep track of what is valid and when. What I mean by the next 'bit' ** is this: ** ** if you fed this routine the following line, repeatedly, until EOLN, ** ** a = c * (d-e) /o hi mom o/ + some_funct(g,h)+strlen("hi there"); ** ^^ ^^ ** pretend these are real comment markers :) ** ** you would get: ** c_label c_operation ** a CRN_LABEL<<8 ** NULL CRN_OPERATOR<<8 + COP_EQU ** c CRN_LABEL<<8 ** NULL CRN_OPERATOR<<8 + COP_MULT ** NULL CRN_ORBRAC<<8 ** d CRN_LABEL<<8 ** NULL CRN_OPERATOR<<8 + COP_SUB ** e CRN_LABEL<<8 ** NULL CRN_CRBRAC<<8 ** hi mom CRN_COMMENT<<8 ** NULL CRN_OPERATOR<<8 + COP_ADD ** some_funct CRN_LABEL<<8 ** NULL CRN_ORBRAC<<8 ** g CRN_LABEL<<8 ** NULL CRN_COMMA<<8 ** h CRN_LABEL<<8 ** NULL CRN_CRBRAC<<8 ** NULL CRN_OPERATOR<<8 + COP_ADD ** strlen CRN_LABEL<<8 ** NULL CRN_ORBRAC<<8 ** hi there CRN_STRING<<8 ** NULL CRN_CRBRAC<<8 ** NULL CRN_SEMI<<8 ** NULL CRN_EOF<<8 (assuming this is the end of the file ) */ WORD CompileReadNext(BYTE *c_label, WORD *c_operation) { BYTE *p_label; /* pointers to these things. */ BYTE *pointer; WORD SCM_offset; static CHARMARK SCM[]= { /* make sure you put triple-char, then double, then single */ { ">>=",(CRN_OPERATOR<<8) + COP_EQUSR }, { "<<=",(CRN_OPERATOR<<8) + COP_EQUSL }, { "|=" ,(CRN_OPERATOR<<8) + COP_EQUOR }, { "^=" ,(CRN_OPERATOR<<8) + COP_EQUXOR }, { "&=" ,(CRN_OPERATOR<<8) + COP_EQUAND }, { "-=" ,(CRN_OPERATOR<<8) + COP_EQUSUB }, { "+=" ,(CRN_OPERATOR<<8) + COP_EQUADD }, { "%=" ,(CRN_OPERATOR<<8) + COP_EQUMOD }, { "/=" ,(CRN_OPERATOR<<8) + COP_EQUDIV }, { "*=" ,(CRN_OPERATOR<<8) + COP_EQUMULT }, { "&&" ,(CRN_OPERATOR<<8) + COP_BAND }, { "||" ,(CRN_OPERATOR<<8) + COP_BOR }, { "!=" ,(CRN_OPERATOR<<8) + COP_BNEQU }, { "==" ,(CRN_OPERATOR<<8) + COP_BEQU }, { "<=" ,(CRN_OPERATOR<<8) + COP_LEQ }, { ">=" ,(CRN_OPERATOR<<8) + COP_GEQ }, { "<<" ,(CRN_OPERATOR<<8) + COP_SL }, { ">>" ,(CRN_OPERATOR<<8) + COP_SR }, { "--" ,(CRN_OPERATOR<<8) + COP_ASUB }, { "++" ,(CRN_OPERATOR<<8) + COP_AADD }, { "`" ,(CRN_OPERATOR<<8) + COP_COMP }, { "<" ,(CRN_OPERATOR<<8) + COP_LS }, { ">" ,(CRN_OPERATOR<<8) + COP_GR }, { "!" ,(CRN_OPERATOR<<8) + COP_NOT }, { "=" ,(CRN_OPERATOR<<8) + COP_EQU }, { "+" ,(CRN_OPERATOR<<8) + COP_ADD }, { "-" ,(CRN_OPERATOR<<8) + COP_SUB }, { "*" ,(CRN_OPERATOR<<8) + COP_MULT }, { "/" ,(CRN_OPERATOR<<8) + COP_DIV }, { "%" ,(CRN_OPERATOR<<8) + COP_MOD }, { "&" ,(CRN_OPERATOR<<8) + COP_AND }, { "|" ,(CRN_OPERATOR<<8) + COP_OR }, { "\\" ,(CRN_OPERATOR<<8) + COP_XOR }, { "{" ,CRN_OBRAC<<8 }, /* grammar marks */ { "}" ,CRN_CBRAC<<8 }, { "(" ,CRN_ORBRAC<<8 }, { ")" ,CRN_CRBRAC<<8 }, { ";" ,CRN_SEMI<<8 }, { "," ,CRN_COMMA<<8 }, { "[" ,CRN_OSBRAC<<8 }, { "]" ,CRN_CSBRAC<<8 }, { NULL ,0 }, }; pointer=cSrc; /* start at beginning of program */ *c_label=0; /* null-out all our return codes */ *c_operation=0; /* first, lets find first non-space, non-LF, non-etc char*/ while(((*pointer == ' ')||(*pointer < 32))&&(*pointer !=0)) pointer++; if (*pointer == 0) /* check for EOF */ { *c_operation=CRN_EOF<<8; CompileSetSrc(pointer); return(CRN_RC_OK); } if ((*pointer == '/') && (*(pointer+1)=='/')) { /* we've a '/'/' comment! */ pointer=pointer+2; /* advance pointer to comment 'guts' */ *c_operation=CRN_COMMENT<<8; /* define as comment */ p_label=c_label; /* start our 'c_label' filling! */ while ((*pointer!='\n')&&(*pointer!='\r')&&(*pointer!=10)&& (*pointer!=0)) { *p_label=*pointer; /* fill up label with comment */ pointer++; /* advance pointer & p_label */ p_label++; } /* at this point, whatever we reached, it's 'end of comment' */ *p_label=0; /* mark as end of string */ CompileSetSrc(pointer); /* send back 'the rest */ return(CRN_RC_OK); } if ((*pointer == '/') && (*(pointer+1)=='*')) { /* we've a '/'*' comment! */ pointer=pointer+2; /* advance pointer to comment text */ *c_operation=CRN_COMMENT<<8; /* define as comment */ p_label=c_label; /* start our 'label' filling! */ while (((*pointer!='*')||(*(pointer+1)!='/'))&& (*pointer!=0)) { *p_label=*pointer; /* fill up label with comment */ pointer++; /* advance pointer & p_label */ p_label++; } /* at this point, if EOF, error! */ if (*pointer == 0) { sprintf(c_label,"'/*' comment missing matching '*/' before EOF"); CompileSetSrc(pointer); return(CRN_RC_EOF); } /* ok, we've found the end marker */ pointer=pointer+2; /* advance pointer to outside comment */ *p_label=0; /* mark as end of string */ CompileSetSrc(pointer); /* send back 'the rest */ return(CRN_RC_OK); } if (*pointer == '"') { /* check if this is a quoted string */ *c_operation=CRN_STRING<<8; /* define as string */ p_label=c_label; /* start our 'label' filling! */ pointer++; /* skip past open " */ while ((*pointer !='"')&&(*pointer != 0)) { /* copy text into label - quote string so anything goes */ if ((*pointer=='\\')&&(*(pointer+1)!=0)) { /* escape sequence */ pointer++; if (*pointer=='a') *p_label='\a'; else if (*pointer=='b') *p_label='\b'; else if (*pointer=='f') *p_label='\f'; else if (*pointer=='n') *p_label='\n'; else if (*pointer=='r') *p_label='\r'; else if (*pointer=='t') *p_label='\t'; else if (*pointer=='v') *p_label='\v'; else *p_label=*pointer; } else *p_label=*pointer; p_label++; pointer++; } if (*pointer==0) { /* an EOF? Error! */ sprintf(c_label,"Unexpected EOF! You are missing a final \" to your quote!"); CompileSetSrc(pointer); return(CRN_RC_EOF); } *p_label=0; /* terminate c_label */ pointer++; /* advance pointer past ending " */ CompileSetSrc(pointer); return(CRN_RC_OK); } if (*(pointer+1)!=0) {/* we don't want to go over - segmentation faults :) */ if ((*pointer=='\'')&&(*(pointer+2)=='\'')) { /* ' quoted number */ *c_operation=CRN_NUMBER<<8; /* define as number */ p_label=c_label; /* start our 'label' filling! */ pointer++; *(p_label++)=((*pointer)/100)+'0'; *(p_label++)=((*pointer)/10)-(((*pointer)/100)*10)+'0'; *(p_label++)=(*pointer)-(((*pointer)/10)*10)+'0'; *(p_label++)=0; /* terminate string */ pointer+=2; CompileSetSrc(pointer); return(CRN_RC_OK); } } /* now, the following while-loop is just to save code space and */ /* whip through all the cases where we would return after reading a */ /* simple char string. This is what the big structure def'n is for. */ SCM_offset=0; /* start at the beginning */ while (SCM[SCM_offset].SCMstr!=NULL) { if ((strlen(SCM[SCM_offset].SCMstr)==3)&& /* first give triple a crack */ (*pointer==SCM[SCM_offset].SCMstr[0])&& (*(pointer+1)==SCM[SCM_offset].SCMstr[1])&& (*(pointer+2)==SCM[SCM_offset].SCMstr[2])) { *c_operation=SCM[SCM_offset].SCMoperation; CompileSetSrc(pointer+3); strcpy(c_label,SCM[SCM_offset].SCMstr); return(CRN_RC_OK); } else if ((strlen(SCM[SCM_offset].SCMstr)==2)&& /* then doubles */ (*pointer==SCM[SCM_offset].SCMstr[0])&& (*(pointer+1)==SCM[SCM_offset].SCMstr[1])) { *c_operation=SCM[SCM_offset].SCMoperation; CompileSetSrc(pointer+2); strcpy(c_label,SCM[SCM_offset].SCMstr); return(CRN_RC_OK); } else if ((strlen(SCM[SCM_offset].SCMstr)==1)&& /* finally singles */ (*pointer==SCM[SCM_offset].SCMstr[0])) { *c_operation=SCM[SCM_offset].SCMoperation; CompileSetSrc(pointer+1); strcpy(c_label,SCM[SCM_offset].SCMstr); return(CRN_RC_OK); } SCM_offset++; } if ((*pointer>='0')&&(*pointer<='9')) { /* we've got a number */ *c_operation=CRN_NUMBER<<8; /* define as number */ p_label=c_label; /* initialize p_label to start of c_label */ while((*pointer>='0')&&(*pointer<='9')) { *p_label=*pointer; /* copy number into 'label' */ pointer++; /* advance pointers */ p_label++; } *p_label=0; /* terminate label */ CompileSetSrc(pointer); return(CRN_RC_OK); } if (((*pointer>='a')&&(*pointer<='z'))|| /* we're lowercase alpha */ ((*pointer>='A')&&(*pointer<='Z'))|| /* we're uppercase alpha */ (*pointer == '_')) { /* and of course, the underscore is valid */ /* ok, for us to have made it this far, we've got to be looking */ /* at an alphabetic label. Let's read it into c_label now. */ /* Start copying label, and boogey along until we hit a non-label*/ /* character (eg: 'int a' or 'a = 2;' ) or a '(' (eg: printf("hi");)*/ *c_operation=CRN_LABEL<<8; /* define as label */ p_label=c_label; /* initialize p_label to start of c_label */ while(((*pointer>='a')&&(*pointer<='z'))|| /* we're lowercase alpha */ ((*pointer>='A')&&(*pointer<='Z'))|| /* we're uppercase alpha */ ((*pointer>='0')&&(*pointer<='9'))|| /* numbers just can't be the first character in a label */ (*pointer == '_')) { /* and of course, the underscore is valid */ *p_label=*pointer; /* copy label into 'label' */ pointer++; /* advance pointer & p_label */ p_label++; } /* while */ *p_label=0; /* terminate label */ CompileSetSrc(pointer); return(CRN_RC_OK); } else { /* we've got an invalid/unrecognized character! */ sprintf(c_label,"I don't recognize this character: %c",*pointer); CompileSetSrc(pointer+1); return(CRN_RC_SYNTAX); } } /* CompileReadNext */ /* Compile * The guts of this whole thing. * * Compile is a great big huge gigantic enormous ugly disgusting state machine. * I hope you like it :) * * ccSrc = pointer to a STR containing source code to compile. * ccComp = pointer to a pointer to a STR (which will be created by Compile) * containing compiled binary code. NOTE: ccComp will contain, * upon return, a pointer to the STR. * ccThing = the THING to send informational messages to (eg compile errors). * */ WORD Compile(STR *ccSrc,STR **ccComp,THING *ccThing) { ULWORD cValid; /* mask as to what operation is currently valid */ ULWORD cState; /* current state for state machine */ BYTE cLabel[1000]; /* Label storage - use with CompileReadNext */ UWORD cOperation; /* operation - use with CompileReadNext */ UWORD cLastOperation; /* used to save last CompileReadNext operation */ BYTE cError[200]; /* for error messages */ BYTE cError2[200]; /* for error messages */ UWORD counter; /* used here and there as a local counter */ UWORD cReserved; /* offset to Reserved word in cResWord */ UWORD cFunction; /* offset to function in fTable */ UWORD cVar; /* offset to variable in cVarTable */ COMPILEDATA cTemp; /* data variable used for communicating with stacks etc. */ UWORD cCurLocal; /* current local variable we're at */ UWORD cTotalLocal,cTotalGlobal,cTotalPrivate; /* variable totals */ /* flags used by compile state machine */ ULWORD cVarFlag; /* variable type flag */ ULWORD cExpFlag; /* Expression Type flag */ ULWORD cNumParam; /* # parameters we've had in this function call */ *ccComp=NULL; /* if we return w/ an error, return NULL */ cComp=0; cSrc=cSrcTop=cLastSrc=ccSrc->sText; /* setup source code for global access */ cNextSrc=NULL; cThing=ccThing; /* set up Thing so that we have someplace to dump errors */ cNumParam=0; cReqStackSize=cReqStackSizeMax=0; /* reset our interp stack size */ cReqParameter=0; /* reset our interp parameter list size */ if ((cRc=CompileInitStack())) /* initialize (empty) stack */ return(cRc); /* set up start of code */ strcpy(cCompBuf,CODE_PROG_HEADER); cComp=CODE_PROG_HEADER_LENGTH; *cVarTable[cSystemVariable].cText=0; /* initialize (empty) variable table */ cVarTable[cSystemVariable].cType=CDT_NULL; cVarTable[cSystemVariable].cDomain=CDOMAIN_UNDEF; cVarTable[cSystemVariable].cOffset=0; cCurVar=cSystemVariable+1; cCurLocal=cSystemVariable+1; /* locals reside along side system vars. :) */ cState=CS_START; /* State 1 is the starting state. State 0 exits */ cValid=CV_COMMENT|CV_VAR|CV_CBRAC|CV_FUNCT|CV_RESWRD|CV_ORBRAC| CV_OPERATOR|CV_OBRAC|CV_EOF|CV_COMMENT|CV_SEMI; /** start of Compile state machine **/ while (1) { if (cNextSrc) { /* we've already parsed the next block - just skip ahead */ cRc=CompileGetNextSrc(); cOperation=cLastOperation; if (cRc) return(cRc); } else { cRc=CompileReadNext(cLabel,&cOperation); cLastOperation=cOperation; if (cRc != CRN_RC_OK) { /* check for error codes from CompileReadNext */ switch(cRc) { case CRN_RC_EOF: sprintf(cError,"parse error (EOF): %s\n",cLabel); break; case CRN_RC_SYNTAX: sprintf(cError,"parse error (SYNTAX): %s\n",cLabel); break; default: sprintf(cError,"parse error (unknown): %s\n",cLabel); break; } CompileErrorReport(cError); return(COMPILE_SYNTAX_ERROR); } } if (((cOperation&0xFF00)>>8)==CRN_LABEL) { /* chng label to fn,var,etc. */ /* first, check for reserved word */ counter=0; while((*cResWord[counter].cText!=0)&& (strcmp(cResWord[counter].cText,cLabel))) { counter++; } if (*cResWord[counter].cText!=0) { /* we've found it */ cOperation=(CRN_RESWRD<<8)+(cOperation&0x00FF); cReserved=counter; } else { /* not reserved, must be a function, variable, or undefined. */ /* first, check if it's a function */ counter=0; while((fTable[counter].fText!=NULL)&& /*NOTE: Function calls are all*/ (STRICMP(fTable[counter].fText,cLabel))) { /* NOT case dependent!!*/ counter++; } if (fTable[counter].fText !=NULL) { /* we've found it */ cOperation=(CRN_FUNCT<<8)+(cOperation&0x00FF); cFunction=counter; } else { /* not function, must be variable or undefined */ counter=0; while((counter<cCurVar)&& (strcmp(cVarTable[counter].cText,cLabel))) { counter++; } if (counter<cCurVar) { /* found it */ cOperation=(CRN_VAR<<8)+(cOperation&0x00FF); cVar=counter; } else { /* not variable, must be undefined */ cOperation=(CRN_UNDEF<<8)+(cOperation&0x00FF); } /* variable check */ } /* function check */ } /* reserved check */ } /* if (cOoperation==CRN_LABEL) */ cState=(cState&0xFFFFFF00)+((cOperation&0xFF00)>>8); if (BIT(codeSet,CODE_DEBUGCOMPILE)) { sprintf(cError,"^a 0x%08lX : %04X `%s'\n",cState,cOperation,cLabel); printf(cError); if (cThing) SendThing(cError,cThing); } /* Now, before we enter the state machine, we do a preliminary error */ /* check. This looks at what is valid at the current time. It allows */ /* the current state to filter out certain types of stuff, thus */ /* saving gobs of error checking in the state machine itself. It */ /* results in error codes not being quite so specific, but hey, too */ /* bad. If you want, you can code ALL the error codes, one by one, */ /* and someday have pretty error codes for every possible exception, */ /* but I hope you've got a computer with lots of memory! */ /* (well, I guess you do - if you've got that much time to kill, you */ /* must have money to spend on a big computer) */ if (!(cValid&(1<<((cOperation&0xFF00)>>8)))) { /* invalid at this time */ /* define type of error (borrow cLabel as temporary buffer) */ switch((cOperation&0xFF00)>>8) { case CRN_EOF: sprintf(cError2,"EOF"); break; case CRN_OPERATOR: sprintf(cError2,"operator"); break; case CRN_COMMENT: sprintf(cError2,"comment `%s'",cLabel); break; case CRN_COMMA: sprintf(cError2,"comma (,)"); break; case CRN_STRING: sprintf(cError2,"string constant \"%s\"",cLabel); break; case CRN_SEMI: sprintf(cError2,"semicolon (;)"); break; case CRN_NUMBER: sprintf(cError2,"use of constant `%s'",cLabel); break; case CRN_RESWRD: sprintf(cError2,"use of reserved word `%s'",cLabel); break; case CRN_VAR: sprintf(cError2,"reference to variable `%s'",cLabel); break; case CRN_FUNCT: sprintf(cError2,"call to function `%s'",cLabel); break; case CRN_UNDEF: sprintf(cError2,"undefined label `%s' ",cLabel); break; case CRN_OBRAC: sprintf(cError2,"brace `{'"); break; case CRN_CBRAC: sprintf(cError2,"brace `}'"); break; case CRN_OSBRAC: sprintf(cError2,"bracket `['"); break; case CRN_CSBRAC: sprintf(cError2,"bracket `]'"); break; case CRN_ORBRAC: sprintf(cError2,"parenthesis `('"); break; case CRN_CRBRAC: sprintf(cError2,"parenthesis `)'"); break; case CRN_LABEL: sprintf(cError2,"unrecognized label `%s'",cLabel); break; default: sprintf(cError2,"this operation"); break; } sprintf(cError,"compile error: %s is invalid here.\n",cError2); CompileErrorReport(cError); return(COMPILE_SYNTAX_ERROR); } /* ok, here it is - the state machine, in the form of a switch */ switch (cState) { /* EEEEEE NNN NN DDDDD * EE NNNN NN DD DD * EEEE NN NNNN DD DD * EE NN NNN DD DD * EEEEEE NN NN DDDDD */ /* CS_END: end of program */ case CS_END+CRN_EOF: /* end of program */ COMPILE_PULL(&cTemp); /* set `next block' for code section */ cCompBuf[cTemp.cData.cuPointer]=(BYTE)(cComp&0x00ff); cCompBuf[cTemp.cData.cuPointer+1]=(BYTE)((cComp&0xff00)>>8); /* The following WACK of code takes the variable table cVarTable, * and translates it into it's component `compiled' parts. It starts * by tallying the Local, Global, and Private vars. This way, we know * how many of each we're dealing with. Then, it does what is required * for each domain's variables. */ cTotalLocal=cTotalGlobal=cTotalPrivate=0; for(counter=cSystemVariable+1;counter<cCurVar;counter++) { if (cVarTable[counter].cDomain==CDOMAIN_LOCAL) { cTotalLocal++; } else if (cVarTable[counter].cDomain==CDOMAIN_GLOBAL) { cTotalGlobal++; } else if (cVarTable[counter].cDomain==CDOMAIN_PRIVATE) { cTotalPrivate++; } else { sprintf(cError,"compile error: unrecognized domain for `%s'. This shouldn't happen.\nRecord your program and this message, and contact your Sys Admin.\n",cVarTable[counter].cText); CompileErrorReport(cError); return(COMPILE_INTERNAL_ERROR); } } /* tally domain totals */ /* uncomment these two lines if you want a status line * like this: "Variables: 6 local, 1 global, 0 private" printed. */ /* sprintf(cError,"^aVariables: ^c%i ^alocal, ^c%i ^aglobal, ^c%i ^aprivate.\n", cTotalLocal,cTotalGlobal,cTotalPrivate); CompileWarningReport(cError);*/ /* Translate local variables into compiled code */ if (cTotalLocal) { COMPILE_ADDBYTE(CODE_BLK_VAR); /* create VAR block */ cTemp.cInstruction=COP_NULL; /* save location */ cTemp.cData.cuPointer=cComp; COMPILE_PUSH(&cTemp); COMPILE_ADDBYTE(0); /* 'next block' pointer (alloc space) */ COMPILE_ADDBYTE(0); /* 'next block' pointer (alloc space) */ for(counter=cSystemVariable+1;counter<cCurVar;counter++) { /* types */ if (cVarTable[counter].cDomain==CDOMAIN_LOCAL) { COMPILE_ADDBYTE(cVarTable[counter].cType); } } COMPILE_PULL(&cTemp); /* set `next block' for code section */ cCompBuf[cTemp.cData.cuPointer]=(BYTE)(cComp&0x00ff); cCompBuf[cTemp.cData.cuPointer+1]=(BYTE)((cComp&0xff00)>>8); COMPILE_ADDBYTE(CODE_BLK_VAR_NAME); /* create VAR_NAME blk */ cTemp.cInstruction=COP_NULL; /* save location */ cTemp.cData.cuPointer=cComp; COMPILE_PUSH(&cTemp); COMPILE_ADDBYTE(0); /* 'next block' pointer (alloc space) */ COMPILE_ADDBYTE(0); /* 'next block' pointer (alloc space) */ for(counter=cSystemVariable+1;counter<cCurVar;counter++) { /* types */ if (cVarTable[counter].cDomain==CDOMAIN_LOCAL) { COMPILE_STRING(cVarTable[counter].cText); } } COMPILE_PULL(&cTemp); /* set `next block' for code section */ cCompBuf[cTemp.cData.cuPointer]=(BYTE)(cComp&0x00ff); cCompBuf[cTemp.cData.cuPointer+1]=(BYTE)((cComp&0xff00)>>8); } if (cTotalGlobal) { CompileErrorReport("compile error: global variables unsupported.\n"); return(COMPILE_INTERNAL_ERROR); /******* CONVERT VARIABLE TABLE INTO GLOBAL*****/ /******* ADD GLOBAL VARIABLE SECTIONS TO CODE ******/ } if (cTotalPrivate) { CompileErrorReport("compile error: private variables unsupported.\n"); return(COMPILE_INTERNAL_ERROR); /******* CONVERT VARIABLE TABLE INTO PRIVATE*****/ /******* ADD PRIVATE VARIABLE SECTIONS TO CODE ******/ } COMPILE_ADDBYTE(CODE_BLK_NULL); *ccComp=StrCreate(cCompBuf, cComp-1, HASH); InterpStackAlloc(cReqStackSizeMax,cReqParameter,cTotalLocal); return(COMPILE_OK); break; /* SSSS TTTTTT AAAA RRRRR TTTTTT * SS TT AA AA RR RR TT * SSS TT AAAAAA RRRR TT * SS TT AA AA RR RR TT * SSSS TT AA AA RR RR TT */ /* CS_START: start of program */ case CS_START+CRN_SEMI: case CS_START+CRN_COMMENT: case CS_START+CRN_VAR: case CS_START+CRN_CBRAC: case CS_START+CRN_FUNCT: case CS_START+CRN_RESWRD: case CS_START+CRN_ORBRAC: case CS_START+CRN_OPERATOR: case CS_START+CRN_OBRAC: COMPILE_GETLASTSRC(); /* Whoah! backup! */ COMPILE_ADDBYTE(CODE_BLK_CODE); /* code block header */ cTemp.cInstruction=COP_NULL; cTemp.cData.cuOffset=cComp; COMPILE_PUSH(&cTemp); /* push marker for 'next blk' offset */ COMPILE_ADDBYTE(0); /* 'next block' pointer (alloc space) */ COMPILE_ADDBYTE(0); /* 'next block' pointer (alloc space) */ cTemp.cInstruction=COP_NULL; /* push cValid and cState for */ cTemp.cData.cuValid=CV_EOF|CV_COMMENT; /* when we find closing `}' */ COMPILE_PUSH(&cTemp); cTemp.cData.cuState=CS_END; COMPILE_PUSH(&cTemp); COMPILE_UPSTACK(); cState=CS_MAIN; /* goto normal handler */ cValid=CV_SEMI|CV_FUNCT|CV_VAR|CV_OPERATOR|CV_ORBRAC|CV_OBRAC| CV_RESWRD|CV_COMMENT; break; case CS_START+CRN_EOF: sprintf(cError,"compile error: nothing to compile\n"); CompileErrorReport(cError); return(COMPILE_SYNTAX_ERROR); break; /* VV VV AAAA RRRRR * VV VV AA AA RR RR * VV VV AAAAAA RRRR * VVV AA AA RR RR * V AA AA RR RR */ /* CS_VAR: allocate & specify variables */ case CS_VAR+CRN_RESWRD: /* domain reader */ if (cCurVar>=CMAX_VAR) { sprintf(cError,"compile error: variable table full. You've got too many variables!\n"); CompileErrorReport(cError); return(COMPILE_INTERNAL_ERROR); } if ((cReserved==CRES_INT)|| (cReserved==CRES_STR)|| (cReserved==CRES_EXIT)|| (cReserved==CRES_EXTRA)|| (cReserved==CRES_THING)) { cVarTable[cCurVar].cDomain=CDOMAIN_LOCAL; /* default to local */ cVarTable[cCurVar].cOffset=cCurLocal; cCurLocal++; COMPILE_GETLASTSRC(); /* backup so our `type' can be read */ } else if(cReserved==CRES_LOCAL) { cVarTable[cCurVar].cDomain=CDOMAIN_LOCAL; cVarTable[cCurVar].cOffset=cCurLocal; cCurLocal++; } else if(cReserved==CRES_GLOBAL) { cVarTable[cCurVar].cDomain=CDOMAIN_GLOBAL; cVarTable[cCurVar].cOffset=0; /*****CHANGE*****/ } else if(cReserved==CRES_PRIVATE) { cVarTable[cCurVar].cDomain=CDOMAIN_PRIVATE; cVarTable[cCurVar].cOffset=0; /*****CHANGE*****/ } else { sprintf(cError,"compile error: unrecognized variable domain `%s'. This should not happen.\nRecord your program and this message, and contact your Sys Admin.\n",cLabel); CompileErrorReport(cError); return(COMPILE_INTERNAL_ERROR); } cValid=CV_COMMENT|CV_RESWRD; cState=CS_VAR+0x100; break; case CS_VAR+0x100+CRN_RESWRD: /* type reader */ if (cReserved==CRES_INT) { cVarTable[cCurVar].cType=CDT_INT; } else if (cReserved==CRES_STR) { cVarTable[cCurVar].cType=CDT_STR; } else if (cReserved==CRES_THING) { cVarTable[cCurVar].cType=CDT_THING; } else if (cReserved==CRES_EXTRA) { cVarTable[cCurVar].cType=CDT_EXTRA; } else if (cReserved==CRES_EXIT) { cVarTable[cCurVar].cType=CDT_EXIT; } else { sprintf(cError,"compile error: unrecognized variable type `%s'. This should not happen.\nRecord your program and this message, and contact your Sys Admin.\n",cLabel); CompileErrorReport(cError); return(COMPILE_INTERNAL_ERROR); } cValid=CV_COMMENT|CV_UNDEF|CV_VAR; cState=CS_VAR+0x200; break; case CS_VAR+0x200+CRN_UNDEF: /* we know type,domain. Define the sucker */ if (strlen(cLabel)>CVAR_NAME_LENGTH) { sprintf(cError,"compile error: variable name `%s' exceeds length limit of %i chars.\n",cLabel,CVAR_NAME_LENGTH); CompileErrorReport(cError); return(COMPILE_SYNTAX_ERROR); } strcpy(cVarTable[cCurVar].cText,cLabel); cValid=CV_COMMENT|CV_COMMA|CV_SEMI; cState=CS_VAR+0x300; cCurVar++; break; case CS_VAR+0x200+CRN_VAR: sprintf(cError,"compile error: variable `%s' is already defined!\n",cLabel); CompileErrorReport(cError); return(COMPILE_SYNTAX_ERROR); break; case CS_VAR+0x300+CRN_COMMA: /* define another of the same */ if (cCurVar>=CMAX_VAR) { sprintf(cError,"compile error: variable table full. You've got too many variables!\n"); CompileErrorReport(cError); return(COMPILE_INTERNAL_ERROR); } cVarTable[cCurVar].cType=cVarTable[cCurVar-1].cType; cVarTable[cCurVar].cDomain=cVarTable[cCurVar-1].cDomain; if (cVarTable[cCurVar].cDomain==CDOMAIN_LOCAL) { cVarTable[cCurVar].cOffset=cCurLocal; cCurLocal++; } else if (cVarTable[cCurVar].cDomain==CDOMAIN_GLOBAL) { cVarTable[cCurVar].cOffset=0; /*****CHANGE*****/ /* ADD VARIABLE TO GLOBAL TABLE */ } else if (cVarTable[cCurVar].cDomain==CDOMAIN_PRIVATE) { cVarTable[cCurVar].cOffset=0; /*****CHANGE*****/ /* ADD VARIABLE TO PRIVATE TABLE */ } else { sprintf(cError,"compile error: unrecognized variable domain. This should not happen.\nRecord your program and this message, and contact your Sys Admin.\n"); CompileErrorReport(cError); return(COMPILE_INTERNAL_ERROR); } cValid=CV_COMMENT|CV_UNDEF|CV_VAR; cState=CS_VAR+0x200; /* go back and define another */ break; case CS_VAR+0x300+CRN_SEMI: COMPILE_DOWNSTACK(); COMPILE_PULL(&cTemp); /* return to calling state */ cState=cTemp.cData.cuState; COMPILE_PULL(&cTemp); cValid=cTemp.cData.cuValid; break; /* MMM MMM AAAA IIIIII NNN NN * MMMM MMMM AA AA II NNNN NN * MM MMMM MM AAAAAA II NN NN NN * MM MM MM AA AA II NN NNNN * MM MM AA AA IIIIII NN NNN */ /* CS_MAIN: main loop - process a 'statement'. */ case CS_MAIN+CRN_OBRAC: /* we've encountered a { - compound statement */ cTemp.cInstruction=COP_NULL; cTemp.cData.cuValid=CV_SEMI|CV_FUNCT|CV_VAR|CV_OPERATOR|CV_ORBRAC| CV_OBRAC|CV_RESWRD|CV_COMMENT|CV_CBRAC; COMPILE_PUSH(&cTemp); cTemp.cData.cuState=CS_MAIN+0x200; /* brace handler */ COMPILE_PUSH(&cTemp); COMPILE_UPSTACK(); cState=CS_MAIN; /* call statement handler */ cValid=CV_COMMENT|CV_VAR|CV_FUNCT|CV_RESWRD|CV_ORBRAC|CV_OPERATOR| CV_OBRAC|CV_SEMI|CV_CBRAC; /* NOTE: THIS IS THE ONLY PLACE ALLOWD TO CALL CS_MAIN WITH CV_CBRAC */ break; case CS_MAIN+CRN_CBRAC: /* closing char - empty { } */ /* THIS SHOULD ONLY HAPPEN IMMEDIATELY FOLLOWING CS_MAIN+CRN_OBRAC */ /* IN THE EVENT THAT THE CODER ENTERED " { } " */ COMPILE_DOWNSTACK(); COMPILE_PULL(&cTemp); COMPILE_PULL(&cTemp); COMPILE_DOWNSTACK(); COMPILE_PULL(&cTemp); /* return to calling state */ cState=cTemp.cData.cuState; COMPILE_PULL(&cTemp); cValid=cTemp.cData.cuValid; break; case CS_MAIN+CRN_SEMI: /* null statement */ COMPILE_DOWNSTACK(); COMPILE_PULL(&cTemp); /* return to calling state */ cState=cTemp.cData.cuState; COMPILE_PULL(&cTemp); cValid=cTemp.cData.cuValid; break; case CS_MAIN+CRN_FUNCT: /* expression statement */ case CS_MAIN+CRN_VAR: case CS_MAIN+CRN_OPERATOR: case CS_MAIN+CRN_ORBRAC: COMPILE_GETLASTSRC(); /* whoah! backup! */ cTemp.cInstruction=COP_NULL; cTemp.cData.cuValid=CV_SEMI|CV_COMMENT; COMPILE_PUSH(&cTemp); cTemp.cData.cuState=CS_MAIN+0x100; /* goto wrapup after this */ COMPILE_PUSH(&cTemp); cState=CS_GET_EXP; /* Ok: we're just throwing the whole line at */ /* CS_GET_EXP. It's going to return us cVarFlag*/ /* and cExpFlag. We then let our wrapup state */ /* compare what we get back to what we expected*/ /* (ie what we just put on the stack) and let */ /* it handle any errors. The CS_GET_EXP should */ /* be able to handle anything with the exprsn. */ cValid=CV_COMMENT|CV_ORBRAC|CV_STRING|CV_NUMBER|CV_FUNCT|CV_VAR| CV_OPERATOR; COMPILE_UPSTACK(); break; case CS_MAIN+CRN_RESWRD: if ((cReserved==CRES_INT)|| (cReserved==CRES_STR)|| (cReserved==CRES_THING)|| (cReserved==CRES_EXIT)|| (cReserved==CRES_EXTRA)|| (cReserved==CRES_LOCAL)|| (cReserved==CRES_GLOBAL)|| (cReserved==CRES_PRIVATE)) { COMPILE_GETLASTSRC(); cState=CS_VAR; /* goto variable handler - let it return to caller. */ cValid=CV_RESWRD|CV_COMMENT; } else if (cReserved==CRES_IF) { COMPILE_GETLASTSRC(); cState=CS_IF; /* goto if handler - let it return to caller. */ cValid=CV_RESWRD|CV_COMMENT; } else if (cReserved==CRES_WHILE) { COMPILE_GETLASTSRC(); cState=CS_WHILE; /* goto if handler - let it return to caller. */ cValid=CV_RESWRD|CV_COMMENT; } else if (cReserved==CRES_ELSE) { sprintf(cError,"compile error: reserved word `%s' is invalid here.\n",cLabel); CompileErrorReport(cError); return(COMPILE_SYNTAX_ERROR); } else if((cReserved==CRES_STOP)|| (cReserved==CRES_RETURN)) { COMPILE_GETLASTSRC(); cState=CS_STOP; /* goto if handler - let it return to caller. */ cValid=CV_RESWRD|CV_COMMENT; } else if ((cReserved==CRES_CHAR)|| (cReserved==CRES_CONST)|| (cReserved==CRES_DOUBLE)|| (cReserved==CRES_FLOAT)|| (cReserved==CRES_LONG)|| (cReserved==CRES_PUBLIC)|| (cReserved==CRES_SHORT)|| (cReserved==CRES_SIGNED)|| (cReserved==CRES_STRUCT)|| (cReserved==CRES_TYPEDEF)|| (cReserved==CRES_UNION)|| (cReserved==CRES_UNSIGNED)|| (cReserved==CRES_CONTINUE)|| (cReserved==CRES_VOID)) { sprintf(cError,"compile error: reserved word `%s' not supported.\n",cLabel); CompileErrorReport(cError); sprintf(cError,"Only `str', `int', `thing', `local', `global', and `private' are valid\n"); CompileWarningReport(cError); sprintf(cError,"variable types.\n"); CompileWarningReport(cError); return(COMPILE_SYNTAX_ERROR); } else { sprintf(cError,"compile error: reserved word `%s' not supported\n",cLabel); CompileErrorReport(cError); return(COMPILE_INTERNAL_ERROR); } break; case CS_MAIN+0x100+CRN_SEMI: /* this is our CS_MAIN expr wrapup state */ if ((!(cExpFlag & CEFLAG_FUNCT))&&(!(cExpFlag&CEFLAG_EXP))) { sprintf(cError,"compile error: this is not a valid assignment or function call.\n"); CompileErrorReport(cError); return(COMPILE_SYNTAX_ERROR); } /* Everything came back ok! */ /* Since this is the MAIN loop, and both a function and an */ /* expression will leave a value on the stack, compile a pop. */ cTemp.cInstruction=COP_POP; COMPILE_COMPILE(&cTemp); COMPILE_DOWNSTACK(); COMPILE_PULL(&cTemp); /* return to calling state */ cState=cTemp.cData.cuState; COMPILE_PULL(&cTemp); cValid=cTemp.cData.cuValid; break; case CS_MAIN+0x200+CRN_CBRAC: /* close brace `}' */ COMPILE_DOWNSTACK(); /* return to caller */ COMPILE_PULL(&cTemp); cState=cTemp.cData.cuState; COMPILE_PULL(&cTemp); cValid=cTemp.cData.cuValid; break; case CS_MAIN+0x200+CRN_SEMI: /* more of this compound statement! */ case CS_MAIN+0x200+CRN_FUNCT: case CS_MAIN+0x200+CRN_VAR: case CS_MAIN+0x200+CRN_OPERATOR: case CS_MAIN+0x200+CRN_ORBRAC: case CS_MAIN+0x200+CRN_OBRAC: case CS_MAIN+0x200+CRN_RESWRD: COMPILE_GETLASTSRC(); /* there's more in this {}! */ /* backup & do it again. */ cTemp.cInstruction=COP_NULL; cTemp.cData.cuValid=CV_SEMI|CV_FUNCT|CV_VAR|CV_OPERATOR|CV_ORBRAC| CV_OBRAC|CV_RESWRD|CV_COMMENT|CV_CBRAC; COMPILE_PUSH(&cTemp); cTemp.cData.cuState=CS_MAIN+0x200; COMPILE_PUSH(&cTemp); COMPILE_UPSTACK(); cValid=CV_SEMI|CV_FUNCT|CV_VAR|CV_OPERATOR|CV_ORBRAC|CV_OBRAC| CV_RESWRD|CV_COMMENT; cState=CS_MAIN; break; /* IIIIII FFFFFF * II FF * II FFFF * II FF * IIIIII FF */ case CS_IF+CRN_RESWRD: cValid=CV_ORBRAC|CV_COMMENT; /* now, expect `(' */ cState=CS_IF+0x100; break; case CS_IF+0x100+CRN_ORBRAC: cTemp.cInstruction=COP_NULL; cTemp.cData.cuValid=CV_COMMENT|CV_CRBRAC; COMPILE_PUSH(&cTemp); cTemp.cData.cuState=CS_IF+0x200; COMPILE_PUSH(&cTemp); COMPILE_UPSTACK(); cValid=CV_COMMENT|CV_ORBRAC|CV_STRING|CV_NUMBER|CV_FUNCT|CV_VAR |CV_OPERATOR|CV_CRBRAC; cState=CS_GET_EXP; /* get expression to evaluate */ break; case CS_IF+0x200+CRN_CRBRAC: if (!(cExpFlag&CEFLAG_RVALUE)) { /* nothing to evaluate */ CompileErrorReport("compile error: empty `if' (nothing to evaluate)\n"); return(COMPILE_SYNTAX_ERROR); } if (!(cVarFlag&CDFLAG_INT)) { /* no int to evaluate! */ CompileErrorReport("compile error: `if' must have integer expression!\n"); return(COMPILE_SYNTAX_ERROR); } cTemp.cInstruction=COP_NULL; /* save `if' location to adj. offset jmp */ cTemp.cData.cuOffset=cComp; COMPILE_PUSH(&cTemp); cTemp.cInstruction=COP_IFZ; cTemp.cData.cuPointer=0; COMPILE_COMPILE(&cTemp); /* we don't know what we're returning to, nor do we care! */ /* Unless, of course, it's an `else'. */ cTemp.cData.cuValid=CV_EOF|CV_OPERATOR|CV_COMMENT|CV_COMMA|CV_PERIOD| CV_OSBRAC|CV_CSBRAC|CV_OBRAC|CV_CBRAC|CV_ORBRAC| CV_CRBRAC|CV_STRING|CV_SEMI|CV_NUMBER|CV_RESWRD| CV_FUNCT|CV_VAR|CV_UNDEF; COMPILE_PUSH(&cTemp); cTemp.cData.cuState=CS_IF+0x300; COMPILE_PUSH(&cTemp); COMPILE_UPSTACK(); cState=CS_MAIN; /* compile statement */ cValid=CV_SEMI|CV_FUNCT|CV_VAR|CV_OPERATOR|CV_ORBRAC|CV_OBRAC| CV_RESWRD|CV_COMMENT; break; case CS_IF+0x300+CRN_EOF: case CS_IF+0x300+CRN_OPERATOR: case CS_IF+0x300+CRN_COMMENT: case CS_IF+0x300+CRN_COMMA: case CS_IF+0x300+CRN_PERIOD: case CS_IF+0x300+CRN_OSBRAC: case CS_IF+0x300+CRN_CSBRAC: case CS_IF+0x300+CRN_OBRAC: case CS_IF+0x300+CRN_CBRAC: case CS_IF+0x300+CRN_ORBRAC: case CS_IF+0x300+CRN_CRBRAC: case CS_IF+0x300+CRN_STRING: case CS_IF+0x300+CRN_SEMI: case CS_IF+0x300+CRN_NUMBER: case CS_IF+0x300+CRN_FUNCT: case CS_IF+0x300+CRN_UNDEF: case CS_IF+0x300+CRN_VAR: case CS_IF+0x400+CRN_EOF: /* yes, overlapping states. But look at it.*/ case CS_IF+0x400+CRN_OPERATOR: /* This is saving a fair amount of code. */ case CS_IF+0x400+CRN_COMMENT: case CS_IF+0x400+CRN_COMMA: case CS_IF+0x400+CRN_PERIOD: case CS_IF+0x400+CRN_OSBRAC: case CS_IF+0x400+CRN_CSBRAC: case CS_IF+0x400+CRN_OBRAC: case CS_IF+0x400+CRN_CBRAC: case CS_IF+0x400+CRN_ORBRAC: case CS_IF+0x400+CRN_CRBRAC: case CS_IF+0x400+CRN_STRING: case CS_IF+0x400+CRN_SEMI: case CS_IF+0x400+CRN_NUMBER: case CS_IF+0x400+CRN_FUNCT: case CS_IF+0x400+CRN_UNDEF: case CS_IF+0x400+CRN_VAR: case CS_IF+0x400+CRN_RESWRD: /* second time - no check for an 'else' */ COMPILE_PULL(&cTemp); cCompBuf[cTemp.cData.cuPointer+1]=(BYTE)(cComp&0x00ff); /* adj if jmp */ cCompBuf[cTemp.cData.cuPointer+2]=(BYTE)((cComp&0xff00)>>8); /* boogey on back to home base - ie return to caller */ COMPILE_GETLASTSRC(); COMPILE_DOWNSTACK(); COMPILE_PULL(&cTemp); /* return to calling state */ cState=cTemp.cData.cuState; COMPILE_PULL(&cTemp); cValid=cTemp.cData.cuValid; break; case CS_IF+0x300+CRN_RESWRD: if (cReserved==CRES_ELSE) { /* there's an else! */ COMPILE_PULL(&cTemp); /* mark zero */ cCompBuf[cTemp.cData.cuPointer+1]=(BYTE)((cComp+3)&0x00ff); /* adj if jmp */ cCompBuf[cTemp.cData.cuPointer+2]=(BYTE)(((cComp+3)&0xff00)>>8); cTemp.cInstruction=COP_NULL; /* save `goto' location to adj. offset jmp */ cTemp.cData.cuOffset=cComp; COMPILE_PUSH(&cTemp); cTemp.cInstruction=COP_GOTO; cTemp.cData.cuPointer=0; COMPILE_COMPILE(&cTemp); /* we don't know what we're returning to, nor do we care! */ /* Unless, of course, it's an `else'. */ cTemp.cData.cuValid=CV_EOF|CV_OPERATOR|CV_COMMENT|CV_COMMA|CV_PERIOD| CV_OSBRAC|CV_CSBRAC|CV_OBRAC|CV_CBRAC|CV_ORBRAC| CV_CRBRAC|CV_STRING|CV_SEMI|CV_NUMBER|CV_RESWRD| CV_FUNCT|CV_VAR|CV_UNDEF; COMPILE_PUSH(&cTemp); cTemp.cData.cuState=CS_IF+0x400; COMPILE_PUSH(&cTemp); COMPILE_UPSTACK(); cState=CS_MAIN; /* compile statement */ cValid=CV_SEMI|CV_FUNCT|CV_VAR|CV_OPERATOR|CV_ORBRAC|CV_OBRAC| CV_RESWRD|CV_COMMENT; break; } else { COMPILE_PULL(&cTemp); cCompBuf[cTemp.cData.cuPointer+1]=(BYTE)(cComp&0x00ff); /* adj if jmp */ cCompBuf[cTemp.cData.cuPointer+2]=(BYTE)((cComp&0xff00)>>8); /* boogey on back to home base - ie return to caller */ COMPILE_GETLASTSRC(); COMPILE_DOWNSTACK(); COMPILE_PULL(&cTemp); /* return to calling state */ cState=cTemp.cData.cuState; COMPILE_PULL(&cTemp); cValid=cTemp.cData.cuValid; } break; /* WW WW HH HH IIIIII LL EEEEEE * WW WWW WW HH HH II LL EE * WWWW WWWW HHHHHHH II LL EEEE * WWW WWW HH HH II LL EE * WW WW HH HH IIIIII LLLLLL EEEEEE */ case CS_WHILE+CRN_RESWRD: cValid=CV_ORBRAC|CV_COMMENT; /* now, expect `(' */ cState=CS_WHILE+0x100; break; case CS_WHILE+0x100+CRN_ORBRAC: cTemp.cInstruction=COP_GOTO; /* save `goto' location to adj. goto */ cTemp.cData.cuOffset=cComp; COMPILE_PUSH(&cTemp); cTemp.cInstruction=COP_NULL; cTemp.cData.cuValid=CV_COMMENT|CV_CRBRAC; COMPILE_PUSH(&cTemp); cTemp.cData.cuState=CS_WHILE+0x200; COMPILE_PUSH(&cTemp); COMPILE_UPSTACK(); cValid=CV_COMMENT|CV_ORBRAC|CV_STRING|CV_NUMBER|CV_FUNCT|CV_VAR |CV_OPERATOR|CV_CRBRAC; cState=CS_GET_EXP; /* get expression to evaluate */ break; case CS_WHILE+0x200+CRN_CRBRAC: if (!(cExpFlag&CEFLAG_RVALUE)) { /* nothing to evaluate */ CompileErrorReport("compile error: empty `while' (nothing to evaluate)\n"); return(COMPILE_SYNTAX_ERROR); } if (!(cVarFlag&CDFLAG_INT)) { /* no int to evaluate! */ CompileErrorReport("compile error: `if' must have integer expression!\n"); return(COMPILE_SYNTAX_ERROR); } cTemp.cInstruction=COP_NULL; /* save `while' location to adj. goto */ cTemp.cData.cuOffset=cComp; COMPILE_PUSH(&cTemp); cTemp.cInstruction=COP_WHILEZ; cTemp.cData.cuPointer=0; COMPILE_COMPILE(&cTemp); /* we don't know what we're returning to, nor do we care! */ /* Unless, of course, it's an `else'. */ cTemp.cData.cuValid=CV_EOF|CV_OPERATOR|CV_COMMENT|CV_COMMA|CV_PERIOD| CV_OSBRAC|CV_CSBRAC|CV_OBRAC|CV_CBRAC|CV_ORBRAC| CV_CRBRAC|CV_STRING|CV_SEMI|CV_NUMBER|CV_RESWRD| CV_FUNCT|CV_VAR|CV_UNDEF; COMPILE_PUSH(&cTemp); cTemp.cData.cuState=CS_WHILE+0x300; COMPILE_PUSH(&cTemp); COMPILE_UPSTACK(); cState=CS_MAIN; /* compile statement */ cValid=CV_SEMI|CV_FUNCT|CV_VAR|CV_OPERATOR|CV_ORBRAC|CV_OBRAC| CV_RESWRD|CV_COMMENT; break; case CS_WHILE+0x300+CRN_EOF: case CS_WHILE+0x300+CRN_OPERATOR: case CS_WHILE+0x300+CRN_COMMENT: case CS_WHILE+0x300+CRN_COMMA: case CS_WHILE+0x300+CRN_PERIOD: case CS_WHILE+0x300+CRN_OSBRAC: case CS_WHILE+0x300+CRN_CSBRAC: case CS_WHILE+0x300+CRN_OBRAC: case CS_WHILE+0x300+CRN_CBRAC: case CS_WHILE+0x300+CRN_ORBRAC: case CS_WHILE+0x300+CRN_CRBRAC: case CS_WHILE+0x300+CRN_STRING: case CS_WHILE+0x300+CRN_SEMI: case CS_WHILE+0x300+CRN_NUMBER: case CS_WHILE+0x300+CRN_FUNCT: case CS_WHILE+0x300+CRN_UNDEF: case CS_WHILE+0x300+CRN_RESWRD: case CS_WHILE+0x300+CRN_VAR: COMPILE_PULL(&cTemp); /* mark zero */ cCompBuf[cTemp.cData.cuPointer+1]=(BYTE)((cComp+3)&0x00ff); /* adj while jmp */ cCompBuf[cTemp.cData.cuPointer+2]=(BYTE)(((cComp+3)&0xff00)>>8); COMPILE_COMPILESTACK(); /* boogey on back to home base - ie return to caller */ COMPILE_GETLASTSRC(); COMPILE_DOWNSTACK(); COMPILE_PULL(&cTemp); /* return to calling state */ cState=cTemp.cData.cuState; COMPILE_PULL(&cTemp); cValid=cTemp.cData.cuValid; break; /* EEEEEE XX XX IIIIII TTTTTT * EE XX XX II TT * EEEE XXXX II TT * EE XX XX II TT * EEEEEE XX XX IIIIII TT */ case CS_STOP+CRN_RESWRD: cValid=CV_SEMI|CV_COMMENT; /* now, expect `;' */ cState=CS_STOP+0x100; cTemp.cInstruction=COP_TERM; COMPILE_COMPILE(&cTemp); break; case CS_STOP+0x100+CRN_SEMI: COMPILE_DOWNSTACK(); COMPILE_PULL(&cTemp); /* return to calling state */ cState=cTemp.cData.cuState; COMPILE_PULL(&cTemp); cValid=cTemp.cData.cuValid; break; /* GGGGG EEEEEE TTTTTT EEEEEE XX XX PPPPP * GG EE TT EE XX XX PP PP * GG GGG EEEE TT EEEE XXXX PPPPP * GG GG EE TT EE XX XX PP * GGGGG EEEEEE TT ______ EEEEEE XX XX PP */ /* just a note before we get into this. */ /* Get_Exp returns, in cExpFlag and cVarFlag, the type of */ /* expression read in. cExpFlag indicates: is it a valid lvalue? */ /* rvalue? Is it a full equation (ie a=b+c as opposed to b+c)? */ /* Is it a valid function call? */ /* cVarFlag indicates the type of variables involved. */ case CS_GET_EXP+CRN_SEMI: /* null expression */ cTemp.cInstruction=COP_PUSHV; cTemp.cData.cuSLWord=0; COMPILE_GETLASTSRC(); /* whoah! backup and return ; */ COMPILE_DOWNSTACK(); COMPILE_PULL(&cTemp); /* return to calling state */ cState=cTemp.cData.cuState; COMPILE_PULL(&cTemp); cValid=cTemp.cData.cuValid; break; case CS_GET_EXP+CRN_CRBRAC: cNumParam=0; /* we got a SomeFunct() type call - no params */ COMPILE_GETLASTSRC(); /* whoah! backup and return ) */ cVarFlag=cExpFlag=0; COMPILE_DOWNSTACK(); COMPILE_PULL(&cTemp); /* return to calling state */ cState=cTemp.cData.cuState; COMPILE_PULL(&cTemp); cValid=cTemp.cData.cuValid; break; case CS_GET_EXP+CRN_FUNCT: case CS_GET_EXP+CRN_VAR: case CS_GET_EXP+CRN_STRING: case CS_GET_EXP+CRN_NUMBER: case CS_GET_EXP+CRN_ORBRAC: case CS_GET_EXP+CRN_OPERATOR: /* for -, !, ++, --, ~ */ COMPILE_GETLASTSRC(); /* backup! */ cTemp.cInstruction=COP_NULL; /* start with "all possibilities" */ cTemp.cData.cuExpFlag=CEFLAG_FUNCT|CEFLAG_LVALUE|CEFLAG_RVALUE| CEFLAG_EXP; COMPILE_PUSH(&cTemp); /* and slowly whittle them away */ cTemp.cData.cuVarFlag=CDFLAG_STR|CDFLAG_INT|CDFLAG_THING|CDFLAG_NULL| CDFLAG_EXTRA|CDFLAG_EXIT; COMPILE_PUSH(&cTemp); cTemp.cData.cuValid=CV_COMMENT|CV_OPERATOR|CV_COMMA|CV_SEMI|CV_CRBRAC; COMPILE_PUSH(&cTemp); cTemp.cData.cuState=CS_GET_EXP+0x100; COMPILE_PUSH(&cTemp); COMPILE_UPSTACK(); cValid=CV_COMMENT|CV_FUNCT|CV_NUMBER|CV_ORBRAC|CV_VAR|CV_STRING|CV_OPERATOR; cState=CS_GET_NEXT; break; case CS_GET_EXP+0x100+CRN_SEMI: case CS_GET_EXP+0x100+CRN_CRBRAC: case CS_GET_EXP+0x100+CRN_COMMA: COMPILE_PULL(&cTemp); /* pull cVarFlag */ cVarFlag=cVarFlag & cTemp.cData.cuVarFlag; COMPILE_PULL(&cTemp); /* pull cExpFlag */ cExpFlag=cExpFlag & cTemp.cData.cuExpFlag; if (!(cVarFlag)) { /* wrong data type */ sprintf(cError,"compile error: incompatible data types.\n"); CompileErrorReport(cError); return(COMPILE_SYNTAX_ERROR); } /* compile anything left on the stack */ while(cSP) { COMPILE_COMPILESTACK(); } /* backup and exit */ COMPILE_GETLASTSRC(); COMPILE_DOWNSTACK(); COMPILE_PULL(&cTemp); /* pull cState */ cState=cTemp.cData.cuState; COMPILE_PULL(&cTemp); /* pull cValid */ cValid=cTemp.cData.cuValid; break; case CS_GET_EXP+0x100+CRN_OPERATOR: COMPILE_PULL(&cTemp); /* pull cVarFlag */ cVarFlag=cVarFlag & cTemp.cData.cuVarFlag; COMPILE_PULL(&cTemp); /* pull cExpFlag */ cExpFlag=cExpFlag & cTemp.cData.cuExpFlag; /* compare data types */ if (!(cVarFlag)) { /* wrong data type */ sprintf(cError,"compile error: incompatible data types.\n"); CompileErrorReport(cError); return(COMPILE_SYNTAX_ERROR); } if ((cOperation&0xff)<=COP_EQU) { /* equate operation */ if (!(cExpFlag&CEFLAG_LVALUE)) { /* invalid lvalue */ sprintf(cError,"compile error: invalid lvalue in expression <lvalue>=<rvalue>\n"); CompileErrorReport(cError); return(COMPILE_SYNTAX_ERROR); } if (((cOperation&0xff)!=COP_EQU)&& /* check for non-`=' and non-ints!*/ (!(cVarFlag&CDFLAG_INT))) { sprintf(cError,"compile error: can only use this operator on `int' types.\n"); CompileErrorReport(cError); return(COMPILE_SYNTAX_ERROR); } cTemp.cInstruction=cOperation&0xff; COMPILE_PUSH(&cTemp); /* just call CS_GET_EXP, make sure it's a valid rvalue, & exit */ cTemp.cInstruction=COP_NULL; cTemp.cData.cuExpFlag=cExpFlag; COMPILE_PUSH(&cTemp); cTemp.cData.cuVarFlag=cVarFlag; COMPILE_PUSH(&cTemp); cTemp.cData.cuValid=CV_COMMENT|CV_SEMI|CV_COMMA|CV_CRBRAC; COMPILE_PUSH(&cTemp); cTemp.cData.cuState=CS_GET_EXP+0x200; COMPILE_PUSH(&cTemp); /* and call CS_GET_EXP */ COMPILE_UPSTACK(); cValid=CV_COMMENT|CV_ORBRAC|CV_STRING|CV_NUMBER|CV_FUNCT|CV_VAR|CV_OPERATOR; cState=CS_GET_EXP; } /* if (equate) */ else if (((cOperation&0xff)==COP_ASUB)|| ((cOperation&0xff)==COP_AADD)) { /* ++ or -- */ if (!(cVarFlag&CDFLAG_INT)) { /* invalid op with this type */ sprintf(cError,"compile error: can only use this operator on `int' types.\n"); CompileErrorReport(cError); return(COMPILE_SYNTAX_ERROR); } if (!(cExpFlag&CEFLAG_LVALUE)) { /* no lvalue! AAAAA */ sprintf(cError,"compile error: modifiable lvalue (ie a variable) is needed to use ++ or --\n"); CompileErrorReport(cError); return(COMPILE_SYNTAX_ERROR); } cExpFlag=(cExpFlag|CEFLAG_LVALUE|CEFLAG_FUNCT) -(CEFLAG_LVALUE|CEFLAG_FUNCT); cExpFlag|=CEFLAG_EXP; cTemp.cInstruction=cOperation&0xFF; COMPILE_COMPILE(&cTemp); /* compile unary operator */ cTemp.cInstruction=COP_NULL; /* and push back cExpFlag & cVarFlag */ cTemp.cData.cuExpFlag=cExpFlag; COMPILE_PUSH(&cTemp); cTemp.cData.cuVarFlag=cVarFlag; COMPILE_PUSH(&cTemp); } /* -- or ++ operators */ else if ( (((cOperation&0xff)==COP_BEQU)|| ((cOperation&0xff)==COP_BNEQU))&& (!(cVarFlag&CDFLAG_INT)) ) { /* == or != w/ non-int */ /* this is a special case because we have to turn a non-int */ /* expression such as `a==b' (assuming a & b are non-ints) */ /* into an int expression so it can be evaluated properly! */ cTemp.cInstruction=cOperation&0xff; COMPILE_PUSH(&cTemp); /* just call CS_GET_EXP, make sure it's a valid rvalue, modify cVarFlags, & exit */ cTemp.cInstruction=COP_NULL; cTemp.cData.cuExpFlag=cExpFlag; COMPILE_PUSH(&cTemp); cTemp.cData.cuVarFlag=cVarFlag; COMPILE_PUSH(&cTemp); cTemp.cData.cuValid=CV_COMMENT|CV_SEMI|CV_COMMA|CV_CRBRAC; COMPILE_PUSH(&cTemp); cTemp.cData.cuState=CS_GET_EXP+0x300; COMPILE_PUSH(&cTemp); /* and call CS_GET_EXP */ COMPILE_UPSTACK(); cValid=CV_COMMENT|CV_ORBRAC|CV_STRING|CV_NUMBER|CV_FUNCT|CV_VAR|CV_OPERATOR; cState=CS_GET_EXP; } /* == or != w/ non-int */ else { /* everything else (non-equate operation) */ if (!(cVarFlag&CDFLAG_INT)) { /* invalid op with this type */ sprintf(cError,"compile error: can only use this operator on `int' types.\n"); CompileErrorReport(cError); return(COMPILE_SYNTAX_ERROR); } /* adjust cExpFlag - it can't be these & have an operator! */ cExpFlag=(cExpFlag|CEFLAG_LVALUE|CEFLAG_FUNCT|CEFLAG_EXP) -(CEFLAG_LVALUE|CEFLAG_FUNCT|CEFLAG_EXP); /* push the instruction */ cTemp.cInstruction=0xff; while((cTemp.cInstruction > (cOperation&0xff)) && cSP) { COMPILE_PULL(&cTemp); if (cTemp.cInstruction > (cOperation&0xff)) { COMPILE_COMPILE(&cTemp); } /* if */ else { COMPILE_PUSH(&cTemp); } /* else */ } /* while */ cTemp.cInstruction=cOperation&0xff; COMPILE_PUSH(&cTemp); cTemp.cData.cuExpFlag=cExpFlag; /* save everything & get next thing */ COMPILE_PUSH(&cTemp); cTemp.cData.cuVarFlag=cVarFlag; COMPILE_PUSH(&cTemp); cTemp.cData.cuValid=CV_COMMENT|CV_OPERATOR|CV_COMMA|CV_SEMI|CV_CRBRAC; COMPILE_PUSH(&cTemp); cTemp.cData.cuState=CS_GET_EXP+0x100; COMPILE_PUSH(&cTemp); COMPILE_UPSTACK(); cValid=CV_COMMENT|CV_FUNCT|CV_NUMBER|CV_ORBRAC|CV_VAR|CV_STRING|CV_OPERATOR; cState=CS_GET_NEXT; } /* else non-equate operator */ break; case CS_GET_EXP+0x200+CRN_SEMI: /* this state handles expressions */ case CS_GET_EXP+0x200+CRN_CRBRAC: case CS_GET_EXP+0x200+CRN_COMMA: COMPILE_PULL(&cTemp); /* pull cVarFlag */ cVarFlag=cVarFlag & cTemp.cData.cuVarFlag; if (!(cVarFlag)) { /* wrong data type */ sprintf(cError,"compile error: assignment involves incompatible data types.\n"); CompileErrorReport(cError); return(COMPILE_SYNTAX_ERROR); } COMPILE_PULL(&cTemp); /* pull cExpFlag */ if (!(cExpFlag&CEFLAG_RVALUE)) { /* invalid rvalue */ sprintf(cError,"compile error: invalid rvalue in expression <lvalue>=<rvalue>\n"); CompileErrorReport(cError); return(COMPILE_SYNTAX_ERROR); } /* note: we KNOW we have an expression, thus the CEFLAG_EXP etc above */ cExpFlag=(cExpFlag&cTemp.cData.cuExpFlag)|CEFLAG_EXP; /* compile anything left on the stack */ while(cSP) { COMPILE_COMPILESTACK(); } /* backup and exit */ COMPILE_GETLASTSRC(); COMPILE_DOWNSTACK(); COMPILE_PULL(&cTemp); /* pull cState */ cState=cTemp.cData.cuState; COMPILE_PULL(&cTemp); /* pull cValid */ cValid=cTemp.cData.cuValid; break; case CS_GET_EXP+0x300+CRN_SEMI: /* this state handles pointer == & != */ case CS_GET_EXP+0x300+CRN_CRBRAC: case CS_GET_EXP+0x300+CRN_COMMA: COMPILE_PULL(&cTemp); /* pull cVarFlag */ cVarFlag=cVarFlag & cTemp.cData.cuVarFlag; if (!(cVarFlag)) { /* wrong data type */ sprintf(cError,"compile error: equality involves incompatible data types.\n"); CompileErrorReport(cError); return(COMPILE_SYNTAX_ERROR); } COMPILE_PULL(&cTemp); /* pull cExpFlag */ if (!(cExpFlag&CEFLAG_RVALUE)) { /* invalid rvalue */ sprintf(cError,"compile error: invalid rvalue in expression <lvalue>=<rvalue>\n"); CompileErrorReport(cError); return(COMPILE_SYNTAX_ERROR); } cExpFlag=((cExpFlag&cTemp.cData.cuExpFlag)| (CEFLAG_EXP|CEFLAG_FUNCT|CEFLAG_LVALUE)) -(CEFLAG_EXP|CEFLAG_FUNCT|CEFLAG_LVALUE); cVarFlag=CDFLAG_INT; /* mark our equate function as a proper int */ /* compile anything left on the stack */ while(cSP) { COMPILE_COMPILESTACK(); } /* backup and exit */ COMPILE_GETLASTSRC(); COMPILE_DOWNSTACK(); COMPILE_PULL(&cTemp); /* pull cState */ cState=cTemp.cData.cuState; COMPILE_PULL(&cTemp); /* pull cValid */ cValid=cTemp.cData.cuValid; break; /* FFFFFF UU UU NNN NN CCCC TTTTTT IIIIII OOOO NNN NN * FF UU UU NNNN NN CC CC TT II OO OO NNNN NN * FFFF UU UU NN NN NN CC TT II OO OO NN NN NN * FF UU UU NN NNNN CC CC TT II OO OO NN NNNN * FF UUUUU NN NNN CCCC TT IIIIII OOOO NN NNN */ case CS_FUNCTION+CRN_FUNCT: cTemp.cInstruction=COP_EXECR; /* push function on stack */ cTemp.cData.cuFunction=cFunction; COMPILE_PUSH(&cTemp); cTemp.cInstruction=COP_NULL; /* push this fn's return type */ cTemp.cData.cuParamType=fTable[cFunction].fDataType; COMPILE_PUSH(&cTemp); cTemp.cData.cuUnsigned=cNumParam; /* push last fn's # params */ COMPILE_PUSH(&cTemp); cNumParam=1; /* assume 1 param for this procedure - we are reset to 0 if we have a ) as our first entry to our expression! */ counter=0; /* and push param types on stack */ while(fTable[cFunction].fParamType[counter]!=CDT_NULL) counter++; /* you see, we want to put the parameters on the stack in reverse */ /* order (it's a stack - get it? - FILO ring a bell?) */ if (!counter) { /* ie NO parameters */ cTemp.cData.cuValid=CV_CRBRAC|CV_COMMENT|CV_COMMA; COMPILE_PUSH(&cTemp); cTemp.cData.cuState=CS_FUNCTION+0x400; /* empty ) handler */ COMPILE_PUSH(&cTemp); } else { /* put parameter types on stack */ counter--; cTemp.cData.cuParamType=fTable[cFunction].fParamType[counter]; COMPILE_PUSH(&cTemp); cTemp.cData.cuValid=CV_CRBRAC|CV_COMMENT|CV_COMMA; /* first, our ) handler */ COMPILE_PUSH(&cTemp); cTemp.cData.cuState=CS_FUNCTION+0x300; /* ) handler */ COMPILE_PUSH(&cTemp); while(counter) { /* here's where we put them on the stack! */ counter--; cTemp.cData.cuParamType=fTable[cFunction].fParamType[counter]; COMPILE_PUSH(&cTemp); cTemp.cData.cuValid=CV_COMMENT|CV_COMMA|CV_CRBRAC; COMPILE_PUSH(&cTemp); cTemp.cData.cuState=CS_FUNCTION+0x200; /* , handler */ COMPILE_PUSH(&cTemp); } /* while(counter) */ } /* else */ COMPILE_UPSTACK(); cValid=CV_ORBRAC|CV_COMMENT; /* read ( */ cState=CS_FUNCTION+0x100; break; case CS_FUNCTION+0x100+CRN_ORBRAC: /* the stack has been set up and everything, so we just have to */ /* call CS_GET_EXP. This state is just to make sure there's a ( */ cValid=CV_COMMENT|CV_ORBRAC|CV_STRING|CV_NUMBER|CV_FUNCT|CV_VAR| CV_CRBRAC|CV_OPERATOR; /* NOTE: we allow a CV_CRBRAC because we might have somefunct() */ /* but this should not be normal practice with CS_GET_EXP.*/ cState=CS_GET_EXP; break; case CS_FUNCTION+0x200+CRN_COMMA: COMPILE_PULL(&cTemp); if ((!(cVarFlag&(1<<cTemp.cData.cuParamType)))|| (!(cExpFlag&CEFLAG_RVALUE))) { sprintf(cError,"compile error: data type of parameter to function is incorrect.\n"); CompileErrorReport(cError); return(COMPILE_SYNTAX_ERROR); } cNumParam++; /* increment our # parameters in this function call */ COMPILE_UPSTACK(); cValid=CV_COMMENT|CV_ORBRAC|CV_STRING|CV_NUMBER|CV_FUNCT|CV_VAR|CV_OPERATOR; cState=CS_GET_EXP; break; case CS_FUNCTION+0x200+CRN_CRBRAC: /* unless our param type is CDT_ETC, too few parameters to function */ COMPILE_PULL(&cTemp); if (cTemp.cData.cuParamType==CDT_ETC) { /* we've finally run out of parameters with a CDT_ETC param type. */ /* let's pack up our bags and go home. */ COMPILE_GETLASTSRC(); COMPILE_PULL(&cTemp); /* return to calling state */ cState=cTemp.cData.cuState; COMPILE_PULL(&cTemp); cValid=cTemp.cData.cuValid; break; } sprintf(cError,"compile error: Bill, while I agree that, in time, our band will be\n most triumphant, there's too few parameters passed to this function.\n"); CompileErrorReport(cError); return(COMPILE_SYNTAX_ERROR); break; case CS_FUNCTION+0x300+CRN_COMMA: COMPILE_PULL(&cTemp); if (cTemp.cData.cuParamType==CDT_ETC) { /* anything goes... */ /* anything goes - as many variables, of any type */ /* push our CDT_ETC back on the stack - for next time, and * see if there's "one more variable" - which will land us * back here! */ COMPILE_PUSH(&cTemp); cTemp.cData.cuValid=CV_CRBRAC|CV_COMMENT|CV_COMMA; /* first, our ) handler */ COMPILE_PUSH(&cTemp); cTemp.cData.cuState=CS_FUNCTION+0x300; /* ) handler */ COMPILE_PUSH(&cTemp); cNumParam++; /* increment our # parameters in this function call */ COMPILE_UPSTACK(); cValid=CV_COMMENT|CV_ORBRAC|CV_STRING|CV_NUMBER|CV_FUNCT|CV_VAR|CV_OPERATOR; cState=CS_GET_EXP; break; } /* too many parameters to function */ sprintf(cError,"compile error: But Ted, there's too many parameters passed to this function!\n"); CompileErrorReport(cError); return(COMPILE_SYNTAX_ERROR); break; case CS_FUNCTION+0x300+CRN_CRBRAC: COMPILE_PULL(&cTemp); if (cTemp.cData.cuParamType!=CDT_ETC) /* type is specified */ if ((!(cVarFlag&(1<<cTemp.cData.cuParamType)))|| (!(cExpFlag&CEFLAG_RVALUE))) { sprintf(cError,"compile error: data type of parameter to function is incorrect.\n"); CompileErrorReport(cError); return(COMPILE_SYNTAX_ERROR); } cTemp.cInstruction=COP_PUSHV; /* load in our # params specifier */ cTemp.cData.cuSLWord=cNumParam; COMPILE_COMPILE(&cTemp); COMPILE_PULL(&cTemp); /* retrieve our last fn's cNumParam value */ cNumParam=cTemp.cData.cuUnsigned; COMPILE_PULL(&cTemp); /* get our return data type */ cVarFlag=1<<cTemp.cData.cuParamType; cExpFlag=CEFLAG_RVALUE|CEFLAG_FUNCT; /* while we're setting flags */ COMPILE_COMPILESTACK(); /* compile our COP_EXEC */ COMPILE_DOWNSTACK(); COMPILE_PULL(&cTemp); /* return to calling state */ cState=cTemp.cData.cuState; COMPILE_PULL(&cTemp); cValid=cTemp.cData.cuValid; break; case CS_FUNCTION+0x400+CRN_CRBRAC: /* no-parameter ) handler */ if (cVarFlag | cExpFlag) { sprintf(cError,"compile error: this function expects no parameters!\n"); CompileErrorReport(cError); return(COMPILE_SYNTAX_ERROR); } cTemp.cInstruction=COP_PUSHV; /* load in our # params specifier */ cTemp.cData.cuSLWord=cNumParam; COMPILE_COMPILE(&cTemp); COMPILE_PULL(&cTemp); /* retrieve our last fn's cNumParam value */ cNumParam=cTemp.cData.cuUnsigned; COMPILE_PULL(&cTemp); /* get our return data type */ cVarFlag=1<<cTemp.cData.cuParamType; cExpFlag=CEFLAG_RVALUE|CEFLAG_FUNCT; /* while we're setting flags */ COMPILE_COMPILESTACK(); /* compile our COP_EXEC */ COMPILE_DOWNSTACK(); COMPILE_PULL(&cTemp); /* return to calling state */ cState=cTemp.cData.cuState; COMPILE_PULL(&cTemp); cValid=cTemp.cData.cuValid; break; case CS_FUNCTION+0x400+CRN_COMMA: /* this state is just to print out a pleasant error message */ sprintf(cError,"compile error: this function expects no parameters!\n"); CompileErrorReport(cError); return(COMPILE_SYNTAX_ERROR); break; /* GGGGG EEEEEE TTTTTT NNN NN EEEEEE XX XX TTTTTT * GG EE TT NNNN NN EE XX XX TT * GG GGG EEEE TT NN NN NN EEEE XXXX TT * GG GG EE TT NN NNNN EE XX XX TT * GGGGG EEEEEE TT ______ NN NNN EEEEEE XX XX TT */ case CS_GET_NEXT+CRN_FUNCT: COMPILE_GETLASTSRC(); /* whoah! backup! */ cState=CS_FUNCTION; /* pass function over to function handler and */ /* let IT return to our previous state. */ cValid=CV_FUNCT; break; case CS_GET_NEXT+CRN_NUMBER: cTemp.cInstruction=COP_PUSHV; cTemp.cData.cuSLWord=CompileStrToNum(cLabel); COMPILE_COMPILE(&cTemp); cVarFlag=CDFLAG_INT; cExpFlag=CEFLAG_RVALUE; COMPILE_DOWNSTACK(); /* and return to our caller */ COMPILE_PULL(&cTemp); cState=cTemp.cData.cuState; COMPILE_PULL(&cTemp); cValid=cTemp.cData.cuValid; break; case CS_GET_NEXT+CRN_STRING: cTemp.cInstruction=COP_PUSHPT; cTemp.cData.cuPtr=STRCREATE(cLabel); COMPILE_COMPILE(&cTemp); cVarFlag=CDFLAG_STR; cExpFlag=CEFLAG_RVALUE; COMPILE_DOWNSTACK(); /* and return to our caller */ COMPILE_PULL(&cTemp); cState=cTemp.cData.cuState; COMPILE_PULL(&cTemp); cValid=cTemp.cData.cuValid; break; case CS_GET_NEXT+CRN_ORBRAC: cValid=CV_COMMENT|CV_ORBRAC|CV_STRING|CV_NUMBER|CV_FUNCT|CV_VAR| CV_CRBRAC|CV_OPERATOR; cState=CS_GET_EXP; /* let's get the expression in this bracket */ cTemp.cInstruction=COP_NULL; cTemp.cData.cuValid=CV_CRBRAC|CV_COMMENT; /* and return to ) handler */ COMPILE_PUSH(&cTemp); cTemp.cData.cuState=CS_GET_NEXT+0x100; COMPILE_PUSH(&cTemp); COMPILE_UPSTACK(); break; case CS_GET_NEXT+CRN_VAR: if (cVarTable[cVar].cDomain==CDOMAIN_LOCAL) { cTemp.cInstruction=COP_PUSHL; } else if (cVarTable[cVar].cDomain==CDOMAIN_GLOBAL) { cTemp.cInstruction=COP_PUSHG; } else if (cVarTable[cVar].cDomain==CDOMAIN_PRIVATE) { cTemp.cInstruction=COP_PUSHP; } else { sprintf(cError,"internal error (compile.c): Unknown domain for `%s'.\nThis shouldn't happen. Notify your Sys Admin.\n",cVarTable[cVar].cText); CompileErrorReport(cError); return(COMPILE_INTERNAL_ERROR); } cTemp.cData.cuVar=cVarTable[cVar].cOffset; COMPILE_COMPILE(&cTemp); if (cVarTable[cVar].cType==CDT_INT) { cVarFlag=CDFLAG_INT; } else if (cVarTable[cVar].cType==CDT_STR) { cVarFlag=CDFLAG_STR; } else if (cVarTable[cVar].cType==CDT_THING) { cVarFlag=CDFLAG_THING; } else if (cVarTable[cVar].cType==CDT_EXTRA) { cVarFlag=CDFLAG_EXTRA; } else if (cVarTable[cVar].cType==CDT_EXIT) { cVarFlag=CDFLAG_EXIT; } else { sprintf(cError,"internal error (compile.c): Unknown variable type for `%s'.\nThis shouldn't happen. Notify your Sys Admin.\n",cVarTable[cVar].cText); CompileErrorReport(cError); return(COMPILE_INTERNAL_ERROR); } if ((cVarTable[cVar].cDomain==CDOMAIN_LOCAL)&& (cVarTable[cVar].cOffset<cSystemVariableStatic)) { cExpFlag=CEFLAG_RVALUE; } else { cExpFlag=CEFLAG_RVALUE|CEFLAG_LVALUE; } COMPILE_DOWNSTACK(); /* and return to our caller */ COMPILE_PULL(&cTemp); cState=cTemp.cData.cuState; COMPILE_PULL(&cTemp); cValid=cTemp.cData.cuValid; break; case CS_GET_NEXT+CRN_OPERATOR: /* for `, !, \, ++, -- */ if ((cOperation&0xff)==COP_SUB) { /* conversion of `-' */ cOperation=((cOperation&0xff00)+COP_NEG); } if ((cOperation&0xff)==COP_ASUB) { /* conversion of `--' */ cOperation=((cOperation&0xff00)+COP_BSUB); } if ((cOperation&0xff)==COP_AADD) { /* conversion of `++' */ cOperation=((cOperation&0xff00)+COP_BADD); } if (((cOperation&0xff)!=COP_COMP)&& ((cOperation&0xff)!=COP_BSUB)&& ((cOperation&0xff)!=COP_BADD)&& ((cOperation&0xff)!=COP_NOT)&& ((cOperation&0xff)!=COP_NEG)) { /* non-unary operation */ CompileErrorReport("compile error: unexpected operator.\n"); return(COMPILE_SYNTAX_ERROR); } cTemp.cInstruction=cOperation&0xff; /* save instruction */ COMPILE_PUSH(&cTemp); cTemp.cInstruction=COP_NULL; cTemp.cData.cuValid=CV_COMMENT|CV_OPERATOR|CV_COMMA|CV_SEMI|CV_CRBRAC; COMPILE_PUSH(&cTemp); cTemp.cData.cuState=CS_GET_NEXT+0x200; COMPILE_PUSH(&cTemp); COMPILE_UPSTACK(); cValid=CV_COMMENT|CV_FUNCT|CV_NUMBER|CV_ORBRAC|CV_VAR|CV_STRING|CV_OPERATOR; cState=CS_GET_NEXT; break; case CS_GET_NEXT+0x100+CRN_CRBRAC: /* cVarFlag is set. We just adjust cExpFlag to reflect ()'s and exit */ cExpFlag=(cExpFlag|CEFLAG_LVALUE|CEFLAG_FUNCT) -(CEFLAG_LVALUE|CEFLAG_FUNCT); /* ie: since there's ()'s around it, it can't be funct, lvalue, exp.*/ COMPILE_DOWNSTACK(); /* and return to our caller */ COMPILE_PULL(&cTemp); cState=cTemp.cData.cuState; COMPILE_PULL(&cTemp); cValid=cTemp.cData.cuValid; break; case CS_GET_NEXT+0x200+CRN_OPERATOR: /* process uniary operator */ case CS_GET_NEXT+0x200+CRN_SEMI: case CS_GET_NEXT+0x200+CRN_COMMA: case CS_GET_NEXT+0x200+CRN_CRBRAC: COMPILE_GETLASTSRC(); /* whoah! backup! */ COMPILE_PULL(&cTemp); /* get instruction */ if ((cTemp.cInstruction==COP_BSUB)|| (cTemp.cInstruction==COP_BADD)) { /* we need an lvalue for these */ if (!(cExpFlag&CEFLAG_LVALUE)) { /* no lvalue! AAAAA */ sprintf(cError,"compile error: modifiable lvalue (ie a variable) is needed to use ++ or --\n"); CompileErrorReport(cError); return(COMPILE_SYNTAX_ERROR); } } /* modify cExpFlag - it can't be any of these: */ cExpFlag=(cExpFlag|CEFLAG_EXP|CEFLAG_LVALUE|CEFLAG_FUNCT) -(CEFLAG_EXP|CEFLAG_LVALUE|CEFLAG_FUNCT); cExpFlag|=CEFLAG_EXP; COMPILE_COMPILE(&cTemp); /* compile unary operator */ COMPILE_DOWNSTACK(); /* and return to our caller */ COMPILE_PULL(&cTemp); cState=cTemp.cData.cuState; COMPILE_PULL(&cTemp); cValid=cTemp.cData.cuValid; break; /* default: this state handles comments, or should never occur */ default: if ((cState & 0xFF)==CRN_COMMENT) { /* catch-all comment routine */ COMPILE_COMPILECOMMENT(cLabel); cState=cState&0xFFFFFF00; } else { sprintf(cError,"internal error (compile.c): Unknown state 0x%08lX\nRecord this message and your program, and notify your Sys Admin.\n",cState); CompileErrorReport(cError); return(COMPILE_INTERNAL_ERROR); } break; } /* State machine switch */ } /* State machine while(1) loop */ } /* Compile */ /* CompileInit * Initializes all structures required by Compile.c */ void CompileInit() { ULWORD i; ULWORD cOffset; /* allocate our stack */ cStackSizeByte=CSTACK_SIZE; /* default stack size */ MALLOC((void *)cStack,BYTE,cStackSizeByte); /* allocate our stack frame */ cSFPSizeByte=CSTACK_FRAME; /* default stack frame size */ MALLOC((void *)cSFP,BYTE,cSFPSizeByte); /* allocate our compile buffer (where the binary code is stored) */ cCompBufSizeByte=CCODE_SIZE; /* default buffer size */ MALLOC((void *)cCompBuf,BYTE,cCompBufSizeByte); /* generate our global variable tables */ cOffset=0; for (i=0;i<=cSystemVariable;i++) { if (cSysVar[i].cText!=NULL) { strcpy(cVarTable[cOffset].cText,cSysVar[i].cText); cVarTable[cOffset].cType=cSysVar[i].cType; cVarTable[cOffset].cDomain=CDOMAIN_LOCAL; cVarTable[cOffset].cOffset=cOffset; cOffset++; } } }