void Compiler::scanFor(){ if(!cg->isCompiling()) error("can only use 'for' inside a function/procedure"); if(tok->getnext()!=T_IDENT) error("expected an identifier after 'for'"); // output the index variable emitVariableRef(tok->getstring()); if(tok->getnext()!=T_IN) error("expected 'in' after 'for' variable"); // output the expression if(scanExpr()) error("cannot use a function expression in 'for'"); cg->current->newloop(); // start loop and set continuelabel, // get that pointer because we're going to muck about with it LoopData *loop = cg->current->loopstack.peekptr(); // push the FOR *here* although we jump past it; we still need // to match with it and modify it for the jump forwards cg->current->cpushhere(); cg->emit(OP_FOR); // output FOR // modify the continue so it's *AFTER* the FOR. loop->continuelabel.set(cg->current->getlocptr()); }
int analyze_commandline(const std::vector<std::string> &argv) { int argc = argv.size(); // picosel from inputfile select col where col >= 1 and col < 2 size_t i = 1; while (i < argc) { std:: string argi = argv[i]; if (argi == "-o") { if (! (i + 1 < argc)) { std:: cerr << "error: option -o requires an argument" << std:: endl; return 1; } outputFile = argv[i + 1]; i += 2; } else if (argi == "from" || argi == "FROM") { if (! (i + 1 < argc)) { std:: cerr << "error: 'from' requires an argument" << std:: endl; return 1; } fromFile = argv[i + 1]; i += 2; } else if (argi == "select" || argi == "SELECT") { if (! (i + 1 < argc)) { std:: cerr << "error: 'select' requires an argument" << std:: endl; return 1; } selectCol = argv[i + 1]; i += 2; } else if (argi == "where" || argi == "WHERE" || argi == "order" || argi == "ORDER") { break; // for i } else if (argi == "-b") { if (! (i + 1 < argc)) { std:: cerr << "error: option -b requires an argument" << std:: endl; return 1; } binaryOutputFactor = boost::lexical_cast<long long>(argv[i + 1]); i += 2; } else { std:: cerr << "error: invalid command-line argument" << std:: endl; return 1; } } if (fromFile.empty()) { std:: cerr << "error: no input file is given" << std:: endl; return 1; } if (selectCol.empty()) { std:: cerr << "error: no column is selected" << std:: endl; return 1; } if (! (i < argc)) { return 0; } std:: string argi = argv[i]; if (argi == "ORDER" || argi == "order") { // order by column [asc|desc] // i i+1 i+2 i+3 if (! (i + 2 < argc)) { std:: cerr << "error: invaid expression" << std:: endl; return 1; } argi = argv[i + 1]; if (! (argi == "BY" || argi == "by")) { std:: cerr << "error: invaid expression" << std:: endl; return 1; } std:: string col = argv[i + 2]; if (i + 3 < argc) { argi = argv[i + 3]; if (argi == "ASC" || argi == "asc") { orderByAsc = col; } else if (argi == "DESC" || argi == "desc") { orderByDesc = col; } else { std:: cerr << "error: either 'asc' or 'desc' is expected" << std:: endl; return 1; } i += 3; if (i < argc) { std:: cerr << "error: too many parameters" << std:: endl; return 1; } } else { orderByAsc = col; } } else if (argi == "where" || argi == "WHERE") { ++i; std::string s; if (i < argc && (s = argv[i]).find(' ') != std::string::npos) { if (s.length() >= 2 && s[0] == '\"' && s[s.length() - 1] == '\"') { s = s.substr(1, s.length() - 2); // remove the quote's. } std::vector<std::string> exprArgs; boost::algorithm::split(exprArgs, s, boost::algorithm::is_space()); size_t index = 0; if (! scanExpr(&conditions, exprArgs, &index) || index != exprArgs.size()) { return 1; } } else { if (! scanExpr(&conditions, argv, &i)) { return 1; } } } else { std:: cerr << "error: either 'where' or 'order' is expected" << std:: endl; return 1; } if (binaryOutputFactor != 0) { if (outputFile.empty()) { std:: cerr << "error: option -b requires option -o" << std:: endl; return 1; } } return 0; }
void Compiler::scanStmt() { char buf[256]; // temporary buffer int t; switch(tok->getnext()){ case T_IDENT: // it's an expression case T_INT: case T_FLOAT: case T_SUB: case T_BITNOT: case T_PLING: case T_STRING: case T_BACKTICK: case T_OPREN: // deal with debugging words! if(!strcmp(tok->getstring(),"dumplocs")){ cg->emit(OP_SPECIAL,0);break; } if(!strcmp(tok->getstring(),"breakpoint")){ cg->emit(OP_SPECIAL,1);break; } tok->rewind(); // put the token back // scan the expression, might be a label if(!scanExpr(true)) // clear all statements if not a func or other oddity, // or just a dummy for recreation purposes if in immediate mode. cg->emit(cg->isCompiling()?OP_ENDESTMT:OP_ENDESTMT2); break; case T_LOAD: { if(cg->isCompiling()) error("can only run 'load' in interactive mode"); Session *s; if(tok->getnext()!=T_STRING) error("expected a string after 'load'"); try { s = new Session(ses->api); s->feedFile(tok->getstring()); } catch(Exception &e){ delete s; throw e; } delete s; } break; case T_SAVE: { if(cg->isCompiling()) error("can only run 'save' in interactive mode"); if(tok->getnext()!=T_STRING) error("expected a string after 'save'"); const char *fname = tok->getstring(); FILE *a; if(!strlen(fname)) a = stdout; else a = fopen(fname,"w"); if(!a) error("cannot open file '%s'",fname); Serialiser *ser = new Serialiser(ses); ser->write(a); if(strlen(fname)) fclose(a); delete ser; } break; case T_SAVEVAR: { if(cg->isCompiling()) error("can only run 'savevar' in interactive mode"); if(tok->getnext()!=T_IDENT) error("expected a variable name after 'savevar'"); const char *vname = tok->getstring(); int vdesc = lana->consts->findOrCreateString(vname); if(tok->getnext()!=T_STRING) error("expected a string after 'savevar'"); const char *fname = tok->getstring(); // try to get the value Value *v; int id; id = lana->globs->find(vdesc); if(id>=0) { v = lana->globs->get(id); // it's a global } else { id = ses->findSesVar(vdesc); if(id<0) error("variable not found: %s",lana->consts->getStr(vdesc)); v = ses->getSesVar(id); } FILE *a; if(!strlen(fname)) a = stdout; else a = fopen(fname,"w"); if(!a) error("cannot open file '%s'",fname); Serialiser *ser = new Serialiser(ses); ser->serialiseValue(a,v,lana->consts->getStr(vdesc)); if(strlen(fname)) fclose(a); delete ser; } break; case T_FOR: scanFor(); break; case T_ENDFOR: scanEndFor(); break; case T_THIS: tok->rewind(); // put the token back if(!scanExpr(true)) // clear all statements if not a func or other oddity, // or just a dummy for recreation purposes if in immediate mode. cg->emit(cg->isCompiling()?OP_ENDESTMT:OP_ENDESTMT2); break; case T_GOTO: if(!cg->isCompiling()) error("must be compiling a function/procedure to use '%s'",tok->getstring()); scanGoto(); break; case T_ENDFUNC: scanEndFunc(); break; case T_END: if(!(lana->opFlags & LOP_STRIPCOMMENTS)) cg->emit(OP_BLANKLINE); // yes, these are wasteful .. very slightly break; case T_IF: // first we push a special value onto the compiler stack // to mark the start of this if..elseif..elseif..endif cg->current->cpush(-9999); // we scan the expression if(scanExpr()) error("cannot use a function/procedure expression in if"); // stack and output an incomplete if - but this might be a normal if, or a quick if. cg->current->cpushhere(); // now for some cleverness. Is the next token a colon? if(tok->getnext() == T_COLON){ cg->emit(OP_QUICKIF,-100); // if so, parse the next statement recursively scanStmt(); // note that we don't need to output a quick endif, since the recreator // doesn't need it! instruction *ptr = cg->current->cpoplocandcheck(OP_QUICKIF,OP_QUICKIF); // MUST be an OP_IF, no ELSE. if(!ptr) error("not a simple statement in quick-if"); // write the IF, ELSE or ELSEIF again with the correct distance *ptr = INST(INSTOP(*ptr),cg->current->getdiff(ptr)); // now pop off! int n; do{ n = cg->current->cpop(); }while(n!=-9999); } else { // not - put it back! tok->rewind(); cg->emit(OP_IF,-100); } break; case T_ENDIF: { // get the corresponding OP_IF, OP_ELSEIF or OP_ELSE cg->emit(OP_ENDIF); instruction *ptr = cg->current->cpoplocandcheck(OP_IF,OP_ELSE); if(!ptr) error("mismatched endif"); // write the IF, ELSE or ELSEIF again with the correct distance *ptr = INST(INSTOP(*ptr),cg->current->getdiff(ptr)); // now pop and fixup OP_JMPELSEIFs until we get the special -9999 which marked the start for(;;){ int n = cg->current->cpop(); if(n==-9999)break; // we're done! // we're not done - get the code pointer instruction *ptr = cg->current->getPtr(n*sizeof(instruction)); // make sure it's a OP_JMPELSEIF! if(INSTOP(*ptr)!=OP_JMPELSEIF) error("badly formed conditional statement"); // change it so that it jumps to the current location *ptr = INST(INSTOP(*ptr),cg->current->getdiff(ptr)); } } break; case T_ELSEIF: { // pop the instruction off the stack, an OP_IF or OP_ELSEIF instruction *ptr = cg->current->cpoplocandcheck(OP_IF,OP_ELSEIF); // first we need to terminate the previous condition, so // push the location and output a OP_JMPELSEIF ready to fill in. // This will get left on the stack! cg->current->cpushhere(); cg->emit(OP_JMPELSEIF,-100); // now make the IF or ELSEIF we popped jump to this point *ptr = INST(INSTOP(*ptr),cg->current->getdiff(ptr)); // now scan the expression if(scanExpr()) error("cannot use a function/procedure expression in if"); // push the location, and.. // output an OP_ELSEIF with a dummy jump cg->current->cpushhere(); cg->emit(OP_ELSEIF,-100); } break; case T_ELSE: { // write the OP_ELSE which will become a jump forward, // but first recording the location int elseloc = cg->current->getloc(); cg->emit(OP_ELSE,-100); // now we need to make the IF jump to here // get the corresponding OP_IF or OP_ELSEIF instruction *ptr = cg->current->cpoplocandcheck(OP_IF,OP_ELSEIF); if(!ptr) error("mismatched else"); // write the IF again with the correct jump distance int diff = cg->current->getdiff(ptr); *ptr = INST(INSTOP(*ptr),diff); // now push the location of the OP_ELSE, which // will get processed by the OP_ENDIF cg->current->cpush(elseloc); } break; // pop the location case T_RETURN: if(!cg->isCompiling()) error("must be compiling a function/procedure to use '%s'",tok->getstring()); if(tok->getnext() == T_END){ // end of line? tok->rewind(); // no return value if(cg->current->ldth.flags & LDTF_RETURNS) error("functions must return a value"); cg->emit(OP_RETURN,0); } else { tok->rewind(); if(!(cg->current->ldth.flags & LDTF_RETURNS)) error("procedures cannot return a value"); if(scanExpr()) error("cannot directly return a function"); cg->emit(OP_RETURN,1); } break; case T_WHILE: if(!cg->isCompiling()) error("must be compiling a function/procedure to use '%s'",tok->getstring()); // push the current location onto the stack - this is where ENDWHILE will // jump to cg->current->cpushhere(); // we also create and push the loop data here, so that we can use break and // continue! cg->current->newloop(); // scan and output the expression if(scanExpr()) error("cannot use a function/procedure expression in `while`"); // push the WHILE onto the stack so we can write the terminating jump into it cg->current->cpushhere(); // output OP_WHILE with a dummy cg->emit(OP_WHILE,-100); break; case T_ENDWHILE: { // pop the location of the WHILE from the stack instruction *whileptr = cg->current->cpoplocandcheck(OP_WHILE,OP_WHILE); if(!whileptr) error("mismatched endwhile"); // pop the location for the backward jump instruction *jumpdest = cg->current->cpoplocation(); // output the endwhile, which will do the backward jump cg->emit(OP_ENDWHILE,cg->current->getdiff(jumpdest)); // now patch the while instruction with the forward jump to use if the // condition is false *whileptr = INST(OP_WHILE,cg->current->getdiff(whileptr)); /// and end the loop, setting the break label and popping the loop stack cg->current->endloop(); break; } case T_REPEAT: if(!cg->isCompiling()) error("must be compiling a function/procedure to use '%s'",tok->getstring()); // output OP_REPEAT, pushing its location. We don't // jump to here, though - we jump to the following opcode. // This is done just so we can check that the until matches // a repeat. See T_UNTIL. cg->current->cpushhere(); cg->current->newloop(); // push and initialise a new loop stack entry (see T_WHILE above) cg->emit(OP_REPEAT,0); break; case T_UNTIL: { // scan and output the expression if(scanExpr()) error("cannot use a function/procedure expression in `until`"); // pop the location of the OP_REPEAT from the stack instruction *ptr = cg->current->cpoplocandcheck(OP_REPEAT,OP_REPEAT); if(!ptr) error("mismatched `until'"); // increment this, because we want to save cycles by // jumping past the OP_REPEAT (which is a kind of noop) ptr++; // and output the OP_UNTIL jump cg->emit(OP_UNTIL,cg->current->getdiff(ptr)); cg->current->endloop(); // end the current loop stack entry (see T_ENDWHILE above) break; } case T_BREAK: { // we want to break out of the topmost loop on the loop stack // get address we're about to write to instruction *op = cg->current->getlocptr(); // output the break which will be patched later cg->emit(OP_BREAK,-100); // and this jump as a jump to be patched when the break label is resolved LoopData *d = cg->current->loopstack.peekptr(); if(!d) throw ParseException("break with no loop"); d->breaklabel.jumpFrom(op); } break; case T_CONTINUE: { // we want to terminate the current iteration of the topmost loop on the loop stack // and immediately start the loop code again // get address we're about to write to instruction *op = cg->current->getlocptr(); // output the break which will be patched later cg->emit(OP_CONTINUE,-100); // and this jump as a jump to be patched when the break label is resolved LoopData *d = cg->current->loopstack.peekptr(); if(!d) throw ParseException("continue with no loop"); d->continuelabel.jumpFrom(op); } break; case T_COMMENT: scanComment(true); break; default: error("unexpected token '%s'",tok->getstring()); } // see if there's a comment at the end scanPossibleComment(); if(tok->getnext()!=T_END) error("trailing garbage at end of line"); }