/* ParseDef - parse the 'DEF' statement */ static void ParseDef(ParseContext *c) { char name[MAXTOKEN]; Token tkn; /* get the name being defined */ FRequire(c, T_IDENTIFIER); strcpy(name, c->token); /* check for a constant definition */ if ((tkn = GetToken(c)) == '=') ParseConstantDef(c, name); /* otherwise, assume a function definition */ else { Symbol *sym; /* save the lookahead token */ SaveToken(c, tkn); /* enter the function name in the global symbol table */ sym = AddGlobal(c, name, SC_CONSTANT, 0, 0); /* start the code under construction */ StartCode(c, sym->name, CODE_TYPE_FUNCTION); sym->value = c->code; /* get the argument list */ if ((tkn = GetToken(c)) == '(') { if ((tkn = GetToken(c)) != ')') { int offset = 1; SaveToken(c, tkn); do { FRequire(c, T_IDENTIFIER); AddArgument(c, c->token, SC_VARIABLE, offset); ++offset; } while ((tkn = GetToken(c)) == ','); } Require(c, tkn, ')'); } else SaveToken(c, tkn); } FRequire(c, T_EOL); }
/* Execute - execute the main code */ int Execute(System *sys, ObjHeap *heap, VMHANDLE main) { size_t stackSize; Interpreter *i; VMVALUE tmp, tmp2, ind; VMHANDLE obj, htmp; int8_t tmpb; /* allocate the interpreter state */ if (!(i = (Interpreter *)AllocateFreeSpace(sys, sizeof(Interpreter)))) return VMFALSE; /* make sure there is space left for the stack */ if ((stackSize = (sys->freeTop - sys->freeNext) / sizeof(VMVALUE)) <= 0) return VMFALSE; /* setup the heap before/after compact functions */ heap->beforeCompact = NULL; heap->afterCompact = AfterCompact; heap->compactCookie = i; /* initialize the interpreter state */ i->sys = sys; i->heap = heap; i->stack = (VMVALUE *)((uint8_t *)i + sizeof(Interpreter)); i->stackTop = i->stack + stackSize; /* setup to execute the main function */ i->code = main; ObjAddRef(i->code); i->cbase = i->pc = GetCodePtr(main); i->sp = i->fp = i->stackTop; i->hsp = i->hfp = (VMHANDLE *)i->stack - 1; if (setjmp(i->sys->errorTarget)) { while (i->hsp > (VMHANDLE *)i->stack) ObjRelease(i->heap, PopH(i)); ObjRelease(i->heap, i->code); return VMFALSE; } for (;;) { #if 0 ShowStack(i); DecodeInstruction(0, 0, i->pc); #endif switch (VMCODEBYTE(i->pc++)) { case OP_HALT: return VMTRUE; case OP_BRT: get_VMVALUE(tmp, VMCODEBYTE(i->pc++)); if (Pop(i)) i->pc += tmp; break; case OP_BRTSC: get_VMVALUE(tmp, VMCODEBYTE(i->pc++)); if (*i->sp) i->pc += tmp; else Drop(i, 1); break; case OP_BRF: get_VMVALUE(tmp, VMCODEBYTE(i->pc++)); if (!Pop(i)) i->pc += tmp; break; case OP_BRFSC: get_VMVALUE(tmp, VMCODEBYTE(i->pc++)); if (!*i->sp) i->pc += tmp; else Drop(i, 1); break; case OP_BR: get_VMVALUE(tmp, VMCODEBYTE(i->pc++)); i->pc += tmp; break; case OP_NOT: *i->sp = (*i->sp ? VMFALSE : VMTRUE); break; case OP_NEG: *i->sp = -*i->sp; break; case OP_ADD: tmp = Pop(i); *i->sp += tmp; break; case OP_SUB: tmp = Pop(i); *i->sp -= tmp; break; case OP_MUL: tmp = Pop(i); *i->sp *= tmp; break; case OP_DIV: tmp = Pop(i); *i->sp = (tmp == 0 ? 0 : *i->sp / tmp); break; case OP_REM: tmp = Pop(i); *i->sp = (tmp == 0 ? 0 : *i->sp % tmp); break; case OP_CAT: StringCat(i); break; case OP_BNOT: *i->sp = ~*i->sp; break; case OP_BAND: tmp = Pop(i); *i->sp &= tmp; break; case OP_BOR: tmp = Pop(i); *i->sp |= tmp; break; case OP_BXOR: tmp = Pop(i); *i->sp ^= tmp; break; case OP_SHL: tmp = Pop(i); *i->sp <<= tmp; break; case OP_SHR: tmp = Pop(i); *i->sp >>= tmp; break; case OP_LT: tmp = Pop(i); *i->sp = (*i->sp < tmp ? VMTRUE : VMFALSE); break; case OP_LE: tmp = Pop(i); *i->sp = (*i->sp <= tmp ? VMTRUE : VMFALSE); break; case OP_EQ: tmp = Pop(i); *i->sp = (*i->sp == tmp ? VMTRUE : VMFALSE); break; case OP_NE: tmp = Pop(i); *i->sp = (*i->sp != tmp ? VMTRUE : VMFALSE); break; case OP_GE: tmp = Pop(i); *i->sp = (*i->sp >= tmp ? VMTRUE : VMFALSE); break; case OP_GT: tmp = Pop(i); *i->sp = (*i->sp > tmp ? VMTRUE : VMFALSE); break; case OP_LIT: get_VMVALUE(tmp, VMCODEBYTE(i->pc++)); CPush(i, tmp); break; case OP_GREF: get_VMVALUE(tmp, VMCODEBYTE(i->pc++)); obj = (VMHANDLE)tmp; CPush(i, GetSymbolPtr(obj)->v.iValue); break; case OP_GSET: get_VMVALUE(tmp, VMCODEBYTE(i->pc++)); obj = (VMHANDLE)tmp; GetSymbolPtr(obj)->v.iValue = Pop(i); break; case OP_LREF: tmpb = (int8_t)VMCODEBYTE(i->pc++); CPush(i, i->fp[(int)tmpb]); break; case OP_LSET: tmpb = (int8_t)VMCODEBYTE(i->pc++); i->fp[(int)tmpb] = Pop(i); break; case OP_VREF: ind = *i->sp; obj = *i->hsp; if (ind < 0 || ind >= GetHeapObjSize(obj)) Abort(i->sys, str_subscript_err, ind); *i->sp = GetIntegerVectorBase(obj)[ind]; DropH(i, 1); break; case OP_VSET: tmp2 = Pop(i); ind = Pop(i); obj = *i->hsp; if (ind < 0 || ind >= GetHeapObjSize(obj)) Abort(i->sys, str_subscript_err, ind); GetIntegerVectorBase(obj)[ind] = tmp2; DropH(i, 1); break; case OP_LITH: get_VMVALUE(tmp, VMCODEBYTE(i->pc++)); CPushH(i, (VMHANDLE)tmp); ObjAddRef(*i->hsp); break; case OP_GREFH: get_VMVALUE(tmp, VMCODEBYTE(i->pc++)); CPushH(i, GetSymbolPtr((VMHANDLE)tmp)->v.hValue); ObjAddRef(*i->hsp); break; case OP_GSETH: get_VMVALUE(tmp, VMCODEBYTE(i->pc++)); ObjRelease(i->heap, GetSymbolPtr((VMHANDLE)tmp)->v.hValue); GetSymbolPtr((VMHANDLE)tmp)->v.hValue = PopH(i); break; case OP_LREFH: tmpb = (int8_t)VMCODEBYTE(i->pc++); CPushH(i, i->hfp[(int)tmpb]); ObjAddRef(*i->hsp); break; case OP_LSETH: tmpb = (int8_t)VMCODEBYTE(i->pc++); ObjRelease(i->heap, i->hfp[(int)tmpb]); i->hfp[(int)tmpb] = PopH(i); break; case OP_VREFH: ind = Pop(i); obj = *i->hsp; if (ind < 0 || ind >= GetHeapObjSize(obj)) Abort(i->sys, str_subscript_err, ind); *i->hsp = GetStringVectorBase(obj)[ind]; ObjAddRef(*i->hsp); break; case OP_VSETH: htmp = PopH(i); ind = Pop(i); obj = *i->hsp; if (ind < 0 || ind >= GetHeapObjSize(obj)) Abort(i->sys, str_subscript_err, ind); ObjRelease(i->heap, GetStringVectorBase(obj)[ind]); GetStringVectorBase(obj)[ind] = htmp; DropH(i, 1); break; case OP_RESERVE: tmp = VMCODEBYTE(i->pc++); tmp2 = VMCODEBYTE(i->pc++); Reserve(i, tmp); ReserveH(i, tmp2); break; case OP_CALL: StartCode(i); break; case OP_RETURN: tmp = *i->sp; PopFrame(i); Push(i, tmp); break; case OP_RETURNH: htmp = *i->hsp; PopFrame(i); PushH(i, htmp); break; case OP_RETURNV: PopFrame(i); break; case OP_DROP: Drop(i, 1); break; case OP_DROPH: ObjRelease(i->heap, *i->hsp); DropH(i, 1); break; default: Abort(i->sys, str_opcode_err, VMCODEBYTE(i->pc - 1)); break; } } }
/* Compile - compile a program */ ImageHdr *Compile(ParseContext *c) { System *sys = c->sys; ImageHdr *image = c->image; size_t maxHeapUsed = c->maxHeapUsed; VMVALUE *variables; VMUVALUE totalSize; Symbol *sym; /* setup an error target */ if (setjmp(c->errorTarget) != 0) return NULL; /* initialize the scratch buffer */ BufRewind(); /* allocate space for the object table */ image->objectCount = 0; image->objectDataSize = 0; /* use the rest of the free space for the compiler heap */ c->nextGlobal = sys->freeNext; c->nextLocal = sys->freeTop; c->heapSize = sys->freeTop - sys->freeNext; c->maxHeapUsed = 0; /* initialize the global variable count */ image->variableCount = 0; /* initialize block nesting table */ c->btop = (Block *)((char *)c->blockBuf + sizeof(c->blockBuf)); c->bptr = c->blockBuf - 1; /* initialize the code staging buffer */ c->ctop = c->codeBuf + sizeof(c->codeBuf); c->cptr = c->codeBuf; /* initialize the string and label tables */ c->strings = NULL; c->labels = NULL; /* start in the main code */ c->codeType = CODE_TYPE_MAIN; /* initialize the global symbol table */ InitSymbolTable(&c->globals); /* add the intrinsic functions */ AddIntrinsic(c, "ABS", FN_ABS); AddIntrinsic(c, "RND", FN_RND); AddIntrinsic(c, "printStr", FN_printStr); AddIntrinsic(c, "printInt", FN_printInt); AddIntrinsic(c, "printTab", FN_printTab); AddIntrinsic(c, "printNL", FN_printNL); AddIntrinsic(c, "printFlush", FN_printFlush); #ifdef PROPELLER AddIntrinsic(c, "IN", FN_IN); AddIntrinsic(c, "OUT", FN_OUT); AddIntrinsic(c, "HIGH", FN_HIGH); AddIntrinsic(c, "LOW", FN_LOW); AddIntrinsic(c, "TOGGLE", FN_TOGGLE); AddIntrinsic(c, "DIR", FN_DIR); AddIntrinsic(c, "GETDIR", FN_GETDIR); AddIntrinsic(c, "CNT", FN_CNT); AddIntrinsic(c, "PAUSE", FN_PAUSE); AddIntrinsic(c, "PULSEIN", FN_PULSEIN); AddIntrinsic(c, "PULSEOUT", FN_PULSEOUT); #endif /* initialize scanner */ c->inComment = VMFALSE; /* get the next line */ while (GetLine(c)) { Token tkn; if ((tkn = GetToken(c)) != T_EOL) ParseStatement(c, tkn); } /* end the main code with a halt */ putcbyte(c, OP_HALT); /* write the main code */ StartCode(c, "main", CODE_TYPE_MAIN); image->mainCode = c->code; StoreCode(c); /* allocate the global variable table */ if (!(variables = (VMVALUE *)AllocateFreeSpace(sys, image->variableCount * sizeof(VMVALUE)))) ParseError(c, "insufficient space for variable table"); /* store the initial values of the global variables */ for (sym = c->globals.head; sym != NULL; sym = sym->next) { if (!(sym->value & INTRINSIC_FLAG)) variables[sym->value] = sym->initialValue; } /* write out the variable and object tables */ if (!BufWriteWords(variables, image->variableCount) || !BufWriteWords(image->objects, image->objectCount)) ParseError(c, "insufficient scratch space"); /* free up the space the compiler was consuming */ sys->freeNext = c->freeMark; /* allocate space for the object data and variables */ totalSize = (image->objectDataSize + image->variableCount + image->objectCount) * sizeof(VMVALUE); if (!(image->objectData = (VMVALUE *)AllocateFreeSpace(sys, totalSize))) ParseError(c, "insufficient space for objects and variables"); image->variables = image->objectData + image->objectDataSize; image->objects = image->variables + image->variableCount; /* read the object data and variables from the scratch buffer */ BufRewind(); if (!BufReadWords(image->objectData, totalSize)) ParseError(c, "error reading objects and variables"); { int objectTableSize = image->objectCount * sizeof(VMVALUE); int objectDataSize = image->objectDataSize * sizeof(VMVALUE); int dataSize = objectTableSize + objectDataSize + image->variableCount * sizeof(VMVALUE); #if 0 DumpSymbols(&c->globals, "symbols"); #endif VM_printf("H:%d", maxHeapUsed); VM_printf(" O:%d", image->objectCount); VM_printf(" D:%d", objectDataSize); VM_printf(" V:%d", image->variableCount); VM_printf(" T:%d\n", dataSize); } /* return the image */ return image; }
/* Compile - compile a program */ int Compile(ParseContext *c, uint8_t *imageSpace, size_t imageSize, size_t textMax, size_t dataMax) { ImageHdr *image = (ImageHdr *)imageSpace; VMUVALUE textSize; /* setup an error target */ if (setjmp(c->errorTarget) != 0) return -1; /* initialize the image */ if (imageSize < sizeof(ImageHdr) + textMax + dataMax) return -1; memset(image, 0, sizeof(ImageHdr)); c->image = image; /* empty the heap */ c->localFree = c->heapBase; c->globalFree = c->heapTop; /* initialize the image */ c->textBase = c->textFree = imageSpace + sizeof(ImageHdr); c->textTop = c->textBase + textMax; c->dataBase = c->dataFree = c->textBase + textMax; c->dataTop = c->dataBase + dataMax; /* initialize the code buffer */ c->codeFree = c->codeBuf; c->codeTop = c->codeBuf + sizeof(c->codeBuf); /* initialize block nesting table */ c->btop = (Block *)((char *)c->blockBuf + sizeof(c->blockBuf)); c->bptr = c->blockBuf - 1; /* initialize the global symbol table and string table */ InitSymbolTable(&c->globals); /* enter the built-in functions */ EnterBuiltInFunction(c, "delayMs", bi_delayms, sizeof(bi_delayms)); EnterBuiltInFunction(c, "updateLeds", bi_updateleds, sizeof(bi_updateleds)); /* enter the built-in variables */ /* typedef struct { int32_t triggerTop; int32_t triggerBottom; int32_t numLeds; int32_t led[RGB_SIZE]; int32_t patternnum; } VM_variables; */ EnterBuiltInVariable(c, "triggerTop", sizeof(VMVALUE)); EnterBuiltInVariable(c, "triggerBottom", sizeof(VMVALUE)); EnterBuiltInVariable(c, "numLeds", sizeof(VMVALUE)); EnterBuiltInVariable(c, "led", sizeof(VMVALUE) * RGB_SIZE); EnterBuiltInVariable(c, "patternNum", sizeof(VMVALUE)); /* initialize the string table */ c->strings = NULL; /* initialize the label table */ c->labels = NULL; /* start in the main code */ c->codeType = CODE_TYPE_MAIN; /* initialize scanner */ c->inComment = VMFALSE; c->lineNumber = 0; /* compile each line */ while (GetLine(c)) { int tkn; if ((tkn = GetToken(c)) != T_EOL) ParseStatement(c, tkn); } /* end the main code with a halt */ putcbyte(c, OP_HALT); /* write the main code */ StartCode(c, CODE_TYPE_MAIN); image->entry = StoreCode(c); /* determine the text size */ textSize = c->textFree - c->textBase; /* fill in the image header */ image->dataOffset = sizeof(ImageHdr) + textSize; image->dataSize = c->dataFree - c->dataBase; image->imageSize = image->dataOffset + image->dataSize; /* make the data contiguous with the code */ memcpy(&imageSpace[image->dataOffset], c->dataBase, image->dataSize); #ifdef COMPILER_DEBUG VM_printf("entry "); PrintValue(image->entry); VM_printf("\n"); VM_printf("imageSize "); PrintValue(image->imageSize); VM_printf("\n"); VM_printf("textSize "); PrintValue(textSize); VM_printf("\n"); VM_printf("dataOffset "); PrintValue(image->dataOffset); VM_printf("\n"); VM_printf("dataSize "); PrintValue(image->dataSize); VM_printf("\n"); DumpSymbols(&c->globals, "symbols"); #endif /* return successfully */ return 0; }