闂傚倷娴囬妴鈧柛瀣崌閺岀喖顢涘⿰鍐炬毉濡炪們鍎婚幏锟� (0) +1 闂備浇宕垫慨宥咁吋閸℃浼� (0) +1 闂傚倸鍊搁オ瀛樼閻戣棄绠柨鐕傛嫹 (0) +1
闂傚倷娴囬妴鈧柛瀣崌閺岀喖顢涘⿰鍐炬毉濡炪們鍎查崹鍧楀蓟閻旇 鍋撳☉娅亝鎱ㄩ崶褉鏀芥い鏇炴鐎氾拷闂傚倷绀侀幖顐ゆ偖椤愶箑纾块柛鎰嚋閼板潡鏌涘☉娆愮稇缂備讲鏅犻弻鐔碱敍濠婂喚鏆銈冨劵閹凤拷>>

正在阅读:详解如何编写一个简明编译器详解如何编写一个简明编译器

2004-11-04 11:51 出处:CSDN 作者:lzmtw 责任编辑:linjixiong

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

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


  


察看评论详细内容 我要发表评论
作者笔名 简短内容 发表时间
:

关注我们

最新资讯离线随时看 聊天吐槽赢奖品
闂傚倷绀佺紞濠傖缚瑜旈、鏍幢濡炵粯鏁犻梺閫炲苯澧撮柟顔款潐閹峰懘宕ㄦ繝鍌欐樊婵犵妲呴崑鎾诲箯閿燂拷闂傚倷鐒﹂幃鍫曞磿閹惰棄纾绘繛鎴欏灩閺勩儵鎮橀悙鏉垮珟濞存粍绮撻弻娑㈩敃閿濆棛顦ラ梺鍛婃閹凤拷