Joops, väsäsin tommosen yksinkertasen tulkin yksinkertaselle kielelle. Koodia on aika runsaasti, mutta mukana onkin lausekkeen laskija laskujärjestyksineen, muuttujat ja joitakin sisäänrakennettuja funktioita. Muuttujien tyyppejä on numero, stringi. Esimerkeistä varmaan näkee kielen syntaksin.
tulkki.cpp
#include <iostream> #include <vector> #include <string> #include <fstream> #include <ctype.h> #include <stdlib.h> /* Tyypit */ class Any { public: enum AnyType { TypeNumber, TypeString, TypeName, TypeVector, TypeOperator } type; Any(AnyType t) { type = t; } virtual ~Any() {} virtual Any *clone() { return 0; } }; class Number : public Any { public: Number(double n) : Any(TypeNumber) { number = n; } ~Number() {} Any *clone() { return new Number(number); } double number; }; class String : public Any { public: String(const string &s) : Any(TypeString) { str = s; } ~String() {} Any *clone() { return new String(str); } string str; }; class Name : public Any { public: Name(const string &n) : Any(TypeName) { name = n; } ~Name() {} string name; }; class Vector : public Any { public: Vector() : Any(TypeVector) {} ~Vector() {} Any *clone() { Vector *v = new Vector(); for(int i=0; i<(int) vec.size(); i++) vec.push_back(vec[i]->clone()); return v; } vector<Any *> vec; }; class Operator : public Any { public: Operator(const string &o) : Any(TypeOperator) { oper = o; } ~Operator() {} string oper; }; /* Parserit */ Vector *parse_vector(char *b, char **end=0); const string operchars = "*/+-<>=!"; const string groupedopers[] = { "*", "/", "", "+", "-", "", "<", ">", "==", ">=", "<=", "!=", "", "=", "", "" }; Any *parse(char *b, char **end) { static bool lastwasoper = false; while(*b && (isspace(*b) || *b == '#')) { if(*b == '#') { while(*b != '\n' && *b) b++; continue; } b++; } *end = b; if(!*b) return 0; string s; if(isdigit(*b) || (lastwasoper && (*b=='+' || *b=='-'))) { return new Number(strtod(b, end)); } lastwasoper = false; if(*b == '"') { while((*b) && (*(++b) != '"')) { if(*b == '\\') { b++; if(*b == 'n') s += '\n'; else s += *b; } else s += *b; } *end = b+1; return new String(s); } if(isalpha(*b)) { while(*b && isalpha(*b)) { s += *(b++); } *end = b; return new Name(s); } if(*b == ',') { *end = b+1; return new Operator(string(",")); } if(operchars.find(*b) != string::npos) { while(operchars.find(*b) != string::npos) s += *(b++); *end = b; lastwasoper = true; return new Operator(s); } if(*b == '(') return parse_vector(b+1, end); if(*b == ')') return 0; throw string("Hassu merkki: ") + *b; } Vector *parse_vector(char *b, char **end=0) { Vector *v = new Vector(); while(*b) { Any *a = parse(b, &b); if(!a) break; v->vec.push_back(a); } if(end) *end = b+1; return v; } /* Ympäristö / muuttujat */ class Variable { public: Variable(string &n, Any *a) { name = n; var = a; }; string name; Any *var; }; vector<Variable> variables; Any *getVariable(Name *n) { for(int i=0; i<(int) variables.size(); i++) { if(variables[i].name == n->name) return variables[i].var; } throw string("Muuttujaa ei määritelty: ") + n->name; } void setVariable(Name *n, Any *a) { for(int i=0; i<(int) variables.size(); i++) { if(variables[i].name == n->name) { variables[i].var = a->clone(); return; } } variables.push_back(Variable(n->name, a->clone())); } /* Ajo */ Any *interpret(Any *a); void print(Any *any) { switch(any->type) { case Any::TypeNumber: cout << ((Number *) any)->number; break; case Any::TypeString: cout << ((String *) any)->str; break; case Any::TypeName: print(getVariable((Name *) any)); break; case Any::TypeVector: { for(int i=0; i<(int) ((Vector *) any)->vec.size(); i++) print(((Vector *) any)->vec[i]); } break; case Any::TypeOperator: cout << ((Operator *) any)->oper; break; } } Any *function(Name *n, Vector *args) { if(n->name == "if") { Any *c = interpret(args->vec[0]); if(c->type != Any::TypeNumber) throw string("if tahtoo numeron"); if(((Number *) c)->number) { if(args->vec.size() >= 2) return args->vec[1]; } else if(args->vec.size() >= 3) return args->vec[2]; return 0; } if(n->name == "while") { while(1) { Any *c = interpret(args->vec[0]); if(c->type != Any::TypeNumber) throw string("while tahtoo numeron"); if(!((Number *) c)->number) break; interpret(args->vec[1]); } return 0; } Any *a = interpret(args); if(n->name == "rand") return new Number(rand() / (double) RAND_MAX); if(n->name == "int") return new Number((int) ((Number *) a)->number); if(n->name == "print") { print(a); return 0; } if(n->name == "readnumber") { double n; cin >> n; return new Number(n); } if(n->name == "readstring") { string s; cin >> s; return new String(s); } throw string("Hassun niminen funktio") + n->name; } void calculateExpression(vector<Any *> &operands, vector<string *> &operators) { Name *let = 0; if(operators.size() >= 1) { if(*operators[0] == "=") { if(operands[0]->type != Any::TypeName) throw string("= tahtoo nimen"); let = (Name *) operands[0]; operands.erase(operands.begin()); operators.erase(operators.begin()); } } int i; for(i=0; i<(int) operands.size(); i++) { switch(operands[i]->type) { case Any::TypeName: operands[i] = getVariable((Name *) operands[i]); break; case Any::TypeVector: operands[i]= interpret((Vector *) operands[i]); break; default:; } } int s = 0; while(groupedopers[s] != "") { for(i=0; i<(int) operators.size(); i++) { for(int j=s; groupedopers[j] != ""; j++) { if(groupedopers[j] == *operators[i]) { if(operands[i]->type != operands[i+1]->type) throw string("Tyyppivirhe"); Any *r = 0; switch(operands[i]->type) { case Any::TypeNumber: { double a = ((Number *) operands[i])->number, b = ((Number *) operands[i+1])->number; if(*operators[i] == "+") r = new Number(a + b); if(*operators[i] == "-") r = new Number(a - b); if(*operators[i] == "*") r = new Number(a * b); if(*operators[i] == "/") r = new Number(a / b); if(*operators[i] == "<") r = new Number(a < b); if(*operators[i] == ">") r = new Number(a > b); if(*operators[i] == "==") r = new Number(a == b); if(*operators[i] == "<=") r = new Number(a <= b); if(*operators[i] == ">=") r = new Number(a >= b); if(*operators[i] == "!=") r = new Number(a != b); } break; case Any::TypeString: if(*operators[i] == "==") r = new Number(((String *) operands[i])->str == ((String *) operands[i+1])->str); if(*operators[i] == "+") r = new String(((String *) operands[i])->str + ((String *) operands[i+1])->str); default:; } if(!r) throw string("Hassu operaattori tyypille"); operands.erase(operands.begin()+i, operands.begin()+i+2); operators.erase(operators.begin()+i); operands.insert(operands.begin()+i, r); i--; break; } } } while(groupedopers[s++] != ""); } if(let) { setVariable(let, operands[0]); operands.erase(operands.begin()); } } Any *interpret(Any *a) { if(a->type != Any::TypeVector) return a; Vector *v = (Vector *) a; Vector *ret = new Vector(); vector<Any *>::iterator i; for(i=v->vec.begin(); i<v->vec.end();) { vector<Any *> operands; vector<string *> operators; bool readoperand = true; for(; i<v->vec.end(); i++) { if(readoperand) { // Operandi if(i+1 < v->vec.end()) { if((*i)->type==Any::TypeName && (*(i+1))->type==Any::TypeVector) { Any *r = function((Name *) (*i), (Vector *) *(i+1)); if(r) operands.push_back(r); i++; } else operands.push_back(*i); } else operands.push_back(*i); } else { // Operi if((*i)->type == Any::TypeOperator) { if(((Operator *) *i)->oper == ",") { i++; break; } operators.push_back(&((Operator *) *i)->oper); } else throw string("Operaattori da?"); } readoperand = readoperand ? false : true; } calculateExpression(operands, operators); if(operands.size()) ret->vec.push_back(operands[0]); } if(ret->vec.size() == 0) return 0; if(ret->vec.size() == 1) return ret->vec[0]; return ret; } int main(int argc, char *argv[]) { try { if(argc < 2) throw string("Käyttö: tulkki <file>"); ifstream f(argv[1]); if(!f) throw string("Enpä voi avata tiedostoa."); string s; while(f.peek() != -1) s += f.get(); f.close(); interpret(parse_vector(strdup(s.c_str()))); } catch(string &s) { cerr << "Exception: " << s << endl; return 1; } return 0; }
laskupeli
oikein = 0, vaarin = 0, while ((oikein < 5) ( print (oikein, " oikein ja ", vaarin, " väärin.\n"), # Tilastoja x = int(rand() * 10), # Arvotaan luvut y = int(rand() * 10), print (x, " + ", y, " = "), if ( (readnumber() == x+y) # Vertailu (oikein = oikein + 1, # Tosi print ("Oikein.\n") ) (vaarin = vaarin + 1, # Epätosi print ("Väärin.\n") ) ) )), print ("Da.\n")
nimi
print ("Antaisitko nimesi: "), # Kommentti print ("No moi " + readstring() + ".\n")
No tohan näyttäisi ihan siltä, että tätä yritetään tosissaan. :) Ihan oikeasti! Vielä kun lisäät tuen luokille/malleille/muuttujien ylikuormitukselle/windows-tuen/ja siihen samaan myös DirectX-tuki :D
Menisipäs pitkään, mutta sitten voisit julkaista kielen vaikka nimellä D. =D
Heh.. eipäs olekaan ollut hauskaa näin pitkään aikaan.. Heh
Mitään luokkia tai malleja tuollaisiin.. Helmi tulkki, hyvää työtä ;)
1337-C0D3 :D
Mielenkiintoista, mielenkiintoista. Tuolla kielellä voi jo oikeasti tehdä jotain. Pitänee vastata tuohon omalla QBasic-pohjaisella ohjelmointikielellä ;)
Jaha omaa ohjelmointikieltäkin tekemässä :).. Hieno systeemi!
Hieno ja hyvä tulkki...!
saisiko tota mistään ihan erillisenä ohjelmana kun oon systerillä ja täällä ei ole mitää muuta kuin QB :)
no onhan QB:kin mukava mutta kun oon alkanu taas käyttää borlandin tuotteita ja niitä ei täällä systeril oo niin ajattelin jos jostain löytyisi tämä erillisenä ohjelmana
ja voisin sitten kommentoida tätä
ja kertoo että mitä pitäisi lisäillä ja mitä ei jne...
mutta vaikuttaa mukavalta...
Aika laiskasti kommentoitu, muuten hienon näköinen viritys.
Aika hyvä. iostreamia ei ois tarttenu pistää koska fstream sisältää sen.
Tulee tosi monta virhettä...
Ei toimi.
Jeh, using namespace std
puuttuu.
Ja miksi parse_vector
-funktion määrittelyssä on char **end=0
? Se =0
annetaan deklaraatiossa - jossa se jo on. Turhat kaksi kirjainta jotka aiheuttavat virheen.
Aivan mahtava.Tuosta on apua minulle :)
lainaus:
Mielenkiintoista, mielenkiintoista. Tuolla kielellä voi jo oikeasti tehdä jotain. Pitänee vastata tuohon omalla QBasic-pohjaisella ohjelmointikielellä ;)
Tulkilla tulkki jolla silläkin voidaan tehdä tulkki ;)
Parannusehdotuksia:
-Aaltosulut lohkoihin tavallisten sulkujen tilalle
-Puolipisteet rivin loppuun
-else
-goto
Olisi kyllä kiva jos tuon saisi hyvällä kommentoinnilla.
ville-v: Voihan ne itsekkin tehdä ;) Eikös koodivinkit ole sitä varten, että niitä voi muokkailla?
Ja itse tulkki on todella hieno. Eipä itseltäni tuollainen onnistuisi, vaikka jotain tuollaista yritän itsekkin väsätä.
Koodissa on muutamia ongelmia:
Muokkaus:
Lisäksi:
2+2+2
". Saman laskujärjestyspaikan omaavia operaattoreita ei voi olla peräkkäin.2+2+2
antaa virheen "Operaattori da?
".Aihe on jo aika vanha, joten et voi enää vastata siihen.