Example #1
0
/* ParseReturn - parse the 'RETURN' statement */
static void ParseReturn(ParseContext *c)
{
    Token tkn;
    if ((tkn = GetToken(c)) == T_EOL) {
        putcbyte(c, OP_LIT);
        putcword(c, 0);
    }
    else {
        SaveToken(c, tkn);
        ParseRValue(c);
        FRequire(c, T_EOL);
    }
    putcbyte(c, OP_RETURN);
}
Example #2
0
/* ParseGoto - parse the 'GOTO' statement */
static void ParseGoto(ParseContext *c)
{
    FRequire(c, T_IDENTIFIER);
    putcbyte(c, OP_BR);
    putcword(c, ReferenceLabel(c, c->token, codeaddr(c)));
    FRequire(c, T_EOL);
}
Example #3
0
/* ParseDoUntil - parse the 'DO UNTIL' statement */
static void ParseDoUntil(ParseContext *c)
{
    PushBlock(c);
    c->bptr->type = BLOCK_DO;
    c->bptr->u.DoBlock.nxt = codeaddr(c);
    ParseRValue(c);
    putcbyte(c, OP_BRT);
    c->bptr->u.DoBlock.end = putcword(c, 0);
    FRequire(c, T_EOL);
}
Example #4
0
/* ParseElseIf - parse the 'ELSE IF' statement */
static void ParseElseIf(ParseContext *c)
{
    switch (CurrentBlockType(c)) {
    case BLOCK_IF:
        putcbyte(c, OP_BR);
        c->bptr->u.IfBlock.end = putcword(c, c->bptr->u.IfBlock.end);
        fixupbranch(c, c->bptr->u.IfBlock.nxt, codeaddr(c));
        c->bptr->u.IfBlock.nxt = 0;
        ParseRValue(c);
        FRequire(c, T_THEN);
        putcbyte(c, OP_BRF);
        c->bptr->u.IfBlock.nxt = putcword(c, 0);
        FRequire(c, T_EOL);
        break;
    default:
        ParseError(c, "ELSE IF without a matching IF");
        break;
    }
}
Example #5
0
/* 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;
}
Example #6
0
/* CallHandler - compile a call to a runtime print function */
static void CallHandler(ParseContext *c, char *name, ParseTreeNode *expr)
{
    Symbol *sym;
    
    /* find the built-in function */
    if (!(sym = FindSymbol(&c->globals, name)))
        ParseError(c, "undefined print function: %s", name);
        
    /* compile the function symbol reference */
    putcbyte(c, OP_LIT);
    putcword(c, sym->value);

    /* compile the argument */
    if (expr)
        code_rvalue(c, expr);
    
    /* call the function */
    putcbyte(c, OP_CALL);
    putcbyte(c, (expr ? 1 : 0));
    putcbyte(c, OP_DROP);
}
Example #7
0
/* StartCode - start a function or method under construction */
void StartCode(ParseContext *c, CodeType type)
{
    /* all methods must precede the main code */
    if (type != CODE_TYPE_MAIN && c->codeFree > c->codeBuf)
        ParseError(c, "subroutines and functions must precede the main code");

    /* don't allow nested functions or subroutines (for now anyway) */
    if (type != CODE_TYPE_MAIN && c->codeType != CODE_TYPE_MAIN)
        ParseError(c, "nested subroutines and functions are not supported");

    /* initialize the code object under construction */
    InitSymbolTable(&c->arguments);
    InitSymbolTable(&c->locals);
    c->localOffset = 0;
    c->codeType = type;
    
    /* write the code prolog */
    if (type != CODE_TYPE_MAIN) {
        putcbyte(c, OP_FRAME);
        putcbyte(c, 0);
    }
}
Example #8
0
/* ParseFor - parse the 'FOR' statement */
static void ParseFor(ParseContext *c)
{
    ParseTreeNode *var, *step;
    int test, body, inst;
    Token tkn;
    PVAL pv;

    PushBlock(c);
    c->bptr->type = BLOCK_FOR;

    /* get the control variable */
    FRequire(c, T_IDENTIFIER);
    var = GetSymbolRef(c, c->token);
    code_lvalue(c, var, &pv);
    FRequire(c, '=');

    /* parse the starting value expression */
    ParseRValue(c);

    /* parse the TO expression and generate the loop termination test */
    test = codeaddr(c);
    (*pv.fcn)(c, PV_STORE, &pv);
    (*pv.fcn)(c, PV_LOAD, &pv);
    FRequire(c, T_TO);
    ParseRValue(c);
    putcbyte(c, OP_LE);
    putcbyte(c, OP_BRT);
    body = putcword(c, 0);

    /* branch to the end if the termination test fails */
    putcbyte(c, OP_BR);
    c->bptr->u.ForBlock.end = putcword(c, 0);

    /* update the for variable after an iteration of the loop */
    c->bptr->u.ForBlock.nxt = codeaddr(c);
    (*pv.fcn)(c, PV_LOAD, &pv);

    /* get the STEP expression */
    if ((tkn = GetToken(c)) == T_STEP) {
        step = ParseExpr(c);
        code_rvalue(c, step);
        tkn = GetToken(c);
    }

    /* no step so default to one */
    else {
        putcbyte(c, OP_LIT);
        putcword(c, 1);
    }

    /* generate the increment code */
    putcbyte(c, OP_ADD);
    inst = putcbyte(c, OP_BR);
    putcword(c, test - inst - 1 - sizeof(VMUVALUE));

    /* branch to the loop body */
    fixupbranch(c, body, codeaddr(c));
    Require(c, tkn, T_EOL);
}
Example #9
0
/* ParseLoop - parse the 'LOOP' statement */
static void ParseLoop(ParseContext *c)
{
    int inst;
    switch (CurrentBlockType(c)) {
    case BLOCK_DO:
        inst = putcbyte(c, OP_BR);
        putcword(c, c->bptr->u.DoBlock.nxt - inst - 1 - sizeof(VMUVALUE));
        fixupbranch(c, c->bptr->u.DoBlock.end, codeaddr(c));
        PopBlock(c);
        break;
    default:
        ParseError(c, "LOOP without a matching DO");
        break;
    }
    FRequire(c, T_EOL);
}
Example #10
0
/* ParseElse - parse the 'ELSE' statement */
static void ParseElse(ParseContext *c)
{
    int end;
    switch (CurrentBlockType(c)) {
    case BLOCK_IF:
        putcbyte(c, OP_BR);
        end = putcword(c, c->bptr->u.IfBlock.end);
        fixupbranch(c, c->bptr->u.IfBlock.nxt, codeaddr(c));
        c->bptr->type = BLOCK_ELSE;
        c->bptr->u.ElseBlock.end = end;
        break;
    default:
        ParseError(c, "ELSE without a matching IF");
        break;
    }
    FRequire(c, T_EOL);
}
Example #11
0
/* ParseIf - parse the 'IF' statement */
static void ParseIf(ParseContext *c)
{
    Token tkn;
    ParseRValue(c);
    FRequire(c, T_THEN);
    PushBlock(c);
    c->bptr->type = BLOCK_IF;
    putcbyte(c, OP_BRF);
    c->bptr->u.IfBlock.nxt = putcword(c, 0);
    c->bptr->u.IfBlock.end = 0;
    if ((tkn = GetToken(c)) != T_EOL) {
        ParseStatement(c, tkn);
        fixupbranch(c, c->bptr->u.IfBlock.nxt, codeaddr(c));
        PopBlock(c);
    }
    else
        Require(c, tkn, T_EOL);
}
Example #12
0
/* ParseImpliedLetOrFunctionCall - parse an implied let statement or a function call */
static void ParseImpliedLetOrFunctionCall(ParseContext *c)
{
    ParseTreeNode *expr;
    Token tkn;
    PVAL pv;
    expr = ParsePrimary(c);
    switch (tkn = GetToken(c)) {
    case '=':
        code_lvalue(c, expr, &pv);
        ParseRValue(c);
        (*pv.fcn)(c, PV_STORE, &pv);
        break;
    default:
        SaveToken(c, tkn);
        code_rvalue(c, expr);
        putcbyte(c, OP_DROP);
        break;
    }
    FRequire(c, T_EOL);
}
Example #13
0
/* ParseNext - parse the 'NEXT' statement */
static void ParseNext(ParseContext *c)
{
    ParseTreeNode *var;
    int inst;
    switch (CurrentBlockType(c)) {
    case BLOCK_FOR:
        FRequire(c, T_IDENTIFIER);
        var = GetSymbolRef(c, c->token);
        /* BUG: check to make sure it matches the symbol used in the FOR */
        inst = putcbyte(c, OP_BR);
        putcword(c, c->bptr->u.ForBlock.nxt - inst - 1 - sizeof(VMUVALUE));
        fixupbranch(c, c->bptr->u.ForBlock.end, codeaddr(c));
        PopBlock(c);
        break;
    default:
        ParseError(c, "NEXT without a matching FOR");
        break;
    }
    FRequire(c, T_EOL);
}
Example #14
0
/* 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;
}
Example #15
0
/* 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;
}
Example #16
0
/* ParseStop - parse the 'STOP' statement */
static void ParseStop(ParseContext *c)
{
    putcbyte(c, OP_HALT);
    FRequire(c, T_EOL);
}
Example #17
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;
}