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 rob08
00005  *
00006  * rob08 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  * rob08 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 rob08.  If not, see <http://www.gnu.org/licenses/>.
00018  */
00019 
00020 #include "config.h"
00021 #include "scanner.h"
00022 
00023 #include "robIO.h"
00024 
00025 #ifndef BUILDING_DOX
00026 #   include <assert.h>
00027 #   include <boost/regex.hpp>
00028 #   include <FlexLexer.h>
00029 #   include <map>
00030 #   include <sstream>
00031 #endif
00032 
00033 using namespace StreamDecorator;
00034 using std::string;
00035 
00041 class PrivateFlexLexer: public yyFlexLexer {
00042     public:
00043         PrivateFlexLexer(ICharReader *reader, string fileName):
00044 #if DEBUG_STDIN_AS_TERM
00045             yyFlexLexer(&std::cin, &std::cerr),
00046 #else
00047             yyFlexLexer(0, &std::cerr),
00048 #endif
00049             reader_(reader),
00050             fileName_(fileName),
00051             hasError_(false)
00052         {
00053             yylineno = 0;
00054         }
00056         bool hasError() const {
00057             return hasError_;
00058         }
00060         EToken readNext() {
00061             EToken et = static_cast<EToken>
00062                 (this->yylex());
00063             if (et)
00064                 ++ yylineno;
00065             return et;
00066         }
00068         void postError(const char *msg) {
00069             this->LexerError(msg);
00070         }
00071     protected:
00073         virtual void LexerOutput(const char *buf, int size) {
00074             string msg(buf, size);
00075             this->LexerError(msg.c_str());
00076         }
00078         virtual void LexerError(const char *msg) {
00079             this->hasError_ = true;
00080             std::ostream &str = *(this->yyout);
00081             str << Error(E_ERROR, fileName_, msg, lineno(), "lexical error")
00082                 << std::endl;
00083         }
00084 #if not DEBUG_STDIN_AS_TERM
00086         virtual int LexerInput(char *buf, int nChars) {
00087             assert(0 < nChars);
00088             return reader_->getChar(*buf)
00089                 ? 1:0;
00090         }
00091 #endif
00092     private:
00093         ICharReader     *reader_;                       
00094         string          fileName_;                      
00095         bool            hasError_;                      
00096 };
00097 
00101 class FlexScanner: public IScanner {
00102     public:
00103         FlexScanner(ICharReader *reader, string fileName) {
00104             flex_ = new PrivateFlexLexer(reader, fileName);
00105         }
00106         virtual ~FlexScanner() {
00107             delete flex_;
00108         }
00109         virtual bool readNext(Token &token);
00110         virtual bool hasError() const {
00111             return flex_->hasError();
00112         }
00113     private:
00114         PrivateFlexLexer *flex_;                        
00115 };
00116 
00117 namespace {
00118     bool readHex(const string &str, unsigned &dest) {
00119         std::istringstream stream(str);
00120         stream >> std::hex >> dest;
00121         return stream;
00122     }
00123     bool readHexFromEnd(string &str, unsigned width, unsigned &dest) {
00124         // beware boost optimization
00125         string tmp(str);
00126         assert(0 < width);
00127 
00128         // build regex string
00129         const string hexByte("[0-9A-Fa-f]");
00130         string reStr("^(.*)(");
00131         for (unsigned i = 0; i < width; i++)
00132             reStr += hexByte;
00133         reStr += ")$";
00134 
00135         // match regex
00136         const boost::regex re(reStr);
00137         boost::smatch result;
00138         if (!boost::regex_match(str, result, re))
00139             return false;
00140 
00141         // read hex number
00142         if (!readHex(result[2], dest))
00143             return false;
00144 
00145         // cut string
00146         str = result[1];
00147         return true;
00148     }
00149     bool parsePmArgs(const string &str, Token::TArgVector &args) {
00150         string tmp(str);
00151         unsigned speed, distance, ratio;
00152 
00153         if (!readHexFromEnd(tmp, 2, ratio))
00154             return false;
00155 
00156         if (!readHexFromEnd(tmp, 4, distance))
00157             return false;
00158 
00159         if (!readHexFromEnd(tmp, 2, speed))
00160             return false;
00161 
00162         args.push_back(speed);
00163         args.push_back(distance);
00164         args.push_back(ratio);
00165         return true;
00166     }
00167 }
00168 
00169 std::ostream& operator<<(std::ostream &str, EToken type) {
00170     str << Color(C_YELLOW);
00171     switch (type) {
00172         case ET_NULL:                   str << "ET_NULL";                       break;
00173         case ET_GET_WHISKER_STATUS:     str << "ET_GET_WHISKER_STATUS";         break;
00174         case ET_GET_COMPASS_HEADING:    str << "ET_GET_COMPASS_HEADING";        break;
00175         case ET_GET_COMPASS_HEADING_EX: str << "ET_GET_COMPASS_HEADING_EX";     break;
00176         case ET_GET_TEMP:               str << "ET_GET_TEMP";                   break;
00177         case ET_GET_WATER:              str << "ET_GET_WATER";                  break;
00178         case ET_GET_PIR:                str << "ET_GET_PIR";                    break;
00179         case ET_GET_SONAR:              str << "ET_GET_SONAR";                  break;
00180         case ET_GET_TILT:               str << "ET_GET_TILT";                   break;
00181         case ET_GET_BATT_VOLTAGE:       str << "ET_GET_BATT_VOLTAGE";           break;
00182         case ET_GET_SW_VERSION:         str << "ET_GET_SW_VERSION";             break;
00183         case ET_GET_BUTTONS:            str << "ET_GET_BUTTONS";                break;
00184         case ET_GET_LIGHT_LEVEL:        str << "ET_GET_LIGHT_LEVEL";            break;
00185         case ET_GET_SOUND_LEVEL:        str << "ET_GET_SOUND_LEVEL";            break;
00186         case ET_GET_ENCODER_COUNTS:     str << "ET_GET_ENCODER_COUNTS";         break;
00187         case ET_CMD_PG:                 str << "ET_CMD_PG";                     break;
00188         case ET_CMD_PH:                 str << "ET_CMD_PH";                     break;
00189         case ET_CMD_PL:                 str << "ET_CMD_PL";                     break;
00190         case ET_CMD_PM:                 str << "ET_CMD_PM";                     break;
00191         case ET_CMD_PN:                 str << "ET_CMD_PN";                     break;
00192         case ET_CMD_PS:                 str << "ET_CMD_PS";                     break;
00193         case ET_CMD_PW:                 str << "ET_CMD_PW";                     break;
00194     }
00195     str << Color(C_NO_COLOR);
00196     return str;
00197 }
00198 
00199 std::ostream& operator<<(std::ostream &str, const Token &token) {
00200     // start with lineno:token_typ:
00201     str << Color(C_LIGHT_GREEN) << token.lineno << Color(C_NO_COLOR)
00202         << ":" << token.type;
00203 
00204     // append (...) in some cases
00205     switch (token.type) {
00206         case ET_NULL:
00207             break;
00208 
00209         case ET_CMD_PG:
00210         case ET_CMD_PH:
00211         case ET_CMD_PL:
00212         case ET_CMD_PN:
00213         case ET_CMD_PS:
00214         case ET_CMD_PW:
00215             if (token.args.size()!=1) {
00216                 str << "[" << Color(C_LIGHT_RED) << "INVALID_ARGS" << Color(C_NO_COLOR) << "]";
00217                 str << "[" << Color(C_LIGHT_RED) << token.text << Color(C_NO_COLOR) << "]";
00218                 break;
00219             }
00220             str << "["
00221                 << "code=" << Color(C_LIGHT_BLUE) << PrintHex(token.args[0], 2) << Color(C_NO_COLOR)
00222                 << "]";
00223             break;
00224 
00225         case ET_CMD_PM:
00226             if (token.args.size()!=3) {
00227                 str << "[" << Color(C_LIGHT_RED) << "INVALID_ARGS" << Color(C_NO_COLOR) << "]";
00228                 str << "[" << Color(C_LIGHT_RED) << token.text << Color(C_NO_COLOR) << "]";
00229                 break;
00230             }
00231             str << "["
00232                 << "speed=" << Color(C_LIGHT_BLUE) << PrintHex(token.args[0], 2) << Color(C_NO_COLOR)
00233                 << ", distance=" << Color(C_LIGHT_BLUE) << PrintHex(token.args[1], 4) << Color(C_NO_COLOR)
00234                 << ", ratio=" << Color(C_LIGHT_BLUE) << PrintHex(token.args[2], 2) << Color(C_NO_COLOR)
00235                 << "]";
00236             break;
00237 
00238         default:
00239             str << "[" << Color(C_LIGHT_RED) << token.text << Color(C_NO_COLOR) << "]";
00240             break;
00241     }
00242     str << Color(C_NO_COLOR);
00243     return str;
00244 }
00245 
00246 IScanner* ScannerFactory::createScanner(ICharReader *reader, std::string fileName) {
00247     return new FlexScanner(reader, fileName);
00248 }
00249 
00250 bool FlexScanner::readNext(Token &token) {
00251     EToken type;
00252 readNext:
00253     if (!(type = flex_->readNext()))
00254         return false;
00255 
00256     // common part for all tokens
00257     token.type      = type;
00258     token.lineno    = flex_->lineno();
00259     token.text      = flex_->YYText();
00260     token.args.clear();
00261 
00262     switch (token.type) {
00263         case ET_CMD_PG:
00264         case ET_CMD_PH:
00265         case ET_CMD_PL:
00266         case ET_CMD_PN:
00267         case ET_CMD_PS:
00268         case ET_CMD_PW:
00269             {
00270                 unsigned code;
00271                 string tmp(token.text);
00272                 if (!readHexFromEnd(tmp, 2, code)) {
00273                     if (token.type == ET_CMD_PG)
00274                         flex_->postError("invalid PG command");
00275                     else if (token.type == ET_CMD_PG)
00276                         flex_->postError("invalid PH command");
00277                     else if (token.type == ET_CMD_PL)
00278                         flex_->postError("invalid PL command");
00279                     else if (token.type == ET_CMD_PN)
00280                         flex_->postError("invalid PN command");
00281                     else if (token.type == ET_CMD_PS)
00282                         flex_->postError("invalid PS command");
00283                     else
00284                         flex_->postError("invalid PW command");
00285                     goto readNext;
00286                 }
00287                 token.args.push_back(code);
00288             }
00289             break;
00290 
00291         case ET_CMD_PM:
00292             if (!parsePmArgs(token.text, token.args)) {
00293                 flex_->postError("invalid PM command");
00294                 goto readNext;
00295             }
00296             break;
00297 
00298         default:
00299             break;
00300     }
00301 
00302 #if DEBUG_TERM_INPUT
00303     std::cerr << Color(C_LIGHT_BLUE) << "TERM" << Color(C_NO_COLOR) << " --> "
00304         << token << std::endl;
00305 #endif
00306 
00307     return true;
00308 }
00309 

Generated on Fri Jul 10 22:42:01 2009 for rob08 by  doxygen 1.5.4