00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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
00125 string tmp(str);
00126 assert(0 < width);
00127
00128
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
00136 const boost::regex re(reStr);
00137 boost::smatch result;
00138 if (!boost::regex_match(str, result, re))
00139 return false;
00140
00141
00142 if (!readHex(result[2], dest))
00143 return false;
00144
00145
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
00201 str << Color(C_LIGHT_GREEN) << token.lineno << Color(C_NO_COLOR)
00202 << ":" << token.type;
00203
00204
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
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