2014-11-29 1 views
0

Итак, я пытаюсь создать таблицу символов из входного файла, который содержит вложенные блоки C-стиля, подобные этому в C++;Создайте таблицу символов из файла в C++

A: { int a; float b; 
B: { float c; int d; 
C: { int b; int c; 
} 
} 
D: { float a; 
} 
} 

Результат должен выглядеть следующим образом.

A: a -> <int, A> 
b -> <float, A> 
B: a -> <int, A> 
b -> <float, A> 
c -> <float, B> 
d -> <int, B> 
C: a -> <int, A> 
b -> <int, C> -> <float, A> 
c -> <int C> -> <float, B> 
d -> <int, local to B> 
D: a -> <float D> -> <int, A> 
b -> <float, A> 

I'v пытался так много всего. Используя векторы, карты и теперь, наконец, я решил использовать multimaps. Независимо от того, что я делаю, я прихожу к одной и той же проблеме, поэтому она, вероятно, не имеет никакого отношения к структуре данных, которую я выбираю.

Проблема в том, что, поскольку я читаю строки за строкой, я получаю больше, чем нужно. Но если у меня не будет его/iterate мультиплексов в цикле for для каждой строки, я бы повторил их после того, как они были стерты/вытолкнуты. Я не уверен, что делать с логической логикой, чтобы выводить вывод на экран так, как надо, или если я даже на правильном пути.

Вот мой файл .cpp. Игнорируйте комментарии, поскольку они были прошлыми попытками, которые я отказался использовать на данный момент. Также в этой версии я не использую векторы, поэтому вы можете игнорировать векторный код. Я "м только с помощью multimaps Теперь.

#include<iostream> 
#include<fstream> 
#include<string> 
#include <sstream> 
#include <map> 
#include <vector> 
#include <algorithm> 
using namespace std; 

void ReadFromFile(); 
void main(){ 

    ReadFromFile(); 
    cin.get(); 
} 

void ReadFromFile(){ 

    stringstream ss; 
    string type = ""; 
    string var = ""; 
    string lable = ""; 
    string Obraket = ""; 
    string Cbraket = ""; 
    int braketCount = -1; 

    ifstream myfile("input1.txt"); 
    multimap<string, string> symbol; 
    multimap<string, multimap<string, string>> symbolL; 
    if (myfile.is_open()) 
    { 
     for (string line; getline(myfile, line);) 
     { 

      istringstream in(line); 
      if (in.str().find("}") == string::npos && in.str().find("{") != string::npos){ 

       in >> lable; 
       in >> Obraket; 

       braketCount++; 
       cout << Obraket << endl; 
       in >> type; 
       in >> var; 
       symbol.insert(pair<string, string>(var.substr(0, 1), type)); 

       if (in.str().find("float") != string::npos || in.str().find("int") != string::npos){ 

        var = ""; 
        type = ""; 
        in >> type; 
        in >> var; 
        if (type.length() > 1){ 
         symbol.insert(pair<string, string>(var.substr(0, 1), type)); 
        } 
       } 

       symbolL.insert(pair<string, multimap<string, string>>(lable,symbol)); 

        for (multimap<string, multimap<string, string>>::iterator it = symbolL.begin(); it != symbolL.end(); ++it){ 
        cout << it->first; 
        for (multimap<string, string>::iterator it2 = symbol.begin(); it2 != symbol.end(); ++it2){ 
         cout << it2->first << "-> " << "<" << it2->second << ">, " << it->first.substr(0, 1) << endl; 
        } 
        } 
      } 
      else if (in.str().find("}") != string::npos){ 
       in >> Cbraket; 
       //braketCount--; 
       cout << Cbraket << endl; 
       symbolL.erase(prev(symbolL.end())); 

       //symbol.erase(prev(symbol.end())); 
      } 

     } 

     myfile.close(); 
    } 
    else cout << "Unable to open file"; 



} 

Это выход я получаю.

{ 
A:a-> <int>, A 
b-> <float>, A 
{ 
A:a-> <int>, A 
b-> <float>, A 
c-> <float>, A 
d-> <int>, A 
B:a-> <int>, B 
b-> <float>, B 
c-> <float>, B 
d-> <int>, B 
{ 
A:a-> <int>, A 
b-> <float>, A 
b-> <int>, A 
c-> <float>, A 
c-> <int>, A 
d-> <int>, A 
B:a-> <int>, B 
b-> <float>, B 
b-> <int>, B 
c-> <float>, B 
c-> <int>, B 
d-> <int>, B 
C:a-> <int>, C 
b-> <float>, C 
b-> <int>, C 
c-> <float>, C 
c-> <int>, C 
d-> <int>, C 
} 
} 
{ 
A:a-> <int>, A 
a-> <float>, A 
b-> <float>, A 
b-> <int>, A 
c-> <float>, A 
c-> <int>, A 
d-> <int>, A 
D:a-> <int>, D 
a-> <float>, D 
b-> <float>, D 
b-> <int>, D 
c-> <float>, D 
c-> <int>, D 
d-> <int>, D 
} 
} 
+1

Хотя вы можете решить его только с помощью стандартных контейнеров, это будет очень сложно и сложно. Вместо этого нужен некоторый тип контейнера для сбора нескольких атрибутов в одну * структуру *. –

+0

Разве это не то, что я делаю? – Nonlin

+0

Вам нужна sg, как map >>, потому что вы хотите сопоставить для каждой заглавной (blockname) сопоставление переменных. Но реализовать его таким образом будет немного сложнее, чем мой код. Я делаю то же, что и вы, в моем ответе. Но вместо создания типов монстров я структурировал данные. – ch0kee

ответ

0

Вот оно!

Если вы принимаете совет, начните читать основную функцию вместо типы в верхней части.

Мне не нужен мультимап. Вместо копирования переменных родительского блока я обращаюсь только к родительскому контейнеру со своим индексом. Перед печатью происходит обход самый верхний блок, и он собирает все переменные, видимые в текущем блоке.

#include <algorithm> 
#include <cassert> 
#include <fstream> 
#include <iomanip> 
#include <iostream> 
#include <map> 
#include <stack> 
#include <string> 
#include <vector> 

using namespace std; 

typedef string type_t; //type of variable 
typedef string variable_t; //name of variable 
typedef string class_t; //name of 'class' (container) 

const int NO_PARENT = -1; //top-most 

typedef vector<class ClassSymbolTable> symbols_t; //we use vector to preserve order 

// main class, it stores symbols of a single class, and references its parent 
class ClassSymbolTable { 
    class_t _name; //class name 
    map<variable_t, type_t> _types; //map of variable types 
    vector<variable_t> _variables; //we use this vector to preserve order 
    symbols_t& _symbols; //reference to the symbol table 
    int _parent_index = NO_PARENT; //reference to parent index in symbol vector 


    //!! parent class, nullptr if top-level 
    ClassSymbolTable* parent() const { return _parent_index != NO_PARENT ? &_symbols[_parent_index] : nullptr; } 

    // does this class directly declares var ? 
    bool declares_variable(const variable_t& var) const { 
    return _types.find(var) != _types.end(); 
    } 

    // print variable info in desired format 
    void print_variable(const variable_t& var) { 
    if (declares_variable(var)) { 
     cout << " -> <" << _types[var] << ", " << _name << ">"; 
    } 
    if (parent()) { 
     parent()->print_variable(var); 
    } 
    } 

    // traverse classes up to top-level and collect variables in order 
    void collect_variables_to_print(vector<variable_t>& vars) { 
    if (ClassSymbolTable* p = parent()) { 
     p->collect_variables_to_print(vars); 
     // add variables defined on this level 
     vector<variable_t> add_vars; 
     for (size_t i = 0; i < _variables.size(); ++i) { 
     if (find(vars.begin(), vars.end(), _variables[i]) == vars.end()) { 
      // defined on this level 
      add_vars.push_back(_variables[i]); 
     } 
     } 
     vars.insert(vars.end(), add_vars.begin(), add_vars.end()); 
    } 
    else { 
     //top-level 
     vars = _variables; 
    } 
    } 

    // get depth for indentation 
    int get_depth() const { 
    int depth = 0; 
    for (ClassSymbolTable* p = parent(); p; p = p->parent()) { 
     ++depth; 
    } 
    return depth; 
    } 


    static size_t s_max_class_name_length; //for printing 
public: 
    // ctor 
    ClassSymbolTable(const string& name, int parent_index, symbols_t& symbols) 
    : _name(name), _parent_index(parent_index), _symbols(symbols) 
    { 
    s_max_class_name_length = max(s_max_class_name_length, name.length()); 
    } 

    // add variable 
    void add(const variable_t& var, const type_t& type) { 
    _variables.push_back(var); 
    _types[var] = type; 
    } 

    // print this class' vars in desired format 
    void print() { 
    cout.fill(' '); 
    const int indent = get_depth() + s_max_class_name_length + 3 /*for ':' */; 

    vector<variable_t> vars; 
    collect_variables_to_print(vars); 

    // print class name 
    string classname = _name + ": "; 

    cout.fill(' '); 
    cout.width(indent); 
    cout << classname; 

    // print vars 
    cout.width(0); 
    cout << vars[0]; 
    print_variable(vars[0]); 
    cout << endl; 

    for (size_t i = 1; i < vars.size(); ++i) { 
     cout.width(indent); 
     cout << ' '; //pad before 

     cout.width(0); 
     cout << vars[i]; 
     print_variable(vars[i]); 
     cout << endl; 
    } 
    cout.width(0); 
    } 


}; 

size_t ClassSymbolTable::s_max_class_name_length = 0; 


int main(int argc, char* argv[]) 
{ 
    ifstream in("input1.txt"); 
    assert(in.is_open()); 

    symbols_t symbols; 

    //collect symbols 
    const char* delimiters = ":;{}"; 
    vector<string> current_tokens; 
    string buffer; 
    stack<int> class_stack; //to manage class hierarchy, we stack the classes' index in the symbol vector 
    class_stack.push(NO_PARENT); //so we dont have to branch at first level 
    while (in >> buffer) { 
    size_t found = buffer.find_first_of(delimiters); 
    current_tokens.push_back(buffer.substr(0, found)); //either whole or until delimiter 

    if (found != string::npos) { //delimiter found 
     char delimiter = buffer[found]; 
     switch (delimiter) { 
     case ':': //class name 
     assert(current_tokens.size() == 1); 
     { 
      // add new class symbol table and refer to parent class 
      symbols.emplace_back(current_tokens[0], class_stack.top(), symbols); 
      // we rather store index in '{' for symmetric code 
     } 
     break; 
     case '{': //block open 
     assert(!symbols.empty()); 
     { 
      class_stack.push(symbols.size()-1); //stack the index for nested classes 
     } 
     break; 
     case '}': //block close 
     assert(!class_stack.empty()); 
     { 
      class_stack.pop(); //done with this class 
     } 
     break; 
     case ';': //variable 
     assert(!symbols.empty()); 
     assert(current_tokens.size() == 2); 
     { 
      // add variable to the current class symbol table 
      ClassSymbolTable& current_class = symbols.back(); 
      current_class.add(current_tokens[1], current_tokens[0]); 
     } 
     break; 
     } 

     //put back the remaining characters 
     current_tokens.clear(); 
     if (found < buffer.size() - 1) { 
     current_tokens.push_back(buffer.substr(found + 1)); 
     } 

    } 

    } 
    assert(class_stack.size() == 1 && class_stack.top() == NO_PARENT); //just to be sure 

    for (ClassSymbolTable& c : symbols) { 
    c.print(); 
    } 

    cout << "." << endl; 
    return 0; 
} 

Он может быть оптимизирован, чтобы избежать поиска в процессе печати, и вы можете также не следует хранить символы, если вы хотите, чтобы распечатать их. Здесь вы можете хранить локальные переменные, но основная идея будет такой же. И да, я использую еще один контейнер для управления вложением, стек :)

Только с помощью multimap ваши переменные будут перетасованы. Каким-то образом вы должны отслеживать заказ.

Я использую векторы для этого.

(Если вы не можете скомпилировать C++ 11, просто заменить диапазон на основе цикл в самом конце основной)

+0

Итак, как я это делаю (с несколькими картами), это просто не собирается его сокращать? – Nonlin

+0

Если вам действительно нужны мультимаксы, и порядок символов важен, вам нужно, например, сохраните индекс в многоточечном значении. Важен ли порядок? Кстати, аналогичная конструкция, map > делает почти то же самое (подумайте об этом), но может быть проще в использовании. Если у меня будет время, может быть, через несколько часов, я буду искать ошибку в вашем коде, но иногда, когда у нас заканчивается беспорядок, лучше начать все заново;) – ch0kee

1

Я хотел бы предложить структуру (т.е. struct или class) для верхнего уровня, имеют std::map той структуры верхнего уровня. Затем каждая структура в свою очередь содержит std::map для содержащихся символов, снова со структурой, которая содержит, среди прочего, тип символа.

Что-то же просто, как это:

struct LocalSymbol 
{ 
    std::string name; 
    enum 
    { 
     FLOAT, 
     INT 
    } type; 
    // Possibly other information needed for local symbols 
}; 

struct GlobalSymbol 
{ 
    std::string name; 
    // Possibly other information needed for global symbols 
    std::map<std::string, LocalSymbol> locals; 
} 

std::map<std::string, GlobalSymbol> globals; 

Это очень легко дать вам вложенную структуру, которую вы, кажется, хотите, а также соблюдение всех операций, связанных данных близко друг к другу на более мелкие структуры.

Ваша другая большая проблема, по-видимому, заключается в анализе, и я предлагаю вам больше узнать о компиляторах и синтаксическом анализе и попытаться реализовать более традиционный парсер парсеров-лексеров, где вы разделили обработку ввода и разбор на два компонента , Если вы хотите скомпоновать парсерную часть, я предлагаю recursive descent style parser, что упростит обработку областей и уровней.