#include "scanner.h" #include #include #include using namespace std; static const char * tokenNames_[] = { "end of file", "illegal token", "identifier", "number", "'BEGIN'", "'END'", "'IF'", "'THEN'", "'ELSE'", "'FI'", "'WHILE'", "'DO'", "'OD'", "'WRITE'", "'READ'", "':='", "'+' or '-'", "'*' or '/'", "comparison operator", "'('", "')'", "';'", "'++'", "'--'", }; void Scanner::nextToken() { skipSpace(); // Пропускаем комментарии // Если встречаем "/", то за ним должна идти "*". Если "*" не встречена, считаем, что встретили операцию деления // и лексему - операция типа умножения. Дальше смотрим все символы, пока не находим звездочку или символ конца файла. // Если нашли * - проверяем на наличие "/" после нее. Если "/" не найден - ищем следующую "*". while(ch_ == '/') { nextChar(); if(ch_ == '*') { nextChar(); bool inside = true; while(inside) { while(ch_ != '*' && !input_.eof()) { nextChar(); } if(input_.eof()) { token_ = T_EOF; return; } nextChar(); if(ch_ == '/') { inside = false; nextChar(); } } } else { token_ = T_MULOP; arithmeticValue_ = A_DIVIDE; return; } skipSpace(); } //Если встречен конец файла, считаем за лексему конца файла. if(input_.eof()) { token_ = T_EOF; return; } //Если встретили цифру, то до тех пока дальше идут цифры - считаем как продолжение числа. //Запоминаем полученное целое, а за лексему считаем целочисленный литерал if(isdigit(ch_)) { int value = 0; while(isdigit(ch_)) { value = value * 10 + (ch_ - '0'); //поразрядное считывание, преобразуем символьное значение к числу. nextChar(); } token_ = T_NUMBER; intValue_ = value; } //Если же следующий символ - буква ЛА - тогда считываем до тех пор, пока дальше буквы ЛА или цифры. //Как только считали имя переменной, сравниваем ее со списком зарезервированных слов. Если не совпадает ни с одним из них, //считаем, что получили переменную, имя которой запоминаем, а за текущую лексему считаем лексему идентификатора. //Если совпадает с каким-либо словом из списка - считаем что получили лексему, соответствующую этому слову. else if(isIdentifierStart(ch_)) { string buffer; while(isIdentifierBody(ch_)) { buffer += ch_; nextChar(); } transform(buffer.begin(), buffer.end(), buffer.begin(), ::tolower); map::iterator kwd = keywords_.find(buffer); if(kwd == keywords_.end()) { token_ = T_IDENTIFIER; stringValue_ = buffer; } else { token_ = kwd->second; } } //Символ не является буквой, цифрой, "/" или признаком конца файла else { switch(ch_) { //Признак лексемы открывающей скобки - встретили "(" case '(': token_ = T_LPAREN; nextChar(); break; //Признак лексемы закрывающей скобки - встретили ")" case ')': token_ = T_RPAREN; nextChar(); break; //Признак лексемы ";" - встретили ";" case ';': token_ = T_SEMICOLON; nextChar(); break; //Если встречаем ":", то дальше смотрим наличие символа "=". Если находим, то считаем что нашли лексему присваивания //Иначе - лексема ошибки. case ':': nextChar(); if(ch_ == '=') { token_ = T_ASSIGN; nextChar(); } else { token_ = T_ILLEGAL; } break; //Если встретили символ "<", то либо следующий символ "=", тогда лексема нестрогого сравнения. Иначе - строгого. case '<': token_ = T_CMP; nextChar(); if(ch_ == '=') { cmpValue_ = C_LE; nextChar(); } else { cmpValue_ = C_LT; } break; //Аналогично предыдущему случаю case '>': token_ = T_CMP; nextChar(); if(ch_ == '=') { cmpValue_ = C_GE; nextChar(); } else { cmpValue_ = C_GT; } break; //Если встретим "!", то дальше должно быть "=", тогда считаем, что получили лексему сравнения //и знак "!=" иначе считаем, что у нас лексема ошибки case '!': nextChar(); if(ch_ == '=') { nextChar(); token_ = T_CMP; cmpValue_ = C_NE; } else { token_ = T_ILLEGAL; } break; //Если встретим "=" - лексема сравнения и знак "=" case '=': token_ = T_CMP; cmpValue_ = C_EQ; nextChar(); break; //Знаки операций. Для "+"/"-" получим лексему операции типа сложнения, и соответствующую операцию. //для "*" - лексему операции типа умножения case '+': nextChar(); // Ищем оператор инкремента if(ch_ == '+') { token_ = T_INC; nextChar(); } else { token_ = T_ADDOP; arithmeticValue_ = A_PLUS; } break; case '-': nextChar(); // Ищем оператор декремента if(ch_ == '-') { token_ = T_DEC; nextChar(); } else { token_ = T_ADDOP; arithmeticValue_ = A_MINUS; } break; case '*': token_ = T_MULOP; arithmeticValue_ = A_MULTIPLY; nextChar(); break; //Иначе лексема ошибки. default: token_ = T_ILLEGAL; nextChar(); break; } } } void Scanner::skipSpace() { while(isspace(ch_)) { if(ch_ == '\n') { ++lineNumber_; } nextChar(); } } void Scanner::nextChar() { ch_ = input_.get(); } const char * tokenToString(Token t) { return tokenNames_[t]; }