2016-03-27 8 views
2

私は現在非常に基本的なアセンブラを扱っています。アセンブラは、アセンブリ命令を受け取り、16ビットのバイナリ命令を出力して、使用しているコンピュータで使用する必要があります。子クラスの変数を設定する

私のデザイン戦略は、3つの子クラスを持つCommandクラスを作成することでした。 Aコマンド、Cコマンド、およびLコマンドの各タイプのコマンドがあります。私が扱っているコマンドのタイプを特定するために、コマンドタイプに "A"、 "C"、または "L"の文字列を指定しました。

EDIT:

私はまだ適切にこれらのクラスを派生する方法を考え出す多くの問題が生じています。基本的に、AとLのコマンドには変換が必要な整数値を表す "シンボル"文字列が必要ですが、Cコマンドには "dest"、 "comp"、 "jump"の値も必要ですが、 "シンボル"の値はありません。

Command.h

#include <fstream> 
#include <string> 

class Command { 
    std::string command_type = ""; 
protected: 
    void set_commandType(std::string x){command_type = x;} 
public: 
    Command(); 
    virtual ~Command(); 
    std::string commandType() const {return command_type;} 

}; 
class A_COMMAND : public Command 
{ 
    std::string symbol; 
public: 
    A_COMMAND(std::string s); 
    std::string get_symbol(){return symbol;}; //Returns the symbol or decimal Xxx of the current command @Xxx or (Xxx) . Should be called only when commandType() is A_COMMAND or L_COMMAND. 


}; 

class C_COMMAND : public Command 
{ 
    std::string comp; 
    std::string dest; 
    std::string jump; 
public: 
    C_COMMAND(std::string s, std::string d, std::string j); 
    std::string get_comp(){return comp;}; //Returns the comp mnemonic in the current C-command (28 possibilities). Should be called only when commandType() is C_COMMAND. 
    std::string get_dest(){return dest;}; //Returns the dest mnemonic in the current C-command (8 possibilities). Should be called only when commandType() is C_COMMAND. 
    std::string get_jump(){return jump;}; //Returns the jump mnemonic in the current C-command (8 possibilities). Should be called only when commandType() is C_COMMAND. 
}; 

class L_COMMAND : public Command 
{ 
    std::string symbol; 
public: 
    L_COMMAND(std::string s); 
    std::string get_symbol(){return symbol;}; //Returns the symbol or decimal Xxx of the current command @Xxx or (Xxx) . Should be called only when commandType() is A_COMMAND or L_COMMAND. 
}; 

Command.cpp

#include "Command.h" 

//--------------------------------------------- 
//A-Command functions 

Command::Command(){} 

A_COMMAND::A_COMMAND(std::string s) : symbol(s) 
{ 
    set_commandType("A"); 
} 


//--------------------------------------------- 
//C-Command functions 

C_COMMAND::C_COMMAND(std::string c, std::string d, std::string j) : comp(c), dest(d), jump(j) 
{ 
    set_commandType("C"); 
} 

//--------------------------------------------- 
//L-Command functions 

L_COMMAND::L_COMMAND(std::string s) : symbol(s) 
{ 
    set_commandType("L"); 
} 

私が持っている入力を処理しての両端キューを作成するための責任があるParser.cppとParser.hコマンド:

Parser.h

#include "Command.h" 
#include <vector> 
#include <deque> 


class Parser { 
private: 
    std::deque<Command> commands; 
public: 
    Parser(std::vector<std::string>); 
    bool hasMoreCommands() //are there more commands in the input? 
    { 
     if(commands.size() != 0) 
      return true; 
     else 
      return false; 
    } 
    void advance(){commands.pop_front();} //move to next command, should only work if hasMoreCommands returns false} 
    Command currentCommand(){return commands.front();} 
    std::vector<std::string> translateCommands(); //convert commands into binary strings 

}; 

Parser.cpp

#include "Parser.h" 
#include "Command.h" 
#include <vector> 
#include <iostream> 
#include <string> 
#include <unordered_map> 

bool inList(std::string& str, std::vector<std::string> list) //check if a given string contains one of the elements in the comp, dest, jump vectors. if so extract string for use in constructor 
{ 
    for(auto i = list.begin(); i!=list.end(); ++i) 
    { 
     std::size_t found = str.find(*i); 
     if(found!=std::string::npos) 
     { 
      return true; 
     } 
    } 
    return false; 
} 


Parser::Parser(std::vector<std::string> input) { 
    std::vector<std::string> dest_list = {"","M","D","MD","A","AM","AD","AMD"}; //all possible dests 
    std::vector<std::string> comp_list = {"0","1","D","A","!D","!A","-D","-A","D+1","A+1","D-1","A-1","D+A","D-A","A-D","D&A","D|A","M","!M","-M","M+1","M-1","D+M","D-M","M-D","D&M","D|M"}; //all possible comps 
    std::vector<std::string> jump_list = {"","JGT","JEQ","JGE","JLT","JNE","JLE","JMP"}; //all possible jumps 
    std::string dest, comp, jump; 
    std::deque<Command> commands; 
    for(std::vector<std::string>::const_iterator i = input.begin(); i != input.end(); ++i) 
    { 
     std::string line = *i; 
     if(*line.begin()=='@') //A-command 
     { 
      A_COMMAND command(line.substr(1)); 
      std::cout << "Command type: " << command.commandType() << "\n"; 
      std::cout << "symbol: " << command.get_symbol() << "\n"; 
      commands.push_back(command); 
     } 
     else if(*line.begin()=='(' && *line.rbegin() == ')' && line.size() > 2) //L-command 
     { 
      L_COMMAND command(line.substr(1, line.size() - 2)); 
      std::cout << "Command type: " << command.commandType() << "\n"; 
      std::cout << "symbol: " << command.get_symbol() << "\n"; 
      commands.push_back(command);  } 
     else 
     { 
      std::string rhs = line; 
      std::string dest_string = ""; 
      std::string comp_string = ""; 
      std::string jump_string = ""; 
      size_t equals_pos = line.find('='); //position of = in string, if present 
      size_t semi_pos = line.find(';'); //position of ; in string, if present 
      if(equals_pos != line.npos) //if there is an = then we have a dest 
      { 
       dest_string = line.substr(0,equals_pos); 
       rhs = line.substr(equals_pos+1); 
      } 
      if(semi_pos != line.npos) //jump 
      { 
       comp_string = rhs.substr(0,semi_pos); 
       jump_string = rhs.substr(semi_pos+1); 
      } 
      else //no jump 
      { 
       comp_string = rhs; 
      } 

      //now confirm if inputs are valid 
      if(inList(dest_string, dest_list)) 
       dest = dest_string; 
      else 
       std::cout << "invalid dest \n"; 
      if(inList(comp_string, comp_list)) 
       comp = comp_string; 
      else 
       std::cout << "invalid comp \n"; 
      if(inList(jump_string, jump_list)) 
       jump = jump_string; 
      else 
       std::cout << "invalid jump \n"; 

      C_COMMAND command(comp, dest, jump); 
      std::cout << "Command type: " << command.commandType() << "\n"; 
      std::cout << "dest: " << command.get_dest() << "\n"; 
      std::cout << "comp: " << command.get_comp() << "\n"; 
      std::cout << "jump: " << command.get_jump() << "\n"; 
      commands.push_back(command); 
     } 
    } 
} 

私のmain.cppには、入力をロードし、パーサを通してそれを渡します。私が持っている問題は、入力に何もできないということです。

私はそうのような関数を記述しようとしています

string translateLine(Command command, Code code) //Code is a table for translating the command 
{ 
    string output; 
    if(command.commandType() == "A") 
    { 
     string symbol = parser.currentCommand().get_symbol(); 
     cout << symbol << endl; 
     //perform binary conversion 
    } 
    /*else if(command.commandType() == "C") 
    { 
     string dest = command.get_dest(); 
    }*/ 
    //shouldn't be any L commands in symbol-less version 
    else 
    { 
     std::cout << "unexpected command value \n"; 
    } 
    return output; 
} 

しかし、すぐに、私は()get_symbolを呼び出すよう、コンパイラが関数を認識しません。これは基本コマンドにget_symbol()関数がないためですが、関数を基本クラスに正しく追加して下位3に引き出す方法がわかりません。それぞれのクラスですべての関数が使用されているわけではないため、純粋な仮想クラスです。どうすればこれを正しく行うことができますか?

+1

投稿したコードに問題はありません。したがって、問題はあなたが投稿していないコードになります。質問を編集し、[mcve]を含める必要があります。 –

+0

本当にset_commandType()をパブリック関数にしますか?そうでない場合は、 'command_type'を保護することを検討してください。派生クラスが実行中に型を変更できるようにしますか?そうでなければ、それを非公開にして、Commandから派生したクラスだけが使用できる保護されたコンストラクタの引数を値にします。 *(タイプのないコマンドについて話が合理的でない場合は、Commandインスタンスを作成する人を避けるために最善の方法です)。* – HostileFork

+0

元の例はうまくいくはずですか?面白い、食はこれらの宣言について不平を言う。私は元の質問を編集してより多くの情報を提供します。 – Araganor

答えて

2

まず、translateLine()はそれはCommand*パラメータ、ないCommandパラメータを取る必要があり、A_COMMANDC_COMMAND、またはL_COMMANDオブジェクトを受け入れることができる必要があります。ベースクラスへのポインタは、そのベースから派生したクラスへのポインタを保持できますが、ベースクラスのオブジェクトは派生オブジェクトを保持できません。

第二に、あなたも本当にdynamic_castを行わずA_COMMANDオブジェクトを指しているCommandポインタでA_COMMANDに属している関数を呼び出すことはできません。 dynamic_castは、実行時にCommand*からA_COMMANDへのポインタを変換することができ、指されたオブジェクトが実際にA_COMMANDオブジェクトでない場合はNULLを返します。

+0

ありがとう!私はこれを試してみましょう。 – Araganor

+0

イテレータはこの権利のために動作するはずですか?もしそうなら、そのようなイテレータの動的キャストはどのように見えますか? – Araganor

+0

もし彼が望むなら、 'dynamic_cast'が失敗の際に' NULL'/'nullptr'を返す代わりに例外をスローするキャッチでポインタの代わりに参照を使うこともできます。 –

0

基本的な問題は、ランタイムタイプの情報を再開発していることです。 「command_type = A」をclass A_COMMANDに追加する必要はありません。少なくとも1つの仮想メソッドがある場合、C++はオブジェクトのタイプをすでに知っています。あなたのクラスには仮想デストラクタが必要なようです。