一、需求分析
在使用MASM32编写Windows应用程序时,经常要调用Windows API接口函数 和 相应的数据结构,这些数据结构中有很多是类(Class),对于那些在MASM32没有定义的类,我们需要自己来转换。比如:
[Dynamic, Provider("CIMWin32"), UUID("{8502C4E0-5FBB-11D2-AAC1-006008C78BC7}"), SupportsCreate, CreateBy("Create"), SupportsDelete, DeleteBy("Delete"), AMENDMENT]
class Win32_ScheduledJob : CIM_Job
{
string Caption;
string Description;
datetime InstallDate;
string Name;
string Status;
datetime ElapsedTime;
string Notify;
string Owner;
uint32 Priority;
datetime TimeSubmitted;
datetime UntilTime;
string Command;
uint32 DaysOfMonth;
uint32 DaysOfWeek;
boolean InteractWithDesktop;
uint32 JobId;
string JobStatus;
boolean RunRepeatedly;
datetime StartTime;
};
要转换成MASM32中的定义:
Win32_ScheduledJob STRUCT
Caption db ?
Description db ?
InstallDate datetime ?
Name db ?
Status db ?
ElapsedTime datetime ?
Notify db ?
Owner db ?
Priority DWORD ?
TimeSubmitted datetime ?
UntilTime datetime ?
Command db ?
DaysOfMonth DWORD ?
DaysOfWeek DWORD ?
InteractWithDesktop boolean ?
JobId DWORD ?
JobStatus db ?
RunRepeatedly boolean ?
StartTime datetime ?
Win32_ScheduledJob ENDS
手工转换效率太低,我们可以用HTML+JavaScript来构建一个转换平台。
二、页面设计
首先我们来定义转换平台的页面:
左边的文本框用来粘贴要转换的C++ 类代码,右边的文本框用来显示转换后的 MASM32代码,点击右上角的“转换”按钮进行转换。
相应的代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="Generator" content="EditPlus®">
<meta name="Author" content="PurpleEndurer">
<meta name="Keywords" content="C++,MASM32,Class,Struct">
<meta name="Description" content="C++ Class 2 MASM32 Struct">
<title>C++ Class code 2 MASM32 Struct code</title>
</head>
<body>
<table style="backgound:#ccccff;">
<caption style="background: #ccccff; color:yellow;border-top:1px solid purple;border-left:1px solid purple;">
<P><span style=" font:18pt bold;">C++ Class code 2 MASM32 Struct code</span> <span style=" font:14pt bold;color:purple;">by PurpleEndurer</span> <input type="button" value="转换" onclick="tran()"></P>
</caption>
<tr>
<td style="border:1px solid black;background:#ccffff;">
<P align="center">C++ class code</P>
<textarea id="taCppClass" rows="50" cols="40">
[Dynamic, Provider("CIMWin32"), UUID("{8502C4E0-5FBB-11D2-AAC1-006008C78BC7}"), SupportsCreate, CreateBy("Create"), SupportsDelete, DeleteBy("Delete"), AMENDMENT]
class Win32_ScheduledJob : CIM_Job
{
string Caption;
string Description;
datetime InstallDate;
string Name;
string Status;
datetime ElapsedTime;
string Notify;
string Owner;
uint32 Priority;
datetime TimeSubmitted;
datetime UntilTime;
string Command;
uint32 DaysOfMonth;
uint32 DaysOfWeek;
boolean InteractWithDesktop;
uint32 JobId;
string JobStatus;
boolean RunRepeatedly;
datetime StartTime;
};
</textarea>
</td>
<td style="border:1px solid black;background:#ffffcc;">
<P align="center">MASM32 Struct code</P>
<textarea id="taMASM32" rows="50" cols="90"></textarea>
</td>
</tr>
</table>
</body>
</html>
三、对C++类代码的检测
当我们点击右上角的“转换”按钮进行转换时,我们首先要检测一下左边文本框里内容是否为C++类 代码,检测思路是:
首先用正则表达式的search()方法 检测文本中是否包含关键字class,如果不包含 class,文本就不是C++类 代码;
然后我们分别用字符串的indexOf()和lastIndexOf()方法 来查文本中是否包含'{'和'}'两个字符,如果文本不包含这两个字符,就不是C++类 代码,反之我们可以认为文本是C++类 代码。
代码如下:
//功能:判断是否为c++ class定义代码
//输入:c=code
//输出:true=是,false=否
//记录:20230812创建
function isCppClass(c)
{
//taMASM32.value += 'isCppClass : c.search(/\bclass\b/i =' + c.search(/\bclass\b/i) + '\n';
if (c.search(/\bclass\b/i))
{
if ( -1 != c.indexOf('{') )
{
if ( -1 != c.lastIndexOf('}'))
{
return true;
}//if
}//if
}//if
return false;
}//isCppClass(c)
四、生成MASM32注释
由于类的定义在MASM32中和C++不同,有时我们需要参考类在C++中的原始定义,我们一般会将
类在C++中的原始定义代码以注释的形式放在MASM32中,这里我们用字符串的replace()方法 来实现:
//生成masm32注释
taMASM32.value += ';' + v.replace(/\n/g, '\n;') + '\n';
五、获取类名
接下来我们来获取类名。在C++中,类名一般位于关键字class后面。
思路是首先用正则表达式的search()方法获取关键字class的位置,然后用substring()方法截取它后面的文本c,用indexOf()方法 获取文本c中第一个空格的位置p,再用substring()方法截取文本c从开头到p的文本a,这个文本a就是类名。代码如下:
//功能:获取为c++ class的名称
//输入:c=code
//输出:class的名称(可能为'')
//记录:20230812创建
function getClassName(c)
{
var r = c.substring(c.search(/\bclass\b/i) + 5).ltrim();
return r.substring(0, r.indexOf(' '));
}//getClassName(c)
为了确保获取文本c中第一个空格的位置p位于类名的后面,我们用ltrim()删除文本c开头的空格。
在MASM32中,类的定义是用Struct来实现的。
取得类名后,我们就可以生成MASM32中定义的第一行:
taMASM32.value += '\n' + clsName + ' STRUCT\n';
六、将C++类成员定义转换MASM32格式
C++类成员定义在{}中,顺序是成员类型、成员名称,两者中间用空格或制表符间隔。
MASM32中Struct成员定义顺序是成员名称, 成员类型,值,前两项的顺序与c++相反,两者中间也是用空格或制表符间隔。
我们的思路是:首先获取{}中的文本,用replace(';'.'')把文本中位于行末的所有分号去掉。
然后用split('\n')把文本按行转换为数组逐行处理。
我们用replace()方法,获取C++中的成员类型$1和成员名称$2,并替换成"$2\t$1\t?\n"
//功能:将c++ class中的成员定义转换为MASM32结构体成员定义
//输入:c=code
//输出:MASM32结构体成员定义字符串
//记录:20230812创建
function tranStructMem(c)
{
//获取关键字class后的文本
var r = c.substring(c.search(/\bclass\b/i) + 5);
//获取{}之间的文本
r = r.substring(r.indexOf('{')+1, r.lastIndexOf('}'));
r = r.replace(/;/g,''); //去除所有行末的分号
var a = r.split('\n');//按行转换为数组
r = '';
for (var i = 0; i < a.length; i++)
{
r += a[i].replace( /(\w+)\s+(\w+)/, "$2\t$1\t?\n");
}
//r = r.substring(0, r.length-1);//删除最后一个换行符
return tranCppType2Masm32Type(r);
}//tranStructMem(c)
由于c++中的数据类型与MASM32中的并不完全对应,比如c++中的uint32,在MASM32中没有定义,可以用DWORD来对应,所以我们还增加了一个函数tranCppType2Masm32Type来进行类型转换:
//功能:将c++ class中的数据类型转换为MASM32的数据类型
//输入:v=string
//输出:MASM32的数据类型
//记录:20230812创建
function tranCppType2Masm32Type(v)
{
var aType = [
[/string/gi, "db"],
[/uint32/gi, "DWORD"]
];
var r = v;
for (var i = 0; i < aType.length; i++)
{
r = r.replace(aType[i][0], aType[i][1]);
}
return r;
}//tranCppType2Masm32Type(v)
七、运行效果
八、完整代码
如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="Generator" content="EditPlus®">
<meta name="Author" content="PurpleEndurer">
<meta name="Keywords" content="C++,MASM32,Class,Struct">
<meta name="Description" content="C++ Class 2 MASM32 Struct">
<title>C++ Class code 2 MASM32 Struct code</title>
</head>
<body>
<table style="backgound:#ccccff;">
<caption style="background: #ccccff; color:yellow;border-top:1px solid purple;border-left:1px solid purple;">
<P><span style=" font:18pt bold;">C++ Class code 2 MASM32 Struct code</span> <span style=" font:14pt bold;color:purple;">by PurpleEndurer</span> <input type="button" value="转换" onclick="tran()"></P>
</caption>
<tr>
<td style="border:1px solid black;background:#ccffff;">
<P align="center">C++ class code</P>
<textarea id="taCppClass" rows="50" cols="40">
[Dynamic, Provider("CIMWin32"), UUID("{8502C4E0-5FBB-11D2-AAC1-006008C78BC7}"), SupportsCreate, CreateBy("Create"), SupportsDelete, DeleteBy("Delete"), AMENDMENT]
class Win32_ScheduledJob : CIM_Job
{
string Caption;
string Description;
datetime InstallDate;
string Name;
string Status;
datetime ElapsedTime;
string Notify;
string Owner;
uint32 Priority;
datetime TimeSubmitted;
datetime UntilTime;
string Command;
uint32 DaysOfMonth;
uint32 DaysOfWeek;
boolean InteractWithDesktop;
uint32 JobId;
string JobStatus;
boolean RunRepeatedly;
datetime StartTime;
};
</textarea>
</td>
<td style="border:1px solid black;background:#ffffcc;">
<P align="center">MASM32 Struct code</P>
<textarea id="taMASM32" rows="50" cols="90"></textarea>
</td>
</tr>
</table>
<script>
//功能:删除字符串中的所有空格
//记录:20230726创建
String.prototype.eliminateSpace = function()
{
return this.replace(/\s*/g,"");
}
//去除字符串首部空格
String.prototype.ltrim = function()
{
return this.replace(/(^\s*)/g, "");
}
//去除字符串尾部空格
String.prototype.rtrim = function()
{
return this.replace(/(\s*$)/g, "");
}
//去除字符串首尾空格
String.prototype.trim = function()
{
return this.replace(/(^\s*)|(\s*$)/g, "");
/*var t = this.replace(/(^\s*)|(\s*$)/g, "");
return t =t.replace(/(^ *)|( *$)/g, ""); */
}
//功能:判断是否为c++ class定义代码
//输入:c=code
//输出:true=是,false=否
//记录:20230812创建
function isCppClass(c)
{
//taMASM32.value += 'isCppClass : c.search(/\bclass\b/i =' + c.search(/\bclass\b/i) + '\n';
if (c.search(/\bclass\b/i))
{
if ( -1 != c.indexOf('{') )
{
if ( -1 != c.lastIndexOf('}'))
{
return true;
}//if
}//if
}//if
return false;
}//isCppClass(c)
//功能:获取为c++ class的名称
//输入:c=code
//输出:class的名称(可能为'')
//记录:20230812创建
function getClassName(c)
{
var r = c.substring(c.search(/\bclass\b/i) + 5).ltrim();
return r.substring(0, r.indexOf(' '));
}//getClassName(c)
//功能:将c++ class中的数据类型转换为MASM32的数据类型
//输入:v=string
//输出:MASM32的数据类型
//记录:20230812创建
function tranCppType2Masm32Type(v)
{
var aType = [
[/string/gi, "db"],
[/uint32/gi, "DWORD"]
];
var r = v;
for (var i = 0; i < aType.length; i++)
{
r = r.replace(aType[i][0], aType[i][1]);
}
return r;
}//tranCppType2Masm32Type(v)
//功能:将c++ class中的成员定义转换为MASM32结构体成员定义
//输入:c=code
//输出:MASM32结构体成员定义字符串
//记录:20230812创建
function tranStructMem(c)
{
//获取关键字class后的文本
var r = c.substring(c.search(/\bclass\b/i) + 5);
//获取{}之间的文本
r = r.substring(r.indexOf('{')+1, r.lastIndexOf('}'));
r = r.replace(/;/g,''); //去除所有行末的分号
var a = r.split('\n');//按行转换为数组
r = '';
for (var i = 0; i < a.length; i++)
{
r += a[i].replace( /(\w+)\s+(\w+)/, "$2\t$1\t?\n");
}
//r = r.substring(0, r.length-1);//删除最后一个换行符
return tranCppType2Masm32Type(r);
}//tranStructMem(c)
var taCppClass = document.getElementById('taCppClass');
var taMASM32 = document.getElementById('taMASM32');
function tran()
{
var v = taCppClass.value;
if (""==v.trim())
{
taCppClass.value = "请先将C++代码输入或粘贴到这里";
return;
}
//taMASM32.value = v;
if (!isCppClass(v))
{
taMASM32.value = '不是C++ Class定义';
return;
}
//生成masm32注释
taMASM32.value += ';' + v.replace(/\n/g, '\n;') + '\n';
var clsName = getClassName(v);
if (''==clsName)
{
taMASM32.value += '未能获取类名';
return;
}
taMASM32.value += '\n' + clsName + ' STRUCT\n';
//v = v.replace(/[\t\s]+/g,' ');
//var m = extractMember(v);
taMASM32.value += tranStructMem(v);
}//tran()
</script>
</body>
</html>