一个简明的编译器
多次看到有人提起文本表达式的计算问题,就动手整理以前的代码并加上注释。
写一个简单的编译器并不是很复杂的,当中要用到些反射的知识。自已觉得,反射的使用在 NET 中真是无处不在,使用反射没什么效率不效率的问题,毕竟现在的电脑配置并不是很低。适当使用反射,或者通过使用反射本身,会使自己加深对 NET 的理解。以后会写些运用反射增加代码灵活性的小 ” 文章 ” 供初学者参考。
如果只是计算表达式的值的,当然用不了那么多的代码.这样写法,只是使它通用性强些.
以下的我直接贴代码了,不再说些什么(可以说如何如何臭,只是不许骂人)。
Imports System.Reflection
Imports System.CodeDom
Imports System.CodeDom.Compiler
Public Class SourceComp
'// 编译器接口
Private m_Compiler As ICodeCompiler
'// 编译器参数
Private m_CompilerParameters As CompilerParameters
'// 引用的程序集
Private m_RefAssemblies As String () = {"System.dll", "System.Data.dll"}
'// 源代码
Private m_Source As String = ""
'// 记录是否是默认的源代码
Private m_Is_Default As Boolean = True
'// 记录编译状态
Private m_Compiled As Boolean = False
'// 编译生成的程序集
Private m_Assembly As System.Reflection.Assembly
'// 默认源代码生成的实例
Private m_tmpClass As Object
'// 默认源代码生成的实例函数
Private m_MethodInfo As System.Reflection.MethodInfo
'// 默认源代码函数的表达式参数
Private m_Expression As String
'// 返回程序集
Public ReadOnly Property cpAssembly() As System.Reflection.Assembly
Get
Return Me .m_Assembly
End Get
End Property
Sub New ()
'// 获取 VB 编译器实例
Me .m_Compiler = New VBCodeProvider().CreateCompiler
'// 初始编译器参数
Me .m_CompilerParameters = New CompilerParameters
With Me .m_CompilerParameters
.GenerateExecutable = False '//False 值指定编译为类集 ,True 编译为可执行程序
.GenerateInMemory = False '// 只在内存中生成程序集,不输出到磁盘
'// 添加默认的程序集
Me .Add_CompilerParameters()
End With
End Sub
'// 添加要引用的程序集
Private Sub Add_CompilerParameters()
Me .m_CompilerParameters.ReferencedAssemblies.AddRange( Me .m_RefAssemblies)
End Sub
'// 添加指定的引用程序集
Public Sub Add_CompilerParameters( ByVal RefAssemblies As String ())
Me .m_RefAssemblies = RefAssemblies
Me .m_CompilerParameters.ReferencedAssemblies.Clear() '// 清除原有的程序集,重复引用编译会产生异常
Me .Add_CompilerParameters()
End Sub
'// 生成默认的源代码
'// 类名: tmpClass
'// 函数名: GetExpressionValue , 参数 :Expression , 参数类型 : 字符串
'// 主要功能:返回表达式 Expression 的值 , 返回值类型 :Object
Private Sub BuildDefaultSource()
Dim mCodeBuilder As CodeBuilder = New CodeBuilder
With mCodeBuilder
.AppendCode("Imports System")
.AppendCode("Imports System.Data")
.AppendCode("Imports System.Math")
.AppendCode("Imports Microsoft.VisualBasic")
.AppendCode()
.AppendCode("Public Class tmpClass")
.AppendCode(" Public Function GetExpressionValue() As Object")
.AppendCode(" Dim Result As Object")
.AppendCode(" Result={0}") ' 这里传入表达式
.AppendCode(" Return Result")
.AppendCode(" End Function")
.AppendCode("End Class")
End With
Me .m_Source = mCodeBuilder.ToString
End Sub
'// 指定源代码
Public Sub SetSource( ByVal Source As String )
Me .m_Source = Source
Me .m_Compiled = False
Me .m_Is_Default = False
End Sub
'// 从指定文件中读取源代码
Public Sub GetSourceFormFile( ByVal SourceFileName As String )
Dim mCodeBuilder As CodeBuilder = New CodeBuilder
mCodeBuilder.AppendFromFile(SourceFileName)
Me .m_Source = mCodeBuilder.ToString
Me .m_Compiled = False
Me .m_Is_Default = False
End Sub
'// 编译
Public Sub Complile()
If Me .m_Source = "" Then
Me .BuildDefaultSource()
End If
If Me .m_Is_Default Then
' 传入参数
Me .m_Source = String .Format( Me .m_Source, Me .m_Expression)
End If
Dim mCompResult As CompilerResults = Me .m_Compiler.CompileAssemblyFromSource( Me .m_CompilerParameters, Me .m_Source)
'// 错误提示
If (mCompResult.Errors.HasErrors) Then
Dim ErrorMessage As String
ErrorMessage = " 编译错误 :" & vbCrLf
Dim Err As CompilerError
For Each Err In mCompResult.Errors
ErrorMessage = ErrorMessage & Err.ErrorText & vbCrLf
Next
Throw New Exception(" 编译错误 : " + ErrorMessage)
End If
Me .m_Assembly = mCompResult.CompiledAssembly
Me .m_Compiled = True
End Sub
'// 如果是默认源代码,此函数取表达式的值;
'// 如果自定义源代码,请参考本函数视实际自己写
Public Function GetExpressionValue( ByVal Expression As String ) As Object
If Not Me .m_Is_Default Then
MsgBox(" 所用的代码不是默认代码,此函数无效 ")
Return Nothing
End If
' 如