static void DoLoad(System *sys) { VMFILE *fp; /* check for a program name on the command line */ if (!SetProgramName(sys)) { VM_printf("expecting a file name\n"); return; } /* load the program */ if (!(fp = VM_fopen(programName, "r"))) VM_printf("error loading '%s'\n", programName); else { VM_printf("Loading '%s'\n", programName); BufInit(); while (VM_fgets(sys->lineBuf, sizeof(sys->lineBuf), fp) != NULL) { int len = strlen(sys->lineBuf); VMVALUE lineNumber; char *token; sys->linePtr = sys->lineBuf; if ((token = NextToken(sys)) != NULL) { if (ParseNumber(token, &lineNumber)) BufAddLineN(lineNumber, sys->linePtr); else VM_printf("expecting a line number: %s\n", token); } } VM_fclose(fp); } }
static void DoSave(System *sys) { VMFILE *fp; /* check for a program name on the command line */ if (!SetProgramName(sys)) { VM_printf("expecting a file name\n"); return; } /* save the program */ if (!(fp = VM_fopen(programName, "w"))) VM_printf("error saving '%s'\n", programName); else { VMVALUE lineNumber; VM_printf("Saving '%s'\n", programName); BufSeekN(0); while (BufGetLine(&lineNumber, sys->lineBuf)) { char buf[32]; sprintf(buf, "%d ", lineNumber); VM_fputs(buf, fp); VM_fputs(sys->lineBuf, fp); } VM_fclose(fp); } }
/* StoreCode - store the function or method under construction */ void StoreCode(ParseContext *c) { int codeSize; /* check for unterminated blocks */ switch (CurrentBlockType(c)) { case BLOCK_IF: case BLOCK_ELSE: ParseError(c, "expecting END IF"); case BLOCK_FOR: ParseError(c, "expecting NEXT"); case BLOCK_DO: ParseError(c, "expecting LOOP"); case BLOCK_NONE: break; } /* fixup the RESERVE instruction at the start of the code */ if (c->codeType != CODE_TYPE_MAIN) { c->codeBuf[1] = c->localOffset; putcbyte(c, OP_RETURN); } /* make sure all referenced labels were defined */ CheckLabels(c); /* place string literals defined in this function */ PlaceStrings(c); /* determine the code size */ codeSize = (int)(c->cptr - c->codeBuf); #if 0 VM_printf("%s:\n", c->codeName); DecodeFunction((uint8_t *)c->image, (c->image->objectDataSize + GetObjSizeInWords(sizeof(VectorObjectHdr))) * sizeof(VMVALUE), c->codeBuf, codeSize); DumpSymbols(&c->arguments, "arguments"); DumpSymbols(&c->locals, "locals"); VM_printf("\n"); #endif /* store the vector object */ StoreBVectorData(c, c->code, PROTO_CODE, c->codeBuf, codeSize); /* empty the local heap */ c->nextLocal = c->sys->freeTop; InitSymbolTable(&c->arguments); InitSymbolTable(&c->locals); c->labels = NULL; /* reset to compile the next code */ c->codeType = CODE_TYPE_MAIN; c->cptr = c->codeBuf; }
static void DoList(System *sys) { VMVALUE lineNumber; BufSeekN(0); while (BufGetLine(&lineNumber, sys->lineBuf)) VM_printf("%d %s", lineNumber, sys->lineBuf); }
int main(int argc, char *argv[]) { VMVALUE lineNumber = 0; HandlerData data; ImageHdr *image; System *sys; VM_printf("ebasic 0.003\n"); VM_sysinit(argc, argv); sys = InitSystem(space, sizeof(space)); sys->getLine = TermGetLine; sys->getLineCookie = &lineNumber; if (!(image = AllocateImage(sys, IMAGESIZE))) return 1; sys->freeMark = sys->freeNext; data.sys = sys; data.image = image; EditWorkspace(sys, userCmds, (Handler *)CompileAndExecute, &data); return 0; }
/* ParseError - report a parsing error */ void ParseError(ParseContext *c, char *fmt, ...) { va_list ap; /* print the error message */ va_start(ap, fmt); VM_printf("error: "); VM_vprintf(fmt, ap); VM_putchar('\n'); va_end(ap); /* show the context */ VM_printf(" line %d\n", c->lineNumber); VM_printf(" %s\n", c->sys->lineBuf); VM_printf(" %*s\n", c->tokenOffset, "^"); /* exit until we fix the compiler so it can recover from parse errors */ longjmp(c->errorTarget, 1); }
/* Fatal - report a fatal error and exit */ void Fatal(ParseContext *c, char *fmt, ...) { va_list ap; va_start(ap, fmt); VM_printf("error: "); VM_vprintf(fmt, ap); VM_putchar('\n'); va_end(ap); longjmp(c->errorTarget, 1); }
void ShowStack(Interpreter *i) { VMHANDLE *hp; VMVALUE *p; for (hp = (VMHANDLE *)i->stack; hp <= i->hsp; ++hp) { if (hp == i->hfp) VM_printf(str_hfp_tag); VM_printf(str_hstack_entry_fmt, (VMUVALUE)*hp); } VM_printf(str_stack_separator); for (p = i->sp; p < i->stackTop; ++p) { if (p == i->fp) VM_printf(str_fp_tag); VM_printf(str_stack_entry, *p); } VM_putchar('\n'); }
void EditWorkspace(System *sys) { VMVALUE lineNumber; char *token; BufInit(); VM_printf("ebasic 0.001\n"); for (;; ) { VM_getline(sys->lineBuf, sizeof(sys->lineBuf)); sys->linePtr = sys->lineBuf; if ((token = NextToken(sys)) != NULL) { if (ParseNumber(token, &lineNumber)) { if (IsBlank(sys->linePtr)) { if (!BufDeleteLineN(lineNumber)) VM_printf("no line %d\n", lineNumber); } else if (!BufAddLineN(lineNumber, sys->linePtr)) VM_printf("out of edit buffer space\n"); } else { int i; for (i = 0; cmds[i].name != NULL; ++i) if (strcasecmp(token, cmds[i].name) == 0) break; if (cmds[i].handler) { (*cmds[i].handler)(sys); VM_printf("OK\n"); } else VM_printf("unknown command: %s\n", token); } } } }
static void DoRun(System *sys) { ParseContext *c; sys->freeNext = sys->freeSpace; if (!(c = InitCompiler(sys, MAXOBJECTS))) VM_printf("insufficient memory\n"); else { ImageHdr *image; BufSeekN(0); c->getLine = EditGetLine; if ((image = Compile(c)) != NULL) { Interpreter *i = (Interpreter *)sys->freeNext; size_t stackSize = (sys->freeTop - sys->freeNext - sizeof(Interpreter)) / sizeof(VMVALUE); if (stackSize <= 0) VM_printf("insufficient memory\n"); else { InitInterpreter(i, stackSize); Execute(i, image); } } } }
static void DoCat(System *sys) { VMDIRENT entry; VMDIR dir; if (VM_opendir(".", &dir) == 0) { while (VM_readdir(&dir, &entry) == 0) { int len = strlen(entry.name); if (len >= 4 && strcasecmp(&entry.name[len - 4], ".bas") == 0) VM_printf(" %s\n", entry.name); } VM_closedir(&dir); } }
void Abort(ParseContext *c, const char *fmt, ...) { char buf[100], *p = buf; va_list ap; va_start(ap, fmt); VM_printf("error: "); vsnprintf(buf, sizeof(buf), fmt, ap); while (*p != '\0') VM_putchar(*p++); VM_putchar('\n'); va_end(ap); longjmp(c->errorTarget, 1); }
/* 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; }
/* StoreCode - store the function or method under construction */ VMVALUE StoreCode(ParseContext *c) { size_t codeSize; VMVALUE code; uint8_t *p; /* check for unterminated blocks */ switch (CurrentBlockType(c)) { case BLOCK_IF: case BLOCK_ELSE: ParseError(c, "expecting END IF"); case BLOCK_FOR: ParseError(c, "expecting NEXT"); case BLOCK_DO: ParseError(c, "expecting LOOP"); case BLOCK_NONE: break; } /* fixup the RESERVE instruction at the start of the code */ if (c->codeType != CODE_TYPE_MAIN) { c->codeBuf[1] = 2 + c->localOffset; putcbyte(c, OP_RETURN); } /* make sure all referenced labels were defined */ CheckLabels(c); /* allocate code space */ codeSize = (int)(c->codeFree - c->codeBuf); p = (uint8_t *)ImageTextAlloc(c, codeSize); memcpy(p, c->codeBuf, codeSize); /* get the address of the compiled code */ code = (VMVALUE)(p - (uint8_t *)c->image); #ifdef COMPILER_DEBUG { VM_printf("%s:\n", c->codeSymbol ? c->codeSymbol->name : "<main>"); DecodeFunction((uint8_t *)c->image, (uint8_t *)c->image + code, codeSize); DumpSymbols(&c->arguments, "arguments"); DumpSymbols(&c->locals, "locals"); VM_printf("\n"); } #endif /* prepare the buffer for the next function */ c->codeFree = c->codeBuf; /* empty the local heap */ c->localFree = c->heapBase; InitSymbolTable(&c->arguments); InitSymbolTable(&c->locals); c->labels = NULL; /* reset to compile the next code */ c->codeType = CODE_TYPE_MAIN; /* return the code vector */ return code; }