/* * "Logo" interpreter * * Input is a sequence of tokens separated by spaces on stdin. Case is not significant. * * The following input is supported: * * FD distance Move forward * BK distance Move backward * LT degrees Turn left * RT degrees Turn right * REPEAT num [commands] Repeat the sequence times * MAKE "name value Define local variable equal to ; this definition is * valid for the remainder of the scope and overrides any previous * definition of this variable name * :name Refer to variable (either to obtain its value, or, in a * function definition, to name it as a parameter) * TO name params body END Define function as follows: map incoming values to the * parameters named in , then execute the sequence * *, /, +, - Legal arithmetic operators within an expression. No spaces are * allowed inside an expression; *, / are evaluated before +, -. * All arithmetic is integer arithmetic. * integers Legal numbers in an expression. */ #include #include #include #include #include "token.h" #include "var.h" #include "fun.h" #ifndef NULL #define NULL 0 #endif char* HEADER = "\ #include \"conio.h\"\n#include \"dmotor.h\"\n#include \"dsensor.h\"\n\n\ const int SPEED = 255;\nconst float ROT_DIVISOR = 3.75;\nconst int DIST_MULTIPLE = 3;\n\n\ void rt(int deg)\n{\n\ \tds_rotation_set(&SENSOR_1, 0);\n\tds_rotation_set(&SENSOR_2, 0);\n\tds_rotation_set(&SENSOR_3, 0);\n\n\ \tmotor_a_dir(rev);\n\tmotor_b_dir(rev);\n\tmotor_c_dir(rev);\n\ \tmotor_a_speed(SPEED);\n\tmotor_b_speed(SPEED);\n\tmotor_c_speed(SPEED);\n\n\ \twhile(ROTATION_2 > (-deg / ROT_DIVISOR));\n\n\ \tmotor_a_dir(brake);\n\tmotor_b_dir(brake);\n\tmotor_c_dir(brake);\n\ \tmsleep(10);\n\ \tmotor_a_dir(off);\n\tmotor_b_dir(off);\n\tmotor_c_dir(off);\n\ }\n\n\ void lt(int deg)\n{\n\ \tds_rotation_set(&SENSOR_1, 0);\n\tds_rotation_set(&SENSOR_2, 0);\n\tds_rotation_set(&SENSOR_3, 0);\n\n\ \tmotor_a_dir(fwd);\n\tmotor_b_dir(fwd);\n\tmotor_c_dir(fwd);\n\ \tmotor_a_speed(SPEED);\n\tmotor_b_speed(SPEED);\n\tmotor_c_speed(SPEED);\n\n\ \twhile(ROTATION_2 < (deg / ROT_DIVISOR));\n\n\ \tmotor_a_dir(brake);\n\tmotor_b_dir(brake);\n\tmotor_c_dir(brake);\n\ \tmsleep(10);\n\ \tmotor_a_dir(off);\n\tmotor_b_dir(off);\n\tmotor_c_dir(off);\n\ }\n\n\ void fd(int dist)\n{\n\ \tds_rotation_set(&SENSOR_1, 0);\n\tds_rotation_set(&SENSOR_2, 0);\n\tds_rotation_set(&SENSOR_3, 0);\n\n\ \tmotor_a_dir(brake);\n\tmotor_b_dir(rev);\n\tmotor_c_dir(fwd);\n\ \tmotor_b_speed(SPEED);\n\tmotor_c_speed(SPEED);\n\n\ \twhile(ROTATION_3 < (dist * DIST_MULTIPLE));\n\n\ \tmotor_b_dir(brake);\n\tmotor_c_dir(brake);\n\ \tmsleep(10);\n\ \tmotor_a_dir(off);\n\tmotor_b_dir(off);\n\tmotor_c_dir(off);\n\ }\n\n\ void bk(int dist)\n{\n\ \tds_rotation_set(&SENSOR_1, 0);\n\tds_rotation_set(&SENSOR_2, 0);\n\tds_rotation_set(&SENSOR_3, 0);\n\n\ \tmotor_a_dir(brake);\n\tmotor_b_dir(fwd);\n\tmotor_c_dir(rev);\n\ \tmotor_b_speed(SPEED);\n\tmotor_c_speed(SPEED);\n\n\ \twhile(ROTATION_2 < (dist * DIST_MULTIPLE));\n\n\ \tmotor_b_dir(brake);\n\tmotor_c_dir(brake);\n\ \tmsleep(10);\n\ \tmotor_a_dir(off);\n\tmotor_b_dir(off);\n\tmotor_c_dir(off);\n\ }\n\n\ int main(int argc, char** argv)\n{\n\ \tds_active(&SENSOR_1);\n\tds_active(&SENSOR_2);\n\tds_active(&SENSOR_3);\n\ \tds_rotation_on(&SENSOR_1);\n\tds_rotation_on(&SENSOR_2);\n\tds_rotation_on(&SENSOR_3);\n\n"; char* FOOTER = "\n\treturn 0;\n}\n"; char* convertToLower(const char* src) { char* result = new char[strlen(src) + 1]; strcpy(result, src); for(char* i = result; *i; i++) *i = tolower(*i); return result; } char* getNextTok(const char* str) { int length = strlen(str) + 1; char* rest = strchr(str, ' '); if(rest) length -= strlen(rest); char* result = new char[length]; for(int i = 0; i < length; i++) result[i] = str[i]; result[length - 1] = '\0'; return result; } token* tokenize(const char* src, unsigned int& numToks) { int numBracks = 0; for(unsigned int i = 0; i < strlen(src); i++) if((src[i] == '[') || (src[i] == ']')) numBracks++; char* spcBracks = new char[strlen(src) + numBracks + 1]; unsigned int c = 0; for(i = 0; i < strlen(src) + 1; i++) { if(src[i] == ']') { spcBracks[c] = ' '; c++; } spcBracks[c] = src[i]; c++; if(src[i] == '[') { spcBracks[c] = ' '; c++; } } c = 1; for(i = 0; i < strlen(spcBracks); i++) if(spcBracks[i] == ' ') c++; token* toks = new token[c]; numToks = 0; char* scratch = spcBracks; while(*scratch) { char* tok = getNextTok(scratch); scratch += strlen(tok); if(*scratch) scratch++; toks[numToks] = token(tok); delete[] tok; numToks++; } token* result = new token[numToks]; for(i = 0; i < numToks; i++) result[i] = toks[i]; delete[] toks; return result; } int getVal(const token tok, const unsigned int numVars, const var* vars) { int result; bool found = false; unsigned int i = 0; switch(tok.tokType) { case NUM: result = atoi(tok.tok); break; case BINOP: switch(tok.op) { case ADD: result = getVal(*tok.lhs, numVars, vars) + getVal(*tok.rhs, numVars, vars); break; case SUB: result = getVal(*tok.lhs, numVars, vars) - getVal(*tok.rhs, numVars, vars); break; case MUL: result = getVal(*tok.lhs, numVars, vars) * getVal(*tok.rhs, numVars, vars); break; case DIV: result = getVal(*tok.lhs, numVars, vars) / getVal(*tok.rhs, numVars, vars); break; } break; case VARUSE: while((i < numVars) && !found) { if(!strcmp(tok.tok, vars[i].name)) { found = true; result = vars[i].value; } i++; } // FALL THROUGH default: if(!found) { cerr << "ERROR: Expected value, got \"" << tok.tok << "\"" << endl; exit(1); } break; } return result; } void fd(const int dist) { cout << "\tfd(" << dist << ");" << endl; } void bk(const int dist) { cout << "\tbk(" << dist << ");" << endl; } void lt(const int deg) { cout << "\tlt(" << deg << ");" << endl; } void rt(const int deg) { cout << "\trt(" << deg << ");" << endl; } void executeTokens(const unsigned int numToks, const token* toks, const unsigned int numVars, const var* vars, const unsigned int numFuns, const fun* funs) { int rptVal, rpt; unsigned int c, j; bool found; token* body; char* name; unsigned int numParams; char** params; fun* newFuns; var* newVars; for(unsigned int i = 0; i < numToks; i++) { switch(toks[i].tokType) { case FD: i++; fd(getVal(toks[i], numVars, vars)); break; case BK: i++; bk(getVal(toks[i], numVars, vars)); break; case LT: i++; lt(getVal(toks[i], numVars, vars)); break; case RT: i++; rt(getVal(toks[i], numVars, vars)); break; case REPEAT: i++; rptVal = getVal(toks[i], numVars, vars); i++; if(toks[i].tokType != OPEN) { cerr << "ERROR: Expected \"[\", got \"" << toks[i].tok << "\"" << endl; exit(1); } i++; c = 0; found = false; while((i + c < numToks) && !found) { if(toks[i + c].tokType == CLOSE) found = true; else c++; } if(!found) { cerr << "ERROR: \"[\" without corresponding \"]\"" << endl; exit(1); } body = new token[c]; for(j = 0; j < c; j++) body[j] = toks[i + j]; for(rpt = 0; rpt < rptVal; rpt++) executeTokens(c, body, numVars, vars, numFuns, funs); delete[] body; i += c + 1; break; case BEGIN: i++; if(toks[i].tokType != OTHER) { cerr << "ERROR: Expected function name, got \"" << toks[i].tok << "\"" << endl; exit(1); } name = toks[i].tok; i++; numParams = 0; while(toks[i + numParams].tokType == VARUSE) numParams++; params = new char*[numParams]; for(j = 0; j < numParams; j++) { params[j] = new char[strlen(toks[i].tok) + 1]; strcpy(params[j], toks[i].tok); i++; } c = 0; found = false; while((i + c < numToks) && !found) { if(toks[i + c].tokType == END) found = true; else c++; } if(!found) { cerr << "ERROR: \"TO\" without corresponding \"END\"" << endl; exit(1); } body = new token[c]; for(j = 0; j < c; j++) body[j] = toks[i + j]; newFuns = new fun[numFuns + 1]; newFuns[0] = fun(name, numParams, params, c, body); for(j = 1; j < numFuns + 1; j++) newFuns[j] = funs[j - 1]; delete[] body; for(j = 0; j < numParams; j++) delete params[j]; delete[] params; i += c + 1; body = new token[numToks - i]; c = 0; while(i < numToks) { body[c] = toks[i]; i++; c++; } executeTokens(c, body, numVars, vars, numFuns + 1, newFuns); delete[] body; delete[] newFuns; break; case MAKE: i++; if(toks[i].tokType != VARDEF) { cerr << "ERROR: Expected variable definition, got \"" << toks[i].tok << "\"" << endl; exit(1); } name = new char[strlen(toks[i].tok) + 1]; strcpy(name, toks[i].tok); name[0] = ':'; i++; newVars = new var[numVars + 1]; newVars[0] = var(name, getVal(toks[i].tok, numVars, vars)); delete[] name; for(j = 0; j < numVars; j++) { newVars[j + 1] = vars[j]; } i++; body = new token[numToks - i]; c = 0; while(i < numToks) { body[c] = toks[i]; i++; c++; } executeTokens(c, body, numVars + 1, newVars, numFuns, funs); delete[] body; delete[] newVars; break; case OTHER: c = 0; while((c < numFuns) && strcmp(funs[c].name, toks[i].tok)) c++; if(c == numFuns) { cerr << "ERROR: function \"" << toks[i].tok << "\" not found" << endl; exit(1); } newVars = new var[numVars + funs[c].numParams]; for(j = 0; j < funs[c].numParams; j++) { i++; newVars[j] = var(funs[c].params[j], getVal(toks[i].tok, numVars, vars)); } for(j = 0; j < numVars; j++) { newVars[funs[c].numParams + j] = vars[j]; } executeTokens(funs[c].numToks, funs[c].toks, numVars + funs[c].numParams, newVars, numFuns, funs); delete[] newVars; break; default: cerr << "ERROR: Unexpected token \"" << toks[i].tok << "\"" << endl; exit(1); break; } } } int main(int argc, char** argv) { char* input = new char[1000]; cin.getline(input, 1000); char* program = convertToLower(input); delete[] input; unsigned int numToks; token* toks = tokenize(program, numToks); delete[] program; cout << HEADER; executeTokens(numToks, toks, 0, NULL, 0, NULL); cout << FOOTER; delete[] toks; return 0; }