示例#1
0
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());
}
示例#2
0
	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;
	}
示例#3
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");
}