您的位置:首页 > 编程语言 > C语言/C++

一个文本翻译工具的实现

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位。

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<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 翻译文件