Я ищу помощь в отношении специально созданного класса Lexer и использую его для анализа входных данных. Наш профессор предоставил нам некоторый скелетный код для нашего проекта, и мы ДОЛЖНЫ его использовать.
Моя проблема в том, что мы должны иметь возможность вызывать несколько функций одновременно для сортировки таблиц и объединения / сортировки столбцов отдельных таблиц. Например, наш вклад будет выглядеть примерно так:
дисплей <‘имя_файла> отсортировано <«Column2>
где «display» и «sortedby» — это ключевые слова, а column2 будет отсортировано по номеру или алфавиту — в зависимости от содержимого.
Нам дан алгоритм, используемый для сортировки, и моя текущая проблема не в реализации этого, а в том, что наш Lexer / Parser может считывать более одного ввода.
В настоящее время я могу заставить работать только бит «display». Все остальное просто выплевывает сообщение об ошибке.
Я просмотрел код, попытался изменить некоторые из логики — переключение операторов с истины на ложь, подкачка &&’s и ||’, даже пытались некоторые заявления if-else без удачи.
Я мог бы действительно использовать некоторые советы! Часть кода, который мы даем, в оригинальном формате:
Lexer.h:
#ifndef _LEXER_H
#define _LEXER_H
#include <string>
enum token_types_t {
IDENT, // a sequence of alphanumeric characters and _, starting with alpha
TAG, // sequence of characters between < >, no escape
ENDTOK, // end of string/file, no more token
ERRTOK // unrecognized token
};
struct Token {
token_types_t type;
std::string value;
// constructor for Token
Token(token_types_t tt=ENDTOK, std::string val="") : type(tt), value(val) {}
};
class Lexer {
public:
// constructor
Lexer(std::string str="") : input_str(str), cur_pos(0), in_err(false),
separators(" \t\n\r") { }
//modifiers
void set_input(std::string); // set a new input,
void restart(); // move cursor to the beginning, restart
Token next_token(); // returns the next token
bool has_more_token(); // are there more token(s)?
private:
std::string input_str; // the input string to be scanned
size_t cur_pos; // current position in the input string
bool in_err; // are we in the error state?
std::string separators; // set of separators; *not* the best option!
};
#endif
Lexer.cpp:
#include "Lexer.h"#include <iostream>
using namespace std;
Token Lexer::next_token() {
Token ret;
size_t last;
if (in_err) {
ret.type = ERRTOK;
ret.value = "";
return ret;
}
// if not in error state, the default token is the ENDTOK
ret.type = ENDTOK;
ret.value = "";
if (has_more_token()) {
last = cur_pos; // input_str[last] is a non-space char
if (input_str[cur_pos] == '<') {
cur_pos++;
while (cur_pos < input_str.length() && input_str[cur_pos] != '>')
cur_pos++;
if (cur_pos < input_str.length()) {
ret.type = TAG;
ret.value = input_str.substr(last+1, cur_pos-last-1);
cur_pos++; // move past the closing "} else {
in_err = true;
ret.type = ERRTOK;
ret.value = "";
}
} else {
while (cur_pos < input_str.length() &&
separators.find(input_str[cur_pos]) == string::npos &&
input_str[cur_pos] != '<') {
cur_pos++;
}
ret.type = IDENT;
ret.value = input_str.substr(last, cur_pos-last);
}
}
return ret;
}
void Lexer::set_input(string str) {
input_str = str;
restart();
}
bool Lexer::has_more_token() {
while (cur_pos < input_str.length() &&
separators.find(input_str[cur_pos]) != string::npos) {
cur_pos++;
}
return (cur_pos < input_str.length());
}
void Lexer::restart() {
cur_pos = 0;
in_err = false;
}
Наш парсер (часть большего файла .cpp):
bool parse_input(Lexer lexer, string& file_name) {
Token file_name_tok;
if (!lexer.has_more_token() ||
(file_name_tok = lexer.next_token()).type != TAG)
return false;
if (lexer.has_more_token())
return false;
file_name = file_name_tok.value;
return true;
}
Функция отображения (часть того же файла .cpp, что и анализатор):
void display(Lexer cmd_lexer) {
string file_name, line;
if (!parse_input(cmd_lexer, file_name)) {
error_return("Syntax error: display <filename>");
return;
}
ifstream ifs(file_name.c_str());
string error_msg;
if (ifs) {
if (!is_well_formed(ifs, error_msg)) {
error_return(error_msg);
} else {
ifs.clear();
ifs.seekg(0, ios::beg);
print_well_formed_file(ifs);
}
while (ifs.good()) {
getline (ifs, line);
cout << line << endl;
}
} else {
error_return("Can't open " + file_name + " for reading");
}
ifs.close();
}
В зависимости от ответа на мой комментарий, я решу проблему следующим образом:
Если display
Команда должна прочитать исходный файл и проанализировать его, вы можете реализовать его через стек. Всякий раз, когда display
директива найдена и проанализирована, вы помещаете новый экземпляр лексера в стек. Используйте вершину стека для «текущего» лексера.
Если display
команда должна прочитать и выполнить какую-либо операцию с файлом, не связанным с фактическим анализом, затем рассмотреть возможность сохранения инструкций в промежуточной форме фиксированной формы, а когда закончите анализ, вы «выполните» этот промежуточный формат. Это способ, которым почти все современные скриптовые языки делают это.
Кажется, достаточно просто. Чтобы прочитать более одного ввода, вам нужно более одного Lexer / Parser. Просто создайте один для каждого ввода, который вы должны прочитать.