分享
 
 
 

详解如何编写一个简明编译器

王朝other·作者佚名  2006-11-24
窄屏简体版  字體: |||超大  

多次看到有人提起文本表达式的计算问题,就动手整理以前的代码并加上注释。

写一个简单的编译器并不是很复杂的,当中要用到些反射的知识。自已觉得,反射的使用在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

'如果还没有编译则编译

If Not Me.m_Compiled Then

'//传入参数表达式作为代码

Me.m_Expression = Expression

Complile()

'//生成实例,注意类名区分大小写

Me.m_tmpClass = Me.m_Assembly.CreateInstance("tmpClass")

'//取函数,注意大小写

m_MethodInfo = Me.m_tmpClass.GetType().GetMethod("GetExpressionValue")

End If

'//计算结果

Dim Result As Object = m_MethodInfo.Invoke(m_tmpClass, Nothing)

'表达式不同时要重新编译

Me.m_Compiled = False

Return Result

End Function

End Class

'//格式生成或读取代码的类

Public Class CodeBuilder

Private _StringBuilder As System.Text.StringBuilder

'//格式,{0}为空格数,{1}代码字串,最后加回车换行

Private Const CodeFormat As String = "{0}{1}" & ControlChars.CrLf

Sub New()

_StringBuilder = New System.Text.StringBuilder

End Sub

Public Overloads Sub AppendCode()

_StringBuilder.AppendFormat(CodeFormat, Space(0), Space(0))

End Sub

Public Overloads Sub AppendCode(ByVal CodeString As String)

_StringBuilder.AppendFormat(CodeFormat, Space(0), CodeString)

End Sub

Public Overloads Sub AppendCode(ByVal CodeFloor As Integer, ByVal CodeString As String)

_StringBuilder.AppendFormat(CodeFormat, Space(CodeFloor * 4), CodeString)

End Sub

'//直接从已有vb文件中读取代码

Public Sub AppendFromFile(ByVal FileName As String)

If Not System.IO.File.Exists(FileName) Then

MsgBox(FileName & "不存在.")

Exit Sub

End If

Dim tmpStr As String

Dim fs As System.IO.FileStream

fs = New System.IO.FileStream(FileName, IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read)

Dim Reader As New System.IO.StreamReader(fs, System.Text.Encoding.Default)

tmpStr = Reader.ReadToEnd

Reader.Close()

fs.Close()

_StringBuilder.Append(tmpStr)

End Sub

'//返回代码串

Public Overrides Function ToString() As String

Return _StringBuilder.ToString

End Function

'//清除原有代码

Public Sub Clear()

If _StringBuilder.Length > 0 Then _StringBuilder.Remove(0, _StringBuilder.Length - 1)

End Sub

End Class 'CodeBuilder

'测试

Dim MyComp As SourceComp

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

'如果不重新生成实例,则因重新编译时输出同名的临时程序集,会出错

MyComp = New SourceComp

Console.WriteLine(MyComp.GetExpressionValue("Math.Round(Math.SQRT(123 * 456), 2) ").ToString)

'结果236.83

MyComp = New SourceComp

Console.WriteLine(MyComp.GetExpressionValue("123 * 456 > 12 * 6987").ToString)

'结果False

End Sub

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有