Page 1 of 1

A Simple Script Interpreter Example of how to write one. Rate Topic: -----

#1 AdamSpeight2008   User is offline

  • MrCupOfT
  • member icon

Reputation: 2298
  • View blog
  • Posts: 9,535
  • Joined: 29-May 08

Posted 08 July 2008 - 10:18 PM

This is my first attempt of writing simple script interpreter.

Part 1: The State & Engine core
Part 2: Command Routines & Forms
' A Generic Scripting engine.
' By AdamSpeight2008
' Inspiration: Logo by Daniel G. Bobrow, Wally Feurzeig and Seymour Papert. 
#Region "THE SCRIPT ENGINE"
Public Class ScriptEngine
	Private Const ScriptName = "PenScript v1.00"
	Private Tokens_Comment() As String = {"'"}
	Private Tokens_Delimiter() As String = {",", " "}
	Protected Friend mState As New ScriptState
#Region "PenScript Commands"
	' PEN UP
	' PEN DOWN
	' PEN COLOR RED
	' PEN COLOR GREEN
	' PEN COLOR BLUE
	' PEN COLOR BLACK
	' PEN COLOR <RED>,<GREEN>,<BLUE>
	' PEN WIDTH NORMAL
	' PEN WIDTH BIG
	' PEN WIDTH THIN
	' PEN WIDTH <WIDTH>
	' MOVE <X>,<Y>
	' FORWARD <DISTANCE>
	' TURN LEFT <DEGREES>
	' TURN RIGHT <DEGREES>
	' ROTATE <DEGREES>
	' MAKESHAPE <SHAPE NAME>
	' ENDSHAPE
	' DRAWSHAPE <SHAPE NAME>
#End Region

#Region "States used by script engine"
	' #### Start of Properties used by the script. ####
	Partial Class ScriptState
		Public myShapes As New List(Of LogoShape)
		Public ShapeStack As New Stack(Of String)
		Private mCurrentInstruction As String
		Private mMakingShape As Boolean
		Private mWidth As Single = 1
		Private mAngle As Double = 180
		Private mPenDown As Boolean
		Private mShapeNumber As Integer
		Private mX As Double = 0
		Private mY As Double = 0
		Private mLineNumber As Integer
		Private mColor As Color = Drawing.Color.Black


		Public Property CurrentInstruction() As String
			Get
				Return mCurrentInstruction
			End Get
			Set(ByVal value As String)
				mCurrentInstruction = value
			End Set
		End Property

		Public Property MakingShape() As Boolean
			Get
				Return mMakingShape
			End Get
			Set(ByVal value As Boolean)
				mMakingShape = value
			End Set
		End Property

		Public Property Width() As Single
			Get
				Return mWidth
			End Get
			Set(ByVal value As Single)
				mWidth = value
			End Set
		End Property

		Public Property Angle() As Double
			Get
				Return mAngle
			End Get
			Set(ByVal value As Double)
				mAngle = value
			End Set
		End Property

		Public Property PenDown() As Boolean
			Get
				Return mPenDown
			End Get
			Set(ByVal value As Boolean)
				mPenDown = value
			End Set
		End Property
		Public Property X() As Double
			Get
				Return mX
			End Get
			Set(ByVal value As Double)
				mX = value
			End Set
		End Property

		Public Property Y() As Double
			Get
				Return mY
			End Get
			Set(ByVal value As Double)
				mY = value
			End Set
		End Property

		Public Property ShapeNumber() As Integer
			Get
				Return mShapeNumber
			End Get
			Set(ByVal value As Integer)
				mShapeNumber = value
			End Set
		End Property

		Public Property LineNumber() As Integer
			Get
				Return mLineNumber
			End Get
			Set(ByVal value As Integer)
				mLineNumber = value
			End Set
		End Property

		Public Property Color() As Color
			Get
				Return mColor
			End Get
			Set(ByVal value As Color)
				mColor = value
			End Set
		End Property
		'### End of properties ###

		'### Start of Functions ###
		Public Function ContainsShapeName(ByRef ThisShapeName As String) As Boolean
			If myShapes.Count = 0 Then Return False
			For i As Integer = 0 To myShapes.Count - 1
				If myShapes(i).ShapeName = ThisShapeName Then Return True
			Next
			Return False
		End Function

		Public Function IndexOfShapeName(ByRef ThisShapeName As String) As Integer
			For i As Integer = 0 To myShapes.Count - 1
				If myShapes(i).ShapeName = ThisShapeName Then Return i
			Next
		End Function
		'### End of functions ###
	End Class
#End Region

#Region "Logo Shape class"
	' The logo shape class
	Public Class LogoShape
		Private mShapeData As New List(Of String)
		Private mShapeName As String
		Public Property ShapeName() As String
			Get
				Return mShapeName
			End Get
			Set(ByVal value As String)
				mShapeName = value
			End Set
		End Property
		Public ReadOnly Property ShapeData() As List(Of String)
			Get
				Return mShapeData
			End Get
		End Property
		Public Sub AddShapeData(ByRef shapeText As String)
			mShapeData.Add(shapeText)
		End Sub
	End Class
#End Region

	Private Function RecombineInstructionFields(ByRef a() As String) As String
		Dim c As String = ""
		For Each p As String In a
			c &= p & " "
		Next
		Return c
	End Function

#Region "Enumerations"
	Public Enum ExitStates As Integer
		OK = True
		HasError = False
	End Enum
#End Region


	Private COutput As Control

#Region "ENGINE CORE"
#Region "CORE: EXECUTING THE SCRIPT"
	Public Function ExcuteScript(ByRef Commands As List(Of String), ByRef g As Graphics, ByRef OutputCtrl As Control, Optional ByRef SelfCalling As Boolean = False)
		' Check that is something to execute.
		If Commands.Count = 0 Then Return False
		'Is the output control a textbox?
		If (TypeOf OutputCtrl Is TextBox) = False Then
			' nope
			Return False
		End If
		' If the ExecuteScript function is not being selfcalled 
		If Not SelfCalling Then
			' Set a local reference to the "console" control
			COutput = OutputCtrl
			' clear the consol
			COutput.Text = ""
			COutput.Text &= ScriptName & vbNewLine
			' also initialise the script states.
			InitialiseScriptEngineStates()
		End If
		Dim CommandStream As New IO.MemoryStream()
		Dim buffer() As Byte
		' Trim Spaces & Remove the end of line character from each command
		For Each ThisString As String In Commands
			buffer = System.Text.Encoding.UTF8.GetBytes(ThisString.Trim(" "))
			CommandStream.Write(buffer, 0, buffer.Length)
			CommandStream.WriteByte(13)
		Next
		' Set the CommandStream position back to the start. 
		CommandStream.Position = 0
		' Create the script parser for the command stream.
		Dim ScriptParser As New Microsoft.VisualBasic.FileIO.TextFieldParser(CommandStream)
		Dim CommandFields() As String = {}
		' Initialise the Execution state to OK
		Dim ExecutionState As ExitStates = ExitStates.OK
		' Tell the Script Parser what are the tokens for comments.
		ScriptParser.CommentTokens = Tokens_Comment
		' Tell the Script Parser what the tokens are for delimiting he command.
		ScriptParser.Delimiters = Tokens_Delimiter
		' Tell the Script Parsers that delimiters in strings are allowed.
		ScriptParser.HasFieldsEnclosedInQuotes = True
		' While the script parser has something to parse.
		While Not ScriptParser.EndOfData
			' Set the State(LineNumber) to the current line Number of the parser commands.
			mState.LineNumber = ScriptParser.LineNumber
			' TRY & Read the next command, parse it into fields.
			Try
				CommandFields = ScriptParser.ReadFields
			Catch ex As Exception
				ErrorMessage("Error Message: " & ex.Message & vbNewLine)
				' Execution Failed, so indicate error
				ExecutionState = ExitStates.HasError
				' Close the Command Stream
				CommandStream.Close()
				CommandStream = Nothing
				' Exit execution
				Exit While
			End Try
			' Record the Current Instruction in the State(CurrentInstruction)
			mState.CurrentInstruction = RecombineInstructionFields(CommandFields)
			' Try and execute the CommandFields
			' The processing and execution is passed to ExecuteCommand() function
			' - This is to keep the code simple
			' - Makes implementing new easier.
			If ExcuteCommand(CommandFields, g, COutput) = False Then
				' Execution Failed, so indicate error
				ExecutionState = ExitStates.HasError
				' Exit execution
				Exit While
			End If
		End While
		' Close the Command Stream
		CommandStream.Close()
		CommandStream = Nothing
		' Check the state of execution
		Select Case True
			Case mState.MakingShape = False And ExecutionState = ExitStates.OK
				If Not SelfCalling Then ErrorMessage("Executed Successfully.")
				Return True
			Case mState.MakingShape = False And ExecutionState = ExitStates.HasError
				If Not SelfCalling Then ErrorMessage("Unsuccessful Execution")
				Return True
			Case mState.MakingShape = True And ExecutionState = ExitStates.OK
				If Not SelfCalling Then ErrorMessage("Missing ENDSHAPE")
				Return False
			Case mState.MakingShape = True And ExecutionState = ExitStates.HasError
				If Not SelfCalling Then ErrorMessage("Error in Execution (whilst Making Shape)")
				Return True
			Case Else
				Return False
		End Select
	End Function
#End Region

#Region "CORE: EXECUTING THE COMMAND"
	Private Function ExcuteCommand(ByRef command() As String, ByRef g As Graphics, ByRef OutputC As Control) As Boolean
		' Define the exitState to be true (Assumes the command will execute successfully, until an error occurs.)
		Dim ExitState As Boolean = True
		' Shall I record this instruction. (Used for stord procedures)
		Dim RecordInstruction As Boolean = True
		' Which command is it?
		Select Case command(0)
			' -- Start of Known Instructions --
			Case "PRINT" : ExitState = Command_Print(mState, command)
			Case "PEN" : ExitState = Command_Pen(mState, command)
			Case "MOVE" : ExitState = Command_Move(mState, command, g)
			Case "ROTATE" : ExitState = Command_Rotate(mState, command)
			Case "TURN" : ExitState = Command_Turn(mState, command)
			Case "FORWARD" : ExitState = Command_Forward(mState, command, g)
			Case "MAKESHAPE" : RecordInstruction = False : ExitState = Command_MakeShape(mState, command)
			Case "ENDSHAPE" : RecordInstruction = False : ExitState = Command_EndShape(mState, command)
			Case "DRAWSHAPE" : ExitState = Command_DrawShape(mState, command, g)
				' -- End of known instructions --
			Case Else
				' Unknown instruction
				ErrorMessage("Line: " & mState.LineNumber.ToString & vbCrLf & "Unknown Command." & vbCrLf & command(0))
				ExitState = False
		End Select
		' Should I record this instruction
		If mState.MakingShape And RecordInstruction Then mState.myShapes(mState.ShapeNumber).AddShapeData(mState.CurrentInstruction)
		Return ExitState
	End Function
#End Region

#End Region


	Private Sub ErrorMessage(ByRef Message As String)
		' Append the error message onto end of text.
		COutput.Text &= Message & vbNewLine
	End Sub

	Private Sub InitialiseScriptEngineStates()
		' Initialise the states with there default values
		With mState
			.Angle = 0
			.X = 0
			.Y = 0
			.PenDown = False
			.MakingShape = False
			.LineNumber = 0
			.ShapeNumber = -1
			.ShapeStack.Clear()
			.myShapes.Clear()
			.Color = Color.Black
		End With
	End Sub


Continue in part2

Attached File(s)


This post has been edited by AdamSpeight2008: 11 July 2008 - 06:38 AM


Is This A Good Question/Topic? 0
  • +

Replies To: A Simple Script Interpreter

#2 jagatworld   User is offline

  • New D.I.C Head
  • member icon

Reputation: 0
  • View blog
  • Posts: 31
  • Joined: 11-May 08

Posted 11 July 2008 - 12:56 AM

Hello AdamSpeight2008,

Upto some extent, it is ok, but at the last moment, i got a problem.


MyScriptEngine.ExcuteScript(RTB_Script.Lines.ToList, pg, Me.Txt_Output)  

error in :  RTB_Script.Lines.ToList




is giving error.

Please let me know what is the problem........ the error is

Quote

Error 1 Value of type 'String' cannot be converted to 'System.Collections.Generic.List(Of String)'. E:\Srikanth\SampleApps\ScriptInterpreter\ScriptInterpreter\Form1.vb 12 41 ScriptInterpreter


Thanks.
Was This Post Helpful? 0
  • +
  • -

#3 AdamSpeight2008   User is offline

  • MrCupOfT
  • member icon

Reputation: 2298
  • View blog
  • Posts: 9,535
  • Joined: 29-May 08

Posted 11 July 2008 - 02:28 AM

Original was written in Visual Basic 2008, and if run on a lower version would through this error. :stupid:
Modified to compatible in most version of vb.net.
Was This Post Helpful? 0
  • +
  • -

#4 AdamSpeight2008   User is offline

  • MrCupOfT
  • member icon

Reputation: 2298
  • View blog
  • Posts: 9,535
  • Joined: 29-May 08

Posted 13 July 2008 - 08:18 AM

Now split across two tutorials
Part 1: States & Core
Part 2: Commands & Form
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1