Как создать синтаксический анализатор на С++
как создать программу на С++, которая переводила, например, бы этот текст:
main(form(text(hello())text1(new)))
в этот:
main form text hello
main form text1 new
я уже пытался это сделать, но пока не получилось:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
string code = "main(form(text(hello(world))text1(new)))";
vector<string> real_code;
string token;
for(char k: code)
{
if(k == '(')
{
real_code.push_back(token);
real_code.push_back("(");
token = "";
}else if(k == ')')
{
real_code.push_back(token);
real_code.push_back(")");
token = "";
}else{token += k;}
}
for(string j: real_code)
{
cout << j << " ";
}cout << endl << endl;
vector<string> names;
for(int i = 0; i < 11; i++)
{
string here = real_code[i];
string next = (i < 10)? real_code[i+1] : real_code[i];
cout << "\n=> ";
if(here == ")")
{
for(string j: names)
{
cout << j << " ";
}//cout << endl;
names.pop_back();
} else if(here == "("){
continue;
} else {
if(next == ")")
{
names.push_back(here);
for(string j: names)
{
cout << j << " ";
}
}
if(next == "(")
{
names.push_back(here);
}
}
}
}
(Заранее простите за говнокод)
Ответы (2 шт):
#include <string>
#include <sstream>
#include <vector>
using namespace std;
vector<string> parseInput(const string& input) {
vector<string> result;
string current;
for (char c : input) {
if (c == '(' || c == ')') {
if (!current.empty()) {
result.push_back(current);
current.clear();
}
} else {
current += c;
}
}
if (!current.empty()) {
result.push_back(current);
}
return result;
}
void printParsed(const vector<string>& parsed) {
vector<string> stack;
for (const string& token : parsed) {
if (!token.empty()) {
stack.push_back(token);
for (const string& s : stack) {
cout << s << " ";
}
cout << endl;
}
}
}
int main() {
string input = "main(form(text(hello())text1(new)))";
vector<string> parsed = parseInput(input);
printParsed(parsed);
return 0;
}
Вывод:
main form
main form text
main form text hello
main form text1
main form text1 new
Вам потребуются следующие заголовки: vector, optional*, string и iostream.
Пусть у нас будет перечисление
enum class TokenType
{
ident,
open_par,
close_par,
}
Теперь у нас есть перечисление токенов, вы можете добавлять туда нужные вам типы токенов, пока что я добавил только, те которые были нужны вам сейчас.
Пусть у нас будет структура токена
struct Token
{
std::optional<std::string> value;
TokenType type;
}
Пусть у нас есть функция для преобразования токенов в строку.
std::string token_to_string(Token token)
{
if(token.type == TokenType::ident)
return token.value.value();
else if(token.type == TokenType::open_pra)
return " ";
else
return "";
}
Теперь вы можете добавлять или изменять вывод текста. Допустим вы захотите, чтобы open_pra был текст, допустим (, а не пробел. Тогда вам надо просто заменить " " на "("
Теперь пусть будет обратная функция для преобразования строки в токен
Token string_to_token(std::string str)
{
Token token;
if(str == "(")
{
toke.type = TokenType::open_pra;
}
else if(str == ")")
{
token.type = TokenType::close_pra;
}
else
{
token.type = TokenType::ident;
token.value = str;
}
return token;
}
Вы также можете расширять эту функцию по мере расширения перечисления.
Теперь самое главное - превращение кода в токены. За это будет отвечать функция tokenizer.
std::vector<Token> tokenizer(std::string code)
{
std::vector<Token> tokens;
std::string buffer;
for(size_t i = 0; i < code.size(); i++)
{
char symbol = code.at(i);
if(std::isalpha(symbol))
{
buffer.push_back(symbol);
i++;
while(i < code.size() && std::isalnum(code.at(i)))
{
buffer.push_back(code.at(i));
i++;
}
i--;
tokens.push_back(string_to_token(buffer));
buffer.clear();
}
else if(symbol == '(')
{
tokens.push_back(Token{.value = "(", .type = TokenType::open_pra});
}
else if(symbol == ')')
{
tokens.push_back(Token{.value = ")", .type = TokenType::close_pra});
}
else
{
// Можете добавить свой обработчик ошибок при не определённой лексеме, всё же ответы не об этом
std::cerr << "Unknown lexeme\n";
exit(EXIT_FAILUERE);
}
}
return tokens;
}
Теперь мы можем приврать код в вектор токенов с помощью этой функции. Осталась только функция main.
int main()
{
std::string code = "main(form(text(hello())text1(new)))";
std::vector<Token> tokens = tokenizer(code);
for(size_t i = 0; i < tokens.size(); i++)
{
Token token = tokens.at(i);
if(token.type == TokenType::close_pra && i + 1 < tokens.size() && tokens.at(i + 1))
{
std::cout << "\n";
i += 2;
}
else
{
std::cout << token_to_string(token);
}
}
return 0;
}
optional* - для использования optional вам потребуется С++17 или новее.