一个文本翻译工具的实现
2016-01-15 12:29
507 查看
一、需求
一个文本翻译工具,功能类似于汇编器,能够把一些字符串(程序的助记符)翻译为其他的字符串或者数字,并打印到文本文件中。完成的功能如下:
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位。
程序地址分配,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个,那就只处理相应的前几个文件)
输入文件、最终数据文件、寄存器信息文件、宏展开后的数据文件、宏信息文件
默认第二个参数是输入的文件。
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、读取需要转换的文件
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,用它的Handle成员来统一处理。
5、AsmAlgorithm类
AsmAlgorithm类如下:
其中MacroInfo这个宏定义成了:
6、一些全局变量以及宏等
7、AsmAlgorithm处理
Handle成员:
数据准备工作:
接着查找宏域和数据域
处理宏域并宏展开:
处理完宏域之后,接着处理数据域(把它们放入一个vector的m_macrodata里面),处理数据域时,遇到宏定义需要宏展开(宏的信息在m_macro中),并且还需要填写标签地址信息(标签地址信息是一个全局变量g_labeladdrmap)。
数据处理:
我把需要转换的命令分成了五类:标签(%开头的)、跳转(J开头的)、操作(add、sub、mul等)、shell(nop、shl、rttl等)、传送(ld,st),它们不区分大小写,我统一用MyToLower转换成小写了。
fun_manager在必要的时候分别指向这五类函数。
主要算法是遍历每一行,通过命令来判断这一行应该属于哪一类处理,然后调用相应的函数来处理这一行数据。
再介绍辅助函数
MyToLower:
Wrapper:
SplitError:
因为我的程序也会在gcc下编译,所以MySprintf是:
AddRegAddr:
处理宏域的GetMacroInfo:
获取数据域内的信息GetDataAreaInfo:
最后介绍五类转换函数:
标签的LabelHandle:
这里为了和另外几个转换函数风格一致,我用了isource容器,但用不上,需要注意这个isource不能添加到输出容器中。
跳转的JumpHandle:
操作的OperatorHandle:
shell的ShellHandle:
bool AsmAlgorithm::ShellHandle(const int cmdindex, const vector<string> &isource,
vector<string>&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;
}
传送的TransmitHandle:
获取私有成员变量的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()<<endl;
break;
case g_parai::R:
cout << "print register info :" << endl;
cout << myasm.GetReg() << endl;
break;
case g_parai::MD:
cout << "print macro and data info :" << endl;
cout << myasm.GetMacroData() << endl;
break;
case g_parai::M:
cout << "print macro info :" << endl;
cout << myasm.GetMacro() << endl;
break;
default:
break;
}
}
9、在Win控制台和gcc下的makefile
win32:
这个需要vcvars32.bat的环境支持。我开始编的时候能编译过去,后来不知调整了什么就编译不过了,只能分开编译。
gcc:
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这儿了,有需要的朋友可以下载。
一个文本翻译工具,功能类似于汇编器,能够把一些字符串(程序的助记符)翻译为其他的字符串或者数字,并打印到文本文件中。完成的功能如下:
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} |
每一行有效语句分配一个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<int> paraset;//带‘-’参数集合,存储的是到全局数组的偏移量 vector<string> 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<std::string>& GetData(); const std::vector<std::string>& GetReg(); const std::vector<std::vector<std::string>>& GetMacroData(); const std::set<MacroInfo>& GetMacro(); private: //注释处理 无 //标签处理 static bool LabelHandle(const int cmdindex, const std::vector<std::string> &isource, std::vector<std::string> &odst, std::string &errmsg); //跳转处理 拿到输入的数据,按照某种格式输出 static bool JumpHandle(const int cmdindex, const std::vector<std::string> &isource, std::vector<std::string> &odst, std::string &errmsg); //操作处理 static bool OperatorHandle(const int cmdindex, const std::vector<std::string> &isource, std::vector<std::string>&odst, std::string &errmsg); //shell处理 static bool ShellHandle(const int cmdindex, const std::vector<std::string> &isource, std::vector<std::string>&odst, std::string &errmsg); //传送处理 static bool TransmitHandle(const int cmdindex, const std::vector<std::string> &isource, std::vector<std::string>&odst, std::string &errmsg); ////////////////////////////////////////////////////////////////////////// //辅助方法 //大写转小写 static std::string MyToLower(const std::string & str); //包裹函数 把一个容器包装成一个字符串 对应于文件1中的字符串格式 static std::string Wrapper(const std::vector<std::string> isource); //包裹文件2的字符串格式 static std::string Wrapper(const std::pair<std::string, int> & 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<MacroInfo> &odata, std::string & errmsg); //获取数据域内的信息 static bool GetDataAreaInfo(const std::string &idata, const std::set<MacroInfo> &vmi, std::vector<std::vector<std::string>> &odata, std::string &errmsg); private: std::vector<std::string > m_data;//最终的数据信息,若有文件1,将会写入到文件1 std::vector<std::string > m_reg;//寄存器信息,若有文件2,将会写入到文件2 std::vector<std::vector<std::string>> m_macrodata;//宏展开后的数据信息,若有文件3,将会写入到文件3 std::set<MacroInfo> m_macro;//宏信息,若有文件4,将会写入到文件4 };
其中MacroInfo这个宏定义成了:
struct MacroInfo { std::string name;//这个宏的名字 std::string parameter;//这个宏的参数 std::vector<std::vector<std::string>> 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<pair<string, int>> g_reglist;//寄存器列表 //标签地址 static map<string, int> 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<string> &, vector<string> &, string &);//函数对象 vector<string> cmdlist;//命令列表,含所有命令 map<int, fun_manager,greater<int>> 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<vector<string>>::size_type i = 0; i < m_macrodata.size(); i++) {//执行原始文件的每一行 vector<string> 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<int, fun_manager>&item){return cmdoffset >=item.first; }); vector<string> 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<string> 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<std::string, int> & 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<string, int>(reg, g_regaddr)); }
处理宏域的GetMacroInfo:
bool AsmAlgorithm::GetMacroInfo(const string &data, set<MacroInfo> &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<string> FML = String2Vector(line);//first macro list if (FML.size() != 1 || FML[0] != MACROSTART)//不是“macrostart”格式 { errmsg = SplitError("format is not \"macrostart\"", line); return false; } //先获取所有数据到容器里面, //空行舍弃、只含有空格的行也舍弃,以;开头的行(注释行)也舍弃 vector<vector<string>> linelist; while (getline(sin, line)) { if (line.empty()) continue;//空行 vector<string> 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<string> 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<MacroInfo> &vmi, vector<vector<string>> &odata,string &errmsg) {//遇到宏定义需要展开,并填写标签地址 odata.clear(); errmsg.clear(); stringstream sin(idata); string line; getline(sin, line);//第一行的格式应该是 datastart vector<string> 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<string> 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<vector<string>>::size_type i = 0; i < macroit->cmdlist.size(); i++) {//把标签和&的都添加前缀 vector<string> 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<string> &isource, vector<string> &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<string> &isource, vector<string> &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<string> &isource, vector<string>&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<string> &isource,
vector<string>&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;
}
传送的TransmitHandle:
bool AsmAlgorithm::TransmitHandle(const int cmdindex, const vector<string> &isource, vector<string>&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<string, int> & 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()<<endl;
break;
case g_parai::R:
cout << "print register info :" << endl;
cout << myasm.GetReg() << endl;
break;
case g_parai::MD:
cout << "print macro and data info :" << endl;
cout << myasm.GetMacroData() << endl;
break;
case g_parai::M:
cout << "print macro info :" << endl;
cout << myasm.GetMacro() << endl;
break;
default:
break;
}
}
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这儿了,有需要的朋友可以下载。
相关文章推荐
- CPP 虚函数、虚函数表及虚拟继承(转)
- Deploying Control Plane Policing
- Thrift的required和optional源码分析
- c++中extern关键字详解 知识补充笔记
- MBProgressHUD的基本使用
- 意外的结果-C++中的移位操作
- MFC自定义类访问主窗口控件
- LIBCD.lib(crt0.obj) : error LNK2001: unresolved external symbol _main 问题解决
- 单向链表LinkedList的使用
- cpp函数返回对象&&数组
- 继承、组合、委托
- Learn note(cpp): take care when use new in a code block.
- 如果在主串Tag的第pos个位置后存在
- BF算法
- 一个悲伤的gcc故事
- 用gcc编译opencv程序出错
- cocos2d-x-3.2创建项目中出现的一些问题
- vs使用Visual Leak Detector检测内存泄漏的某些注意事项
- opencv学习_11 (模板匹配(包括单模板和多模板))
- 【google protobuf】