一、需求分析
在使用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 STRUCTCaption 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}//ifreturn 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}//ifreturn 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>