一、需求
一个文本翻译工具,功能类似于汇编器,能够把一些字符串(程序的助记符)翻译为其他的字符串或者数字,并打印到文本文件中。完成的功能如下:
1. 助记符翻译
2. 程序地址分配
3. Label替换程序地址
4. 数据地址替换
5. 宏定义的展开
输入文件格式
1. 纯文本文件,允许行首有多个空格或者制表符。同一行内,语句之间用一个或者多个空格或者制表符隔开。
2. 不区分大小写。
3. 注释以“;”开始,占单独一行。处理的时候丢弃注释行。
4. Label以“%”开始,以“:”结束,占单独一行。主要用于表示跳转的目的地址。
5. 立即数以“#”开始,以16进制表示。
6. 立即程序地址和立即数据地址都以“&”开始,以16进制表示。
输出文件格式
文件1:
16’h程序地址:begin instr = {...}; end
文件2:
所有立即数据地址,每行一个。
助记符翻译
阴影文字不做翻译,直接输出。xx为my label的低8位。
Jmp &my_label |
{`brch, `drt, `cnd_non, `jmp_next, 8’hxx} |
Jz & my_label |
{`brch, `drt, `cnd_z, `jmp_next, 8’hxx} |
Jnz & my_label |
{`brch, `drt, `cnd_nz, `jmp_next, 8’hxx} |
Jc & my_label |
{`brch, `drt, `cnd_c, `jmp_next, 8’hxx} |
Jnc & my_label |
{`brch, `drt, `cnd_nz, `jmp_next, 8’hxx} |
Jw & my_label |
{`brch, `drt, `cnd_non, `jmp_wait, 8’hxx} |
|
|
Jmp @ r1r0 |
{`brch, `ptr, `cnd_non, `jmp_next, 8’h00} |
Jz @ r1r0 |
{`brch, `ptr, `cnd_z, `jmp_next, 8’h00} |
Jnz @ r1r0 |
{`brch, `ptr, `cnd_nz, `jmp_next, 8’h00} |
Jc @ r1r0 |
{`brch, `ptr, `cnd_c, `jmp_next, 8’h00} |
Jnc @ r1r0 |
{`brch, `ptr, `cnd_nc, `jmp_next, 8’h00} |
Jw @ r1r0 |
{`brch, `ptr, `cnd_non, `jmp_wait, 8’h00} |
Add rega regb |
{`arth, `add, `rega, `regb} |
Sub rega regb |
{`arth, `sub, `rega, `regb} |
Mul rega regb |
{`arth, `mul, `rega, `regb} |
Mac rega regb |
{`arth, `mac, `rega, `regb} |
Div rega regb |
{`arth, `div, `rega, `regb} |
Sqt rega regb |
{`arth, `sqt, `rega, `regb} |
Nop |
{16’b0} |
Shl 0nmb regs |
{`shft, `left, `with_0, `act, `nmb, `regs} |
Shl 1nmb regs |
{`shft, `left, `with_1, `act, `nmb, `regs} |
Shl snmb regs |
{`shft, `left, `with_s, `act, `nmb, `regs} |
Rttlregs |
{`shft, `left, `with_r, `act, 1’b1, `regs} |
|
|
Shr 0nmb regs |
{`shft, `right, `with_0, `act, `nmb, `regs} |
Shr 1nmb regs |
{`shft, `right, `with_1, `act, `nmb, `regs} |
Shr snmb regs |
{`shft, `right, `with_s, `act, `nmb, `regs} |
Rttrregs |
{`shft, `right, `with_r, `act, 1’b1, `regs} |
Ldregs #立即数 |
{`ldst, `ld_drt_data, `regs, 8’h立即数} |
Ldregs &立即地址 |
{`ldst, `ld_drt_addr, `regs, `立即数据地址} |
Stregs &立即地址 |
{`ldst, `st_drt_addr, `regs, `立即数据地址} |
Ldrega regb |
{`ldst, `reg_or_ptr, `rega, `ld_reg, `regb} |
Strega regb |
{`ldst, `reg_or_ptr, `rega, `st_reg, `regb} |
Ldregs @ r1r0 |
{`ldst, `reg_or_ptr, `regs, `ld_ptr, 4’b0} |
Stregs @ r1r0 |
{`ldst, `reg_or_ptr, `regs, `st_ptr, 4’b0} |
程序地址分配,Label程序地址替换
每一行有效语句分配一个16位16进制的程序地址。对于注释行不分配;对于label行,其表示的是下一行有效语句的地址。
源程序内跳转指令中的跳转目标地址会使用label表示,汇编器把label替换为label表示的实际地址的低8位。把跳转指令之前的“#label_page”替换为label表示的实际地址的高8位。
数据地址替换
保留源程序中的数据地址到输出文件1。同时将其输出到文件2。
宏定义的展开
使用macro_def: name(base_para)标记一段对程序的宏定义。在程序中通过macro_gen: name(base_arg)引用,汇编器将这一段宏定义展开,展开时用base_arg添加到宏定义代码段中的立即地址之前。
输入范例
; an input file example
mul r32_0 r32_1
%my_label ld r64_0 &alu_result
ld r3 #my_label_page
jz my_label
st r64_0 &data_save
ld r1 #5a
输出文件1范例
16’h0000: begin instr = {`arth, `mul, `r32_0, `r32_1} ; end
16’h0001: begin instr = {`ldst, `ld_drt_addr, `r64_0, `alu_result } ; end
16’h0002: begin instr = {`ldst, `ld_drt_data, `r3, 8’h00 } ;end
16’h0003: begin instr = {`brch, `drt, `cnd_z, `jmp_next, 8’h01} ; end
16’h0004: begin instr = {`ldst, `st_drt_addr, `r64_0, `data_save} ; end
16’h0005: begin instr = {`ldst, `ld_drt_data, `r2, 8’h5a} ; end
输出文件2范例
`define alu_result 8’h00
`define data_save 8’h01
二、实现
用VS2013控制台实现
1、需要转换的文件格式如下:
macrostart
macro_def : test1 ( base_para )
{
st r64_0 & data_save
ld r1 # 5a
arth_mus r32_0 r32_1
}
macro_def : test2 ( base_para )
{
arth_mus r32_0 r32_1
% my_label :
ld r64_0 & alu_result
jnz & my_label
}
datastart
; an input file example
arth_mus r32_0 r32_1
st r64_0 & szy_data_save
ld r1 # 5a
arth_mus r32_0 r32_1
ld r1 # 5a
arth_mus r32_0 r32_1
arth_mus r32_0 r32_1
st r64_0 & szy_data_save
ld r1 # 5a
arth_mus r32_0 r32_1
macro_gen : test2 ( lpf )
% my_label :
ld r64_0 & alu_result
ld r3 # my_label_page
jz & my_label
arth_mus r32_0 r32_1
macro_gen : test1 ( cic )
% szy_my_label :
ld r64_0 & szy_alu_result
st r64_0 & data_save
ld r1 # 5a
由于需要区别宏和数据,我用了macrostart和datastart分开这两部分。
2、需要的参数如下:
(至少两个参数)程序 输入文件
如果多余两个参数,则对参数进行分类:一类是以"-"开头的,一类则是文件(输入文件和输出文件)
对于以"-"开头的,目前只识别 -d、-r、-md、-m
这四个参数分别表示处理完翻译之后会打印 最终数据、寄存器信息、宏展开后的数据、宏信息
最多有5个文件,若有5个文件,则分别表示 (若不足5个,那就只处理相应的前几个文件)
输入文件、最终数据文件、寄存器信息文件、宏展开后的数据文件、宏信息文件
//命令行参数处理
set paraset;//带‘-’参数集合,存储的是到全局数组的偏移量
vector filelist;//文件列表
for (int i = 1; i < argc; i++)
{
string currpara(argv[i]);
if (currpara.empty())continue;
if (currpara[0] == '-')//带‘-’参数
{
//判断能否识别这个参数
auto it = find(g_para, g_para + g_paran, currpara);
if (it == g_para + g_paran)//没有找到
{
cout << "\nerror: not indentifies the \"" << currpara << "\".\n";
cout << "----------------------------------\n";
return 0;
}
paraset.insert(it - g_para);
}
else filelist.push_back(currpara);//文件
}
if (filelist.empty())
{
cout << "\nerror: not find infile.\n";
cout << "----------------------------------\n";
return 0;
}
else if (filelist.size() > 5)
{
cout << "\nerror: file num too more(greater than 5).\n";
cout << "----------------------------------\n";
return 0;
}
默认第二个参数是输入的文件。
g_para和g_paran是两个全局变量:
//四个带-的参数: -d,-rd,-md,-m
const int g_paran = 4;
const string g_para[g_paran] = { "-d", "-r", "-md", "-m" };//依次会打印asmalgorithm中的私有成员
enum g_parai{ D = 0, R, MD, M };
3、读取需要转换的文件
//获取输入文件数据
string filedata;//文件数据
string errmsg;
if (!ReadFile(filelist[0], filedata, errmsg))//获取数据
{
cout << "\n" << errmsg << "\nexit!\n";
cout << "----------------------------------\n";
return 0;
}
ReadFile实现为:
bool ReadFile(const string &file, string & filedata, std::string &errmsg)
{
filedata.clear();
errmsg.clear();
ifstream fin;
fin.open(file.c_str());
if (!fin.is_open())
{
errmsg = "not open file: \"" + file + "\"";
return false;
}
ostringstream ss;
ss << fin.rdbuf();
filedata = ss.str();
fin.close();
return true;
}
4、转换文件
//处理输入的文件数据
AsmAlgorithm myasm;
if (!myasm.Handle(filedata,errmsg))//处理数据
{
cout << "\n" << errmsg << "\nexit!\n";
cout << "----------------------------------\n";
return 0;
}
定义了一个类AsmAlgorithm,用它的Handle成员来统一处理。
5、AsmAlgorithm类
AsmAlgorithm类如下:
class AsmAlgorithm
{
public:
AsmAlgorithm();
~AsmAlgorithm();
public://行为
//核心算法处理
/*
总处理函数
对于原始文件的一行,判断是哪种处理,并调用相应处理, 然后包裹格式来获取新行
*/
bool Handle(const std::string &idata, std::string & errmsg);
//获取数据成员信息
const std::vector& GetData();
const std::vector& GetReg();
const std::vector>& GetMacroData();
const std::set& GetMacro();
private:
//注释处理 无
//标签处理
static bool LabelHandle(const int cmdindex, const std::vector &isource,
std::vector &odst, std::string &errmsg);
//跳转处理 拿到输入的数据,按照某种格式输出
static bool JumpHandle(const int cmdindex, const std::vector &isource,
std::vector &odst, std::string &errmsg);
//操作处理
static bool OperatorHandle(const int cmdindex, const std::vector &isource,
std::vector&odst, std::string &errmsg);
//shell处理
static bool ShellHandle(const int cmdindex, const std::vector &isource,
std::vector&odst, std::string &errmsg);
//传送处理
static bool TransmitHandle(const int cmdindex, const std::vector &isource,
std::vector&odst, std::string &errmsg);
//
//辅助方法
//大写转小写
static std::string MyToLower(const std::string & str);
//包裹函数 把一个容器包装成一个字符串 对应于文件1中的字符串格式
static std::string Wrapper(const std::vector isource);
//包裹文件2的字符串格式
static std::string Wrapper(const std::pair & regitem);
//添加一个立即地址到寄存器列表中
static void AddRegAddr(const std::string ®);
//拼接错误函数
static std::string SplitError(const std::string &cause, const std::string &line);
//获取宏域内的信息
static bool GetMacroInfo(const std::string &data, std::set &odata, std::string & errmsg);
//获取数据域内的信息
static bool GetDataAreaInfo(const std::string &idata, const std::set &vmi,
std::vector> &odata, std::string &errmsg);
private:
std::vector m_data;//最终的数据信息,若有文件1,将会写入到文件1
std::vector m_reg;//寄存器信息,若有文件2,将会写入到文件2
std::vector> m_macrodata;//宏展开后的数据信息,若有文件3,将会写入到文件3
std::set m_macro;//宏信息,若有文件4,将会写入到文件4
};
其中MacroInfo这个宏定义成了:
struct MacroInfo
{
std::string name;//这个宏的名字
std::string parameter;//这个宏的参数
std::vector> cmdlist;//这个宏里面的命令列表
friend bool operator<(const MacroInfo &item1, const MacroInfo &item2)
{
return item1.name < item2.name;
}
};
6、一些全局变量以及宏等
//宏定义和展开的入口
#define MACRODEF "macro_def"
#define MACROGEN "macro_gen"
//当前行地址
static int g_currlineaddr = -1;//<=0xffffffff
//寄存器地址
static int g_regaddr = -1;//<=0xff
vector> g_reglist;//寄存器列表
//标签地址
static map g_labeladdrmap;//<标签,地址>
//注释处理的助记符
static const string g_NC = ";";//note cmd
//标签处理的助记符
static const string g_LS = "%";//label start
static const string g_LE = ":";//label end
//跳转处理的的助记符
static const int g_JCN = 6;//Jump cmd num
static const string g_JC[g_JCN] = { "jmp", "jz", "jnz", "jc", "jnc", "jw" };//Jump cmd
enum g_JCI{ JMP = 0, JZ, JNZ, JC, JNC, JW };//Jump cmd index
static const int g_JFN = 2;//Jump flag num
static const string g_JF[g_JFN] = { "&", "@" };//Jump flag
enum g_JFI{ JAND = 0, JAT };//Jump cmd flag
//操作处理的的助记符
static const string g_OP = "arth_";//operator prefix
static const string g_OC = "arth";//operator cmd
//shell处理的助记符
static const int g_SCN = 5;//shell cmd num
static string g_SC[g_SCN] = { "nop", "shl", "rttl", "shr", "rttr" };//shell cmd
enum g_SCI{ NOP = 0, SHL, RTTL, SHR, RTTR };//shell cmd index
static const int g_SFN = 3;//shell flag num
static string g_SF[g_SFN] = { "0", "1", "s" };//shell flag
enum g_SFI{ SFI0 = 0, SFI1, SFIS };//shell flag index
//传送处理的助记符
static const int g_TCN = 2;//transmit cmd num
static string g_TC[g_TCN] = { "ld", "st" };//transmit cmd
enum g_TCI{ LD = 0, ST };//transmit cmd index
static const int g_TFN = 3;//transmit flag num
static string g_TF[g_TFN] = { "#", "&", "@" };//transmit flag num
enum g_TFI{TWELL=0,TAND,TAT};//transmit flag index
7、AsmAlgorithm处理
Handle成员:
数据准备工作:
bool AsmAlgorithm::Handle(const string &idata,string & errmsg)
{
errmsg.clear();
//私有数据的初始化
m_macro.clear();
m_macrodata.clear();
m_data.clear();
m_reg.clear();
g_labeladdrmap.clear();//清空标签地址
g_reglist.clear();//清空寄存器地址信息
接着查找宏域和数据域
/*
获取的文件数据
它有两部分,宏和数据(宏不是必须存在的(若存在,则必须在数据域前面),数据是必须存在的)
用macrostart开始的是宏,直到遇到datastart
用datastart开始的是数据,直到文件结束
*/
/*
宏的格式:文件数据中遇到这个宏名时会把里面的标签(格式为 % label :)
和 &地址(跳转中的&地址和传送中的地址)添加相应的label和地址的前缀(实参_)
macro_def : 宏名 ( 参数 )
{
文件数据中的数据格式
}
例如:
macro_def : test1 ( base_para )
{
st r64_0 & data_save
ld r1 # 5a
mul r32_0 r32_1
}
*/
//
//查找宏区域
auto macrostart = idata.find(MACROSTART);//查找macrostart
string tmpstr(idata.substr(0,macrostart));
int LF = tmpstr.rfind("\n");//从后往前找换行符,行首
if (LF + 1 != macrostart)//行首的下一个不是macrostart
{
errmsg = SplitError("\"macrostart\" is not at top of line",
idata.substr(LF+1, macrostart - LF) + MACROSTART + "...");
return false;
}
//查找数据区域
auto datastart = idata.find(DATASTART);//查找datastart
tmpstr = idata.substr(0, datastart);
LF = tmpstr.rfind("\n");//从后往前找换行符,行首
if (LF + 1 != datastart)//行首的下一个不是datastart
{
errmsg = SplitError("\"datastart\" is not at top of line",
idata.substr(LF+1, datastart - LF) + DATASTART + "...");
return false;
}
//判断宏域和数据域的位置关系
if (datastart == string::npos)//没有找到数据域开始的部分
{
errmsg = "not find data area from the infile.\n";
return false;
}
if (macrostart != string::npos && macrostart > datastart)//宏域在数据域之后,错误
{
errmsg = "the macrostart is not at behand of datastart.\n";
return false;
}
处理宏域并宏展开:
//
if (macrostart != string::npos)//有宏域
{
//处理宏域
if (!GetMacroInfo(idata.substr(macrostart, datastart - macrostart), m_macro, errmsg))
return false;
}
//宏展开和填写标签地址信息
if (!GetDataAreaInfo(idata.substr(datastart), m_macro, m_macrodata, errmsg))
return false;
处理完宏域之后,接着处理数据域(把它们放入一个vector的m_macrodata里面),处理数据域时,遇到宏定义需要宏展开(宏的信息在m_macro中),并且还需要填写标签地址信息(标签地址信息是一个全局变量g_labeladdrmap)。
数据处理:
//
//数据处理。。。
using fun_manager =
bool(*)(const int, const vector &, vector &, string &);//函数对象
vector cmdlist;//命令列表,含所有命令
map> cmdfunmap;//函数对象的映射关系
cmdfunmap.insert({ cmdlist.end() - cmdlist.begin(), LabelHandle });
cmdlist.push_back(g_LS);//标签 0
cmdfunmap.insert({ cmdlist.end() - cmdlist.begin(), JumpHandle });
cmdlist.insert(cmdlist.end(), g_JC, g_JC + g_JCN);//跳转
cmdfunmap.insert({ cmdlist.end() - cmdlist.begin(), OperatorHandle });
cmdlist.insert(cmdlist.end(), g_OC);//操作
cmdfunmap.insert({ cmdlist.end() - cmdlist.begin(), ShellHandle });
cmdlist.insert(cmdlist.end(), g_SC, g_SC + g_SCN);//shell
cmdfunmap.insert({ cmdlist.end() - cmdlist.begin(), TransmitHandle });
cmdlist.insert(cmdlist.end(), g_TC, g_TC + g_TCN);//传送
for (vector>::size_type i = 0; i < m_macrodata.size(); i++)
{//执行原始文件的每一行
vector oldformat = m_macrodata[i];//获取输入的数据格式
string cmd(MyToLower(oldformat[0]));//获取命令
auto cmdit = find(cmdlist.begin(), cmdlist.end(), cmd);//查找这个命令是否存在
if (cmdit == cmdlist.end())//没有找到
{
errmsg = SplitError("command is not find", Vector2String(oldformat));
return false;
}
const int cmdoffset = cmdit - cmdlist.begin();//cmd的偏移
const auto realit = find_if(cmdfunmap.cbegin(), cmdfunmap.cend(), //获取需要执行的cmd属于哪一类
[cmdoffset](const pair&item){return cmdoffset >=item.first; });
vector newformat;//输出的数据格式
//需要执行function的命令
if (!realit->second(cmdoffset - realit->first, oldformat, newformat, errmsg))
{
return false;
}
if (realit->first == 0)//标签的处理,不用添加到输出容器中
{
continue;
}
string newline = Wrapper(newformat);//包裹起来
//追加到新容器中,之后会把这个容器的内容写到目标文件中
m_data.push_back(newline);
}
我把需要转换的命令分成了五类:标签(%开头的)、跳转(J开头的)、操作(add、sub、mul等)、shell(nop、shl、rttl等)、传送(ld,st),它们不区分大小写,我统一用MyToLower转换成小写了。
fun_manager在必要的时候分别指向这五类函数。
主要算法是遍历每一行,通过命令来判断这一行应该属于哪一类处理,然后调用相应的函数来处理这一行数据。
再介绍辅助函数
MyToLower:
string AsmAlgorithm::MyToLower(const string & str)
{
string ret;
for (string::size_type i = 0; i < str.size();i++)
{
ret += tolower(str[i]);
}
return ret;
}
Wrapper:
string AsmAlgorithm::Wrapper(const vector isource)
{//格式:16’h0000: begin instr = {`arth, `mul, `r32_0, `r32_1}; end
g_currlineaddr++;
if (g_currlineaddr > 0xffffffff)
{
g_currlineaddr = 0;
}
char sztmp[50] = { 0 };//前缀部分
MySprintf(sztmp, sizeof(sztmp), "16'h%04x : begin instr = ", (short)(g_currlineaddr));
string vsstr = "{" + Vector2String(isource, ",") + "}";//数据部分
ostringstream sout;
sout << sztmp << setw(45) << left << vsstr << ";end";
return sout.str();
}
std::string AsmAlgorithm::Wrapper(const std::pair & regitem)
{//格式: `define alu_result 8’h00
char regstr[10] = { 0 };
MySprintf(regstr, sizeof(regstr), " 8'h%02x", (char)(regitem.second));
ostringstream sout;
sout << "`define " << setw(15) << left << regitem.first.c_str() << regstr;
return sout.str();
}
SplitError:
string AsmAlgorithm::SplitError(const string &cause, const string &line)
{
char szerr[300] = { 0 };
MySprintf(szerr, sizeof(szerr), "error[%s]: \"%s\"\n", cause.c_str(), line.c_str());
return string(szerr);
}
因为我的程序也会在gcc下编译,所以MySprintf是:
#if defined(_WIN32)|| defined(WIN32) || defined(_WIN64) || defined(WIN64) || defined(_WIN32_WINNT)
#define MySprintf sprintf_s//Win下
#else
#define MySprintf snprintf//linux下
#endif
AddRegAddr:
void AsmAlgorithm::AddRegAddr(const std::string ®)
{
g_regaddr++;
if (g_regaddr > 0xff)
{
g_regaddr = 0;
}
g_reglist.push_back(pair(reg, g_regaddr));
}
处理宏域的GetMacroInfo:
bool AsmAlgorithm::GetMacroInfo(const string &data, set &odata, string &errmsg)
{
/*
格式
macro_def : test1 ( base_para )
{
st r64_0 & data_save
ld r1 # 5a
mul r32_0 r32_1
}
*/
stringstream sin(data);
string line;
getline(sin, line);//第一行的格式应该是 macrostart
vector FML = String2Vector(line);//first macro list
if (FML.size() != 1 || FML[0] != MACROSTART)//不是“macrostart”格式
{
errmsg = SplitError("format is not \"macrostart\"", line);
return false;
}
//先获取所有数据到容器里面,
//空行舍弃、只含有空格的行也舍弃,以;开头的行(注释行)也舍弃
vector> linelist;
while (getline(sin, line))
{
if (line.empty()) continue;//空行
vector s2v = String2Vector(line);
if (s2v.empty()) continue;//只含有空格的行
if (s2v[0] == g_NC) continue;//注释行
linelist.push_back(s2v);
}
//对每一行,开始找macro_def
const int linesize = linelist.size();
int titleline = 0;
for (int i = 0; i < linesize; i++)
{
vector itemlist = linelist[i];
if (itemlist.size() != 6
|| itemlist[0] != MACRODEF
|| itemlist[1] != ":"
|| itemlist[3] != "("
|| itemlist[5] != ")")//这个macro_def不符合格式,错误
{
errmsg = SplitError("format is not \"macro_def : name ( base_para )\"", Vector2String(linelist[i]));
return false;
}
//找到这个宏的题头了
MacroInfo info;
info.name = itemlist[2];
info.parameter = itemlist[4];
titleline = i;//记录下题头行
//开始找这个宏包含的命令信息
//先找{符号
i++;
if (i == linesize)
{
errmsg = SplitError("not find the \"{\" after the macrotitile", Vector2String(linelist[titleline]));
return false;
}
itemlist = linelist[i];
if (!(itemlist.size() == 1 && itemlist[0] == "{"))//这行不是只含有{,则认为是错的
{
errmsg = SplitError("the line is not \"{\" after macrotitle", Vector2String(linelist[titleline]));
errmsg += "it is \"" + Vector2String(linelist[i]) + "\"\n";
return false;
}
//开始找命令行信息了
bool bfindend = false;//用}来判断这个宏的结束
for (i++; i < linesize;i++)
{
itemlist = linelist[i];
if (itemlist.size() == 1 && itemlist[0] == "}")//找到一个只含有}的行
{
bfindend = true;
break;
}
info.cmdlist.push_back(itemlist);
}
if (!bfindend)//遍历完宏域,都没有找到},则认为是错的
{
errmsg = SplitError("not find the \"}\" of the macro_def", Vector2String(linelist[titleline]));
return false;
}
//找到}了
//判断以前是否有这个宏定义
auto it = find_if(odata.begin(), odata.end(),
[info](const MacroInfo &item){return info.name == item.name; });
if (it != odata.end())//这个宏定义已经存在了
{
errmsg = "the macro define of \"" + info.name + "\"have 2 times or more.\n";
return false;
}
odata.insert(info);
}
return true;
}
获取数据域内的信息GetDataAreaInfo:
bool AsmAlgorithm::GetDataAreaInfo(const string &idata, const set &vmi,
vector> &odata,string &errmsg)
{//遇到宏定义需要展开,并填写标签地址
odata.clear();
errmsg.clear();
stringstream sin(idata);
string line;
getline(sin, line);//第一行的格式应该是 datastart
vector FDL = String2Vector(line);//first data list
if (FDL.size() != 1 || FDL[0] != DATASTART)//不是“datastart”格式
{
errmsg = SplitError("format is not \"datastart\"", line);
return false;
}
while (getline(sin, line))
{
if (line.empty())continue;//空行
vector linelist = String2Vector(line);//拆分当前行
if (linelist.empty())continue;//只有空格的行
if (linelist[0] == g_NC)continue;//注释行舍弃
string firstitem = MyToLower(linelist[0]);
const auto findpos = firstitem.find(g_OP);//查找operator处理
if (findpos == 0)//找到 arth_
{
linelist.insert(linelist.begin(), g_OC);
linelist[1] = firstitem.substr(g_OP.size());
}
const string cmd(linelist[0]);//获取命令
//只有宏展开入口macro_gen
if (cmd == MACROGEN)//宏展开
{
if (linelist.size() != 6
|| linelist[0] != MACROGEN
|| linelist[1] != ":"
|| linelist[3] != "("
|| linelist[5] != ")")//这个macro_gen不符合格式
{
errmsg = SplitError("format is not \"macro_gen : name ( para )\"", line);
return false;
}
//将这一行替换为宏定义
//查找这个宏
auto macroit = find_if(vmi.begin(), vmi.end(),
[linelist](const MacroInfo &item){return linelist[2] == item.name; });
if (macroit == vmi.end())//没有找到这个宏定义
{
errmsg = "not find macro define of the \"" + linelist[2] + "\".\n";
return false;
}
for (vector>::size_type i = 0; i < macroit->cmdlist.size(); i++)
{//把标签和&的都添加前缀
vector itemlist = macroit->cmdlist[i];//获取一个命令行的容器
const string mcmd(MyToLower(itemlist[0]));//获取命令
string firstitem = MyToLower(itemlist[0]);
const auto findpos = firstitem.find(g_OP);//查找operator处理
if (findpos == 0)//找到 arth_
{
itemlist.insert(itemlist.begin(), g_OC);
itemlist[1] = firstitem.substr(g_OP.size());
}
//跳转
auto jumpit = find_if(g_JC, g_JC + g_JCN,
[mcmd](const string & item){return item == mcmd; });
//传送
auto tramsit = find_if(g_TC, g_TC + g_TCN,
[mcmd](const string & item){return item == mcmd; });
if (jumpit != g_JC + g_JCN)//跳转处理
{
if (itemlist.size() == 3 && itemlist[1] == g_JF[g_JFI::JAND])//是jxx & xxx
{
itemlist[2] = linelist[4] + "_" + itemlist[2];
}
odata.push_back(itemlist);
}
else if (tramsit != g_TC + g_TCN)//传送处理
{
if (itemlist.size() == 4 && itemlist[2] == g_TF[g_TFI::TAND])//是 ld/st xxx & xxx
{
itemlist[3] = linelist[4] + "_" + itemlist[3];
}
odata.push_back(itemlist);
}
else if (mcmd==g_LS)//标签
{
if (itemlist.size() == 3 && itemlist[2] == g_LE)//完全匹配标签
{
itemlist[1] = linelist[4] + "_" + itemlist[1];
odata.push_back(itemlist);
//写到标签地址中
g_labeladdrmap[itemlist[1]] = odata.size() - g_labeladdrmap.size() - 1;
}
else
{
errmsg = SplitError("format is not \"% label :\" from macro \"" + macroit->name + "\"",
Vector2String(itemlist));
return false;
}
}
else//宏中的其他命令
{
odata.push_back(itemlist);
}
}
}
else//除了宏之外的行信息
{
if (cmd == g_LS)//标签行
{
if (linelist.size() == 3 && linelist[2] == g_LE)//完全匹配标签
{
odata.push_back(linelist);
//写到标签地址中
g_labeladdrmap[linelist[1]] = odata.size() - g_labeladdrmap.size() - 1;
}
else
{
errmsg = SplitError("format is not \"% label :\"", line);
return false;
}
}
else//其他的行
{
odata.push_back(linelist);
}
}
}
return true;
}
最后介绍五类转换函数:
标签的LabelHandle:
bool AsmAlgorithm::LabelHandle(const int cmdindex, const vector &isource,
vector &odst, string &errmsg)
{//格式 % label : //为了和另外几个xxxHandle函数统一,也用了输出容器,其实不需要输出容器
odst.clear();
errmsg.clear();
if (isource.size() != 3 || isource[2] != g_LE)
{
errmsg = AsmAlgorithm::SplitError("format is not \"% label :\"", Vector2String(isource));
return false;
}
//添加到地址 其实在宏展开的时候就已经写好了
g_labeladdrmap[isource[1]] = g_currlineaddr + 1;
return true;
}
这里为了和另外几个转换函数风格一致,我用了isource容器,但用不上,需要注意这个isource不能添加到输出容器中。
跳转的JumpHandle:
bool AsmAlgorithm::JumpHandle(const int cmdindex, const vector &isource,
vector &odst, string &errmsg)
{//格式 jxx &/@ label/r1r0
/*
Jmp & my_label {`brch, `drt, `cnd_non, `jmp_next, 8’hxx}
Jz & my_label {`brch, `drt, `cnd_z, `jmp_next, 8’hxx}
Jnz & my_label {`brch, `drt, `cnd_nz, `jmp_next, 8’hxx}
Jc & my_label {`brch, `drt, `cnd_c, `jmp_next, 8’hxx}
Jnc & my_label {`brch, `drt, `cnd_nc, `jmp_next, 8’hxx}
Jw & my_label {`brch, `drt, `cnd_non, `jmp_wait, 8’hxx}
Jmp @ r1r0 {`brch, `ptr, `cnd_non, `jmp_next, 8’h00}
Jz @ r1r0 {`brch, `ptr, `cnd_z, `jmp_next, 8’h00}
Jnz @ r1r0 {`brch, `ptr, `cnd_nz, `jmp_next, 8’h00}
Jc @ r1r0 {`brch, `ptr, `cnd_c, `jmp_next, 8’h00}
Jnc @ r1r0 {`brch, `ptr, `cnd_nc, `jmp_next, 8’h00}
Jw @ r1r0 {`brch, `ptr, `cnd_non, `jmp_wait, 8’h00}
*/
odst.clear();
errmsg.clear();
if (isource.size() != 3)
{
errmsg = SplitError("format is not \"jxx &/@ label/r1r0\"", Vector2String(isource));
return false;
}
string flag(MyToLower(isource[1]));//获取符号
auto flagit = find(g_JF, g_JF + g_JFN, flag);//查找符号
if (flagit == g_JF + g_JFN)//没找到符号
{
errmsg = SplitError("not find flag \"@/&\"", Vector2String(isource));
return false;
}
if (*flagit == g_JF[g_JFI::JAND])//&
{
if (g_labeladdrmap.find(isource[2]) == g_labeladdrmap.end())//查找标签
{//没找到
errmsg = SplitError("not find the label address", Vector2String(isource));
return false;
}
string tmparray[5] = { "`brch", "`drt", "`cnd_non", "`jmp_next", "8'h" };
odst.assign(tmparray, tmparray + 5);
char sztmp[20] = { 0 };
MySprintf(sztmp, sizeof(sztmp), "%02x", (char)(g_labeladdrmap[isource[2]]));
odst[4] += sztmp;
switch (cmdindex)
{
case g_JCI::JMP:
break;
case g_JCI::JZ:
odst[2] = "`cnd_z";
break;
case g_JCI::JNZ:
odst[2] = "`cnd_nz";
break;
case g_JCI::JC:
odst[2] = "`cnd_c";
break;
case g_JCI::JNC:
odst[2] = "`cnd_nc";
break;
case g_JCI::JW:
odst[3] = "`jmp_wait";
break;
default:
errmsg = SplitError("format is not \"jxx &/@ label/r1r0\"", Vector2String(isource));
return false;
}
return true;
}
else //@
{
if (MyToLower(isource[2]) != MyToLower("r1r0"))
{
errmsg = SplitError("not defined", Vector2String(isource));
return false;
}
string tmparray[5] = { "`brch", "`ptr", "`cnd_non", "`jmp_next", "8'h00" };
odst.assign(tmparray, tmparray + 5);
switch (cmdindex)
{
case g_JCI::JMP:
break;
case g_JCI::JZ:
odst[2] = "`cnd_z";
break;
case g_JCI::JNZ:
odst[2] = "`cnd_nz";
break;
case g_JCI::JC:
odst[2] = "`cnd_c";
break;
case g_JCI::JNC:
odst[2] = "`cnd_nc";
break;
case g_JCI::JW:
odst[3] = "`jmp_wait";
break;
default:
errmsg = SplitError("format is not \"jxx &/@ label/r1r0\"", Vector2String(isource));
return false;
}
return true;
}
}
操作的OperatorHandle:
bool AsmAlgorithm::OperatorHandle(const int cmdindex, const vector &isource,
vector&odst, string &errmsg)
{//格式 operator rega regb
/*
Add rega regb {`arth, `add, `rega, `regb}
Sub rega regb {`arth, `sub, `rega, `regb}
Mul rega regb {`arth, `mul, `rega, `regb}
Mac rega regb {`arth, `mac, `rega, `regb}
Div rega regb {`arth, `div, `rega, `regb}
Sqt rega regb {`arth, `sqt, `rega, `regb}
*/
odst.clear();
errmsg.clear();
if (isource.size() != 4)
{
errmsg = SplitError("format is not \"operator rega regb\"", Vector2String(isource));
return false;
}
//{`arth, `add, `rega, `regb}
odst.push_back("`" + isource[0]);
odst.push_back("`" + isource[1]);
odst.push_back("`" + isource[2]);
odst.push_back("`" + isource[3]);
return true;
}
shell的ShellHandle:
bool AsmAlgorithm::ShellHandle(const int cmdindex, const vector &isource,
vector&odst, string &errmsg)
{//格式 Shl 0 nmb regs
/*
Nop {16’b0}
Shl 0 nmb regs {`shft, `left, `with_0, `act, `nmb, `regs}
Shl 1 nmb regs {`shft, `left, `with_1, `act, `nmb, `regs}
Shl s nmb regs {`shft, `left, `with_s, `act, `nmb, `regs}
Rttl regs {`shft, `left, `with_r, `act, 1’b1, `regs}
Shr 0 nmb regs {`shft, `right, `with_0, `act, `nmb, `regs}
Shr 1 nmb regs {`shft, `right, `with_1, `act, `nmb, `regs}
Shr s nmb regs {`shft, `right, `with_s, `act, `nmb, `regs}
Rttr regs {`shft, `right, `with_r, `act, 1’b1, `regs}
*/
odst.clear();
errmsg.clear();
string tmparray[6] = { "`shft", "`left", "`with_", "`act", "`", "`" };
odst.assign(tmparray, tmparray + 6);
switch (cmdindex)
{
case g_SCI::NOP:
{
if (isource.size() != 1)
{
errmsg = SplitError("format is not \"nop\"", Vector2String(isource));
return false;
}
odst.clear();
odst.push_back("16'b0");
break;
}
case g_SCI::RTTL:
case g_SCI::RTTR:
{
if (isource.size() != 2)
{
errmsg = SplitError("format is not \"rttl/rttr regs\"", Vector2String(isource));
return false;
}
odst[2] = "`with_r";
odst[4] = "1'b1";
odst[5] += isource[1];
if (cmdindex == g_SCI::RTTR)
{
odst[1] = "`right";
}
break;
}
case g_SCI::SHL:
case g_SCI::SHR:
{
if (isource.size() != 4)
{
errmsg = SplitError("format is not \"shl/shr 0/1/s nmb regs\"", Vector2String(isource));
return false;
}
string flag(MyToLower(isource[1]));//获取符号
auto flagit = find(g_SF, g_SF + g_SFN, flag);
if (flagit == g_SF + g_SFN)//没找到
{
errmsg = SplitError("not find flag \"0/1/s\"", Vector2String(isource));
return false;
}
odst[2] += g_SF[flagit - g_SF];
odst[4] += isource[2];
odst[5] += isource[3];
if (cmdindex == g_SCI::SHR)
{
odst[1] = "`right";
}
break;
}
default:
{
errmsg = SplitError("format is not \"nop/shl/shr/rttl/rttr ...\"", Vector2String(isource));
return false;
}
}
return true;
}
bool AsmAlgorithm::TransmitHandle(const int cmdindex, const vector &isource,
vector&odst, string &errmsg)
{//格式 ld/st regx #/&/@/_ xxx
/*
Ld regs # 立即数 {`ldst, `ld_drt_data, `regs, 8’h立即数}
Ld regs & 立即地址 {`ldst, `ld_drt_addr, `regs, `立即数据地址}
St regs & 立即地址 {`ldst, `st_drt_addr, `regs, `立即数据地址}
Ld rega regb {`ldst, `reg_or_ptr, `rega, `ld_reg, `regb}
St rega regb {`ldst, `reg_or_ptr, `rega, `st_reg, `regb}
Ld regs @ r1r0 {`ldst, `reg_or_ptr, `regs, `ld_ptr, 4’b0}
St regs @ r1r0 {`ldst, `reg_or_ptr, `regs, `st_ptr, 4’b0}
*/
odst.clear();
errmsg.clear();
const int isourcesize = isource.size();
if (isourcesize != 3 && isourcesize != 4)
{
errmsg = SplitError("format is not \"ld/st regx #/&/@/_ xxx\"", Vector2String(isource));
return false;
}
if (isourcesize == 3)
{
string temparray[5] = { "`ldst", "`reg_or_ptr", "`", "`ld_reg", "`" };
odst.assign(temparray, temparray + 5);
odst[2] += isource[1];
odst[4] += isource[2];
if (cmdindex==g_TCI::ST)
{
odst[3] = "`st_reg";
}
return true;
}
else//4个元素
{
auto flagit = find(g_TF, g_TF + g_TFN, isource[2]);//查找标志
if (flagit == g_TF + g_TFN)//没找到
{
errmsg = SplitError("not find flag \"#/&/@\"", Vector2String(isource));
return false;
}
const int flagoffset = flagit - g_TF;//获取标志所在的偏移量
switch (flagoffset)
{
case g_TFI::TWELL://#
{
string temparray[4] = { "`ldst", "`ld_drt_data", "`", "8'h"};
odst.assign(temparray, temparray + 4);
odst[2] += isource[1];
//判断是label_page还是立即数
const auto findpos = isource[3].rfind("_page");
if (findpos == string::npos)//没找到 _page
{
odst[3] += isource[3];
}
else
{
string label = isource[3].substr(0, findpos);
if (g_labeladdrmap.find(label) == g_labeladdrmap.end())//查找标签
{//没找到
errmsg = SplitError("not find the label address", Vector2String(isource));
return false;
}
char hight8addr[20] = { 0 };
MySprintf(hight8addr, sizeof(hight8addr), "%02x", (char)(g_labeladdrmap[label] >> 8));
odst[3] += hight8addr;
}
return true;
}
case g_TFI::TAND://&
{
string temparray[4] = { "`ldst", "`ld_drt_addr", "`", "`" };
odst.assign(temparray, temparray + 4);
odst[2] += isource[1];
odst[3] += isource[3];
if (cmdindex==g_TCI::ST)
{
odst[1] = "`st_drt_addr";
}
//判断是否已存在,如果存在就不用写到寄存器地址列表中
string reg = isource[3];
auto regit = find_if(g_reglist.begin(), g_reglist.end(),
[reg](const pair & item){return item.first == reg; });
if (regit == g_reglist.end())
{
AddRegAddr(isource[3]);//添加到寄存器地址列表中去
}
return true;
}
case g_TFI::TAT://@
{
if (MyToLower(isource[3]) != MyToLower("r1r0"))
{
errmsg = SplitError("not defined", Vector2String(isource));
return false;
}
string temparray[5] = { "`ldst", "`reg_or_ptr", "`", "`ld_ptr", "4'b0" };
odst.assign(temparray, temparray + 5);
odst[2] += isource[1];
if (cmdindex == g_TCI::ST)
{
odst[3] = "`st_ptr";
}
return true;
}
default:
{
errmsg = SplitError("format is not \"ld/st regx #/&/@/_ xxx\"", Vector2String(isource));
return false;
}
}
}
return true;
}
获取私有成员变量的get函数不再列出。
8、打印结果
在主程序中,调用Handle处理完之后就可以打印信息:
//写入文件中
switch (filelist.size())
{
case 5:
cout << "macro info into " << filelist[4] << endl;
WriteFile(filelist[4], myasm.GetMacro());
case 4:
cout << "macro and data info into " << filelist[3] << endl;
WriteFile(filelist[3], myasm.GetMacroData());
case 3:
cout << "register info into " << filelist[2] << endl;
WriteFile(filelist[2], myasm.GetReg());
case 2:
cout << "data info into " << filelist[1] << endl;
WriteFile(filelist[1], myasm.GetData());
default:
break;
}
//打印到界面上
cout << endl;
for (auto it = paraset.begin(); it != paraset.end(); ++it)
{
switch (*it)
{
case g_parai::D:
cout << "print data info :" << endl;
cout << myasm.GetData()<
9、在Win控制台和gcc下的makefile
win32:
#Win下编译
#需要vcvars32.bat环境支持
#nmake 本文件
asmtranslator.exe : main.obj asmalgorithm.obj file.obj
link.exe main.obj asmalgorithm.obj file.obj /out:asmtranslator.exe
@del *.obj
main.obj:main.cpp
cl.exe /c /EHsc main.cpp
asmalgorithm.obj:asmalgorithm.cpp
cl.exe /c /EHsc asmalgorithm.cpp
file.obj:file.cpp
cl.exe /c /EHsc file.cpp
这个需要vcvars32.bat的环境支持。我开始编的时候能编译过去,后来不知调整了什么就编译不过了,只能分开编译。
gcc:
#g++ build
#make -f thisfile
AsmTranslator.out: main.o asmalgorithm.o file.o
g++ -o AsmTranslator.out main.o asmalgorithm.o file.o
#clear .o file
@rm -rf *.o
main.o: main.cpp
g++ -std=c++11 -c main.cpp
asmalgorithm.o: asmalgorithm.cpp asmalgorithm.h os.h
g++ -std=c++11 -c asmalgorithm.cpp
file.o: file.cpp file.h
g++ -std=c++11 -c file.cpp
10、测试:
我用1中的那个文件在gcc中使用 ./AsmTranslator.out infile.txt -d -r 测试结果如下:
----------welcome-----------------
welcom to ./AsmTranslator.out!
print data info :
16'h0000 : begin instr = {`arth,`mus,`r32_0,`r32_1} ;end
16'h0001 : begin instr = {`ldst,`st_drt_addr,`r64_0,`szy_data_save} ;end
16'h0002 : begin instr = {`ldst,`ld_drt_data,`r1,8'h5a} ;end
16'h0003 : begin instr = {`arth,`mus,`r32_0,`r32_1} ;end
16'h0004 : begin instr = {`ldst,`ld_drt_data,`r1,8'h5a} ;end
16'h0005 : begin instr = {`arth,`mus,`r32_0,`r32_1} ;end
16'h0006 : begin instr = {`arth,`mus,`r32_0,`r32_1} ;end
16'h0007 : begin instr = {`ldst,`st_drt_addr,`r64_0,`szy_data_save} ;end
16'h0008 : begin instr = {`ldst,`ld_drt_data,`r1,8'h5a} ;end
16'h0009 : begin instr = {`arth,`mus,`r32_0,`r32_1} ;end
16'h000a : begin instr = {`arth,`mus,`r32_0,`r32_1} ;end
16'h000b : begin instr = {`ldst,`ld_drt_addr,`r64_0,`lpf_alu_result} ;end
16'h000c : begin instr = {`brch,`drt,`cnd_nz,`jmp_next,8'h0b} ;end
16'h000d : begin instr = {`ldst,`ld_drt_addr,`r64_0,`alu_result} ;end
16'h000e : begin instr = {`ldst,`ld_drt_data,`r3,8'h00} ;end
16'h000f : begin instr = {`brch,`drt,`cnd_z,`jmp_next,8'h0d} ;end
16'h0010 : begin instr = {`arth,`mus,`r32_0,`r32_1} ;end
16'h0011 : begin instr = {`ldst,`st_drt_addr,`r64_0,`cic_data_save} ;end
16'h0012 : begin instr = {`ldst,`ld_drt_data,`r1,8'h5a} ;end
16'h0013 : begin instr = {`arth,`mus,`r32_0,`r32_1} ;end
16'h0014 : begin instr = {`ldst,`ld_drt_addr,`r64_0,`szy_alu_result} ;end
16'h0015 : begin instr = {`ldst,`st_drt_addr,`r64_0,`data_save} ;end
16'h0016 : begin instr = {`ldst,`ld_drt_data,`r1,8'h5a} ;end
print register info :
`define szy_data_save 8'h00
`define lpf_alu_result 8'h01
`define alu_result 8'h02
`define cic_data_save 8'h03
`define szy_alu_result 8'h04
`define data_save 8'h05
----------------------------------
11、我已压缩这个工程传到 http://download.csdn.net/detail/u011311985/9405378这儿了,有需要的朋友可以下载。