test-scanner.cc

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008 Kamil Dudka <xdudka00@stud.fit.vutbr.cz>
00003  *
00004  * This file is part of vyp08 (compiler and interpreter of VYP08 language).
00005  *
00006  * vyp08 is free software: you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation, either version 3 of the License, or
00009  * any later version.
00010  *
00011  * vyp08 is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with vyp08.  If not, see <http://www.gnu.org/licenses/>.
00018  */
00019 
00020 #include "config.h"
00021 #include "scanner.h"
00022 #include "vypIO.h"
00023 
00024 #ifndef BUILDING_DOX
00025 #   include <algorithm>
00026 #   include <sstream>
00027 #   include <string>
00028 #   include <vector>
00029 #endif
00030 
00031 using namespace StreamDecorator;
00032 using std::string;
00033 
00034 typedef STD_VECTOR(Token) TTokenList;
00035 
00037 struct Test {
00038     string      input;      
00039     bool        hasError;   
00040     TTokenList  tokenList;  
00041 };
00042 
00043 static int errorCode = 0;
00044 
00046 bool operator==(const Token &a, const Token &b) {
00047     if (a.type != b.type)
00048         return false;
00049     if (a.lineno != b.lineno)
00050         return false;
00051     switch (a.type) {
00052         case ETOKEN_NUMBER_INT:
00053             return a.numberInt == b.numberInt;
00054         case ETOKEN_NUMBER_DOUBLE:
00055             return b.numberDouble == b.numberDouble;
00056         case ETOKEN_ID:
00057         case ETOKEN_STRING:
00058             return a.text == b.text;
00059         default:
00060             return true;
00061     }
00062 }
00064 bool operator!=(const Token &a, const Token &b) {
00065     return !operator==(a,b);
00066 }
00067 
00073 void run(const Test &test) {
00074     // test name
00075     static int nTest = 0;
00076     std::ostringstream tmp;
00077     tmp << "test" << ++nTest;
00078     string name(tmp.str());
00079 
00080     // print header
00081     std::cout << ">>> " << name << " - input follows:" << std::endl;
00082     std::cout << test.input << std::endl;
00083     std::istringstream stream(test.input);
00084 
00085     // crate scanner
00086     IScanner *scanner = ScannerFactory::createScanner(stream, name);
00087     Token token;
00088     const TTokenList &tl = test.tokenList;
00089     unsigned i;
00090     for (i = 0; scanner->readNext(token); i++) {
00091 #if 0
00092         std::cout << token << std::endl;
00093 #endif
00094         if (test.hasError)
00095             // input is expected not to be valid
00096             continue;
00097 
00098         const Token &tokenExpected = tl[i];
00099         if (i >= tl.size()) {
00100             std::cerr << "!!! trailing token" << std::endl
00101                 << "---      got: " << token << std::endl << std::endl;
00102             ::errorCode = -1;
00103             break;
00104         }
00105         if (token != tokenExpected) {
00106             std::cerr << "!!! token mismatch" << std::endl
00107                 << "--- expected: " << tl[i] << std::endl
00108                 << "---      got: " << token << std::endl << std::endl;
00109             ::errorCode = -1;
00110         }
00111     }
00112     if (!test.hasError && i < tl.size()) {
00113         std::cerr << "!!! unexpected end of input" << std::endl
00114             << "--- expected: " << tl[i] << std::endl;
00115         ::errorCode = -1;
00116     }
00117     if (scanner->hasError() != test.hasError) {
00118         std::cerr << "!!! unexpected error status" << std::endl
00119             << "--- expected: " << test.hasError << std::endl
00120             << "---      got: " << scanner->hasError() << std::endl;
00121         ::errorCode = -1;
00122     }
00123     delete scanner;
00124     std::cout << std::endl;
00125 }
00126 
00127 int main(int argc, char *argv[]) {
00128 #if CONSOLE_COLOR_OUTPUT
00129     Color::enable(true);
00130 #endif
00131 
00132     if (argc == 2 && string(argv[1]) == string("-")) {
00133         // manual scanner diagnostic
00134 
00135         // create scanner
00136         IScanner *scanner = ScannerFactory::createScanner(std::cin, "-");
00137 
00138         // read from stdin and stream to stdout
00139         Token t;
00140         while (scanner->readNext(t))
00141             std::cout << t << std::endl;
00142 
00143         // evalueate return value
00144         bool bErr = scanner->hasError();
00145         delete scanner;
00146         return bErr ? -1:0;
00147     }
00148 
00149     // initialize test list
00150     typedef STD_VECTOR(Test) TTestList;
00151     TTestList testList;
00152     Test t;
00153     TTokenList &tl = t.tokenList;
00154 
00155     // test #1 - comment / id
00156     t.input = "\n\tid1/* simple comment */id2// inline comment /* garbage /*\nid3////////";
00157     t.hasError = false;
00158     tl.clear();
00159     { Token t(ETOKEN_ID, 2, 0, 0.0, "id1"); tl.push_back(t); }
00160     { Token t(ETOKEN_ID, 2, 0, 0.0, "id2"); tl.push_back(t); }
00161     { Token t(ETOKEN_ID, 3, 0, 0.0, "id3"); tl.push_back(t); }
00162     testList.push_back(t);
00163 
00164     // test #2 - keyword / id
00165     t.input = "int a;doubleb;double d;string\ts;;";
00166     t.hasError = false;
00167     tl.clear();
00168     { Token t(ETOKEN_KW_INT,        1, 0, 0.0, ""          ); tl.push_back(t); }
00169     { Token t(ETOKEN_ID,            1, 0, 0.0, "a"         ); tl.push_back(t); }
00170     { Token t(ETOKEN_OP_SEMICOLON,  1, 0, 0.0, ""          ); tl.push_back(t); }
00171     { Token t(ETOKEN_ID,            1, 0, 0.0, "doubleb"   ); tl.push_back(t); }
00172     { Token t(ETOKEN_OP_SEMICOLON,  1, 0, 0.0, ""          ); tl.push_back(t); }
00173     { Token t(ETOKEN_KW_DOUBLE,     1, 0, 0.0, ""          ); tl.push_back(t); }
00174     { Token t(ETOKEN_ID,            1, 0, 0.0, "d"         ); tl.push_back(t); }
00175     { Token t(ETOKEN_OP_SEMICOLON,  1, 0, 0.0, ""          ); tl.push_back(t); }
00176     { Token t(ETOKEN_KW_STRING,     1, 0, 0.0, ""          ); tl.push_back(t); }
00177     { Token t(ETOKEN_ID,            1, 0, 0.0, "s"         ); tl.push_back(t); }
00178     { Token t(ETOKEN_OP_SEMICOLON,  1, 0, 0.0, ""          ); tl.push_back(t); }
00179     { Token t(ETOKEN_OP_SEMICOLON,  1, 0, 0.0, ""          ); tl.push_back(t); }
00180     testList.push_back(t);
00181 
00182     // test #3 - string ok
00183     t.input =
00184         "STRING /* \"asdffsi\" */\"\\\\n - \\n, /* pseudo-comment */, //,\\n"
00185         "  \\\\\\\\ - \\\\, \\\\\\\" - \\\", garbge\"id+0.01///\n\"\""
00186         "\"a\\\\b -> \\\"c\\\"\"";
00187     t.hasError = false;
00188     tl.clear();
00189     { Token t(ETOKEN_ID,            1, 0, 0.0, "STRING"    ); tl.push_back(t); }
00190     { Token t(ETOKEN_STRING,        1, 0, 0.0, "\\n - \n, /* pseudo-comment */, //,\n  \\\\ - \\, \\\" - \", garbge"); tl.push_back(t); }
00191     { Token t(ETOKEN_ID,            1, 0, 0.0, "id"        ); tl.push_back(t); }
00192     { Token t(ETOKEN_OP_PLUS,       1, 0, 0.0, ""          ); tl.push_back(t); }
00193     { Token t(ETOKEN_NUMBER_DOUBLE, 1, 0, .01, ""          ); tl.push_back(t); }
00194     { Token t(ETOKEN_STRING,        2, 0, 0.0, ""          ); tl.push_back(t); }
00195     { Token t(ETOKEN_STRING,        2, 0, 0.0, "a\\b -> \"c\""); tl.push_back(t); }
00196     testList.push_back(t);
00197 
00198     // tests #4, #5, #6, #7 - string error
00199     t.hasError = true;
00200     tl.clear();
00201     t.input = "\"str";                  testList.push_back(t);
00202     t.input = "\"str\\a\"";             testList.push_back(t);
00203     t.input = "\"str\\\\\"\"";          testList.push_back(t);
00204     t.input = "str\"";                  testList.push_back(t);
00205 
00206     // test #8 - numbers ok
00207     t.input = "double d:=0.0000000000000001e15,-15";
00208     t.hasError = false;
00209     tl.clear();
00210     { Token t(ETOKEN_KW_DOUBLE,     1, 0, 0.0, ""          ); tl.push_back(t); }
00211     { Token t(ETOKEN_ID,            1, 0, 0.0, "d"         ); tl.push_back(t); }
00212     { Token t(ETOKEN_OP_ASSIGN,     1, 0, 0.0, ""          ); tl.push_back(t); }
00213     { Token t(ETOKEN_NUMBER_DOUBLE, 1, 0, 0.0000000000000001e15, ""          ); tl.push_back(t); }
00214     { Token t(ETOKEN_OP_COMMA,      1, 0, 0.0, ""          ); tl.push_back(t); }
00215     { Token t(ETOKEN_OP_MINUS,      1, 0, 0.0, ""          ); tl.push_back(t); }
00216     { Token t(ETOKEN_NUMBER_INT,    1, 15, 0.0, ""         ); tl.push_back(t); }
00217     testList.push_back(t);
00218 
00219     // tests #9, #10, #11 - number error
00220     t.hasError = true;
00221     tl.clear();
00222     t.input = "1_";                     testList.push_back(t);
00223     t.input = "9999999999999999999";    testList.push_back(t);
00224     t.input = "10.0e1000";              testList.push_back(t);
00225 
00226     // test #12 - kw/op
00227     t.input = "{and}(div)double*/else+-eq if<int>ne\n"
00228         "q\tneq<=not>=or:=string,var\n\n\n;void/**/while \n"
00229         "////////////////////////////////////////////";
00230     t.hasError = false;
00231     tl.clear();
00232     { Token t(ETOKEN_OP_LCBR,       1, 0, 0.0, ""          ); tl.push_back(t); }
00233     { Token t(ETOKEN_KW_AND,        1, 0, 0.0, ""          ); tl.push_back(t); }
00234     { Token t(ETOKEN_OP_RCBR,       1, 0, 0.0, ""          ); tl.push_back(t); }
00235     { Token t(ETOKEN_OP_LPAR,       1, 0, 0.0, ""          ); tl.push_back(t); }
00236     { Token t(ETOKEN_KW_DIV,        1, 0, 0.0, ""          ); tl.push_back(t); }
00237     { Token t(ETOKEN_OP_RPAR,       1, 0, 0.0, ""          ); tl.push_back(t); }
00238     { Token t(ETOKEN_KW_DOUBLE,     1, 0, 0.0, ""          ); tl.push_back(t); }
00239     { Token t(ETOKEN_OP_STAR,       1, 0, 0.0, ""          ); tl.push_back(t); }
00240     { Token t(ETOKEN_OP_SLASH,      1, 0, 0.0, ""          ); tl.push_back(t); }
00241     { Token t(ETOKEN_KW_ELSE,       1, 0, 0.0, ""          ); tl.push_back(t); }
00242     { Token t(ETOKEN_OP_PLUS,       1, 0, 0.0, ""          ); tl.push_back(t); }
00243     { Token t(ETOKEN_OP_MINUS,      1, 0, 0.0, ""          ); tl.push_back(t); }
00244     { Token t(ETOKEN_KW_EQ,         1, 0, 0.0, ""          ); tl.push_back(t); }
00245     { Token t(ETOKEN_KW_IF,         1, 0, 0.0, ""          ); tl.push_back(t); }
00246     { Token t(ETOKEN_OP_LESS,       1, 0, 0.0, ""          ); tl.push_back(t); }
00247     { Token t(ETOKEN_KW_INT,        1, 0, 0.0, ""          ); tl.push_back(t); }
00248     { Token t(ETOKEN_OP_GREATER,    1, 0, 0.0, ""          ); tl.push_back(t); }
00249     { Token t(ETOKEN_ID,            1, 0, 0.0, "ne"        ); tl.push_back(t); }
00250     { Token t(ETOKEN_ID,            2, 0, 0.0, "q"         ); tl.push_back(t); }
00251     { Token t(ETOKEN_KW_NEQ,        2, 0, 0.0, ""          ); tl.push_back(t); }
00252     { Token t(ETOKEN_OP_LESS_EQ,    2, 0, 0.0, ""          ); tl.push_back(t); }
00253     { Token t(ETOKEN_KW_NOT,        2, 0, 0.0, ""          ); tl.push_back(t); }
00254     { Token t(ETOKEN_OP_GREATER_EQ, 2, 0, 0.0, ""          ); tl.push_back(t); }
00255     { Token t(ETOKEN_KW_OR,         2, 0, 0.0, ""          ); tl.push_back(t); }
00256     { Token t(ETOKEN_OP_ASSIGN,     2, 0, 0.0, ""          ); tl.push_back(t); }
00257     { Token t(ETOKEN_KW_STRING,     2, 0, 0.0, ""          ); tl.push_back(t); }
00258     { Token t(ETOKEN_OP_COMMA,      2, 0, 0.0, ""          ); tl.push_back(t); }
00259     { Token t(ETOKEN_KW_VAR,        2, 0, 0.0, ""          ); tl.push_back(t); }
00260     { Token t(ETOKEN_OP_SEMICOLON,  5, 0, 0.0, ""          ); tl.push_back(t); }
00261     { Token t(ETOKEN_KW_VOID,       5, 0, 0.0, ""          ); tl.push_back(t); }
00262     { Token t(ETOKEN_KW_WHILE,      5, 0, 0.0, ""          ); tl.push_back(t); }
00263     testList.push_back(t);
00264 
00265     std::for_each(testList.begin(), testList.end(), run);
00266     return ::errorCode;
00267 }

Generated on Sat Jul 4 18:32:59 2009 for vyp08 (compiler and interpreter of VYP08 language) by  doxygen 1.5.4