0

したがって、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>

私は非常に多くのことを試しました。ベクトル、マップを使用して、最終的にマルチマップを使用することにしました。私が何をしても同じ問題に陥るので、おそらく私が選択したデータ構造とは何の関係もありません。

問題は、1 行ずつ読んでいるため、必要以上に計算してしまうことです。しかし、マルチマップが消去/ポップされた後に反復するよりも、各行のforループでマルチマップを計算/反復しない場合。出力を正常に表示するために論理的に何をすべきか、または正しい軌道に乗っているかどうかはわかりません。

これまでのところ、私の .cpp ファイルは次のとおりです。コメントは過去の試みであり、当面は使用しないことを選択したため、無視してください。また、このバージョンではベクトルを使用していないため、ベクトル関連のコードは無視してかまいません。私は今、マルチマップを使用しています。

#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
}
}
4

2 に答える 2

1

トップレベルの構造(つまり astructまたは a 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;

これにより、必要と思われるネストされた構造が非常に簡単に得られるだけでなく、関連するすべてのデータを小さな構造にしっかりとまとめることができます。

あなたの他の大きな問題は解析にあるようです。コンパイラと解析についてもっと読んで、入力処理と解析を2つのコンポーネントに分割する、より伝統的なレクサーパーサーの種類のパーサーを実装することをお勧めします。パーサー部分を手作業でコーディングしたい場合は、スコープとレベルの処理を非常に簡単にする再帰降下スタイルのパーサーをお勧めします。

于 2014-11-30T08:24:52.453 に答える
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 をコンパイルできない場合は、main の最後にある範囲ベースの for ループを置き換えるだけです)

于 2014-11-29T23:26:35.320 に答える