TParser

Miscellaneous Forums/Blitz Showcase/TParser

The forum is locked. These are the original blitzbasic.com forums, kept so they can still be read. No new topics, replies or edits can be made here. To join in, head over to the Blitz3D+ forums.

I was playing around over the christmas period with various things and this kind of spawned itself, it's pretty much uncommented, and probably a completely crap way of doing it but what the heck.
Feel free to post changes, suggestions and/or additions to it here.

The code:
Strict

Rem
Author: Kris Kelly
License: Mozilla Public License 1.1
Version: 0.1a
EndRem

Rem
Type TTokenizer
EndRem

Type TTokenizer
'Fields
	Field File : String
	Field FileHandle
	Field Token : String
	Field Position : Long
	Field Whitespace : String
	Field Delimiters : String
	Field Tokens:TList  'stores a list of all tokens minus the whitespace (delimiters are added seperate from the tokens)
	
'Methods
	Method GetNextToken()
		Local tempToken : String
		Local Char : String

		Char = ReadString(FileHandle, 1)
		
		If Delimiters.Find(Char) > -1 Then 
			Token = Char
			Return
		EndIf
		
		While Whitespace.Find(Char) < 0
		
			If Whitespace.Find(Char) < 0 Then 
				If Delimiters.Find(Char) < 0 Then
					tempToken :+ Char
				Else
					Token = tempToken
					SeekStream(FileHandle, StreamPos(FileHandle) -1)
					Return
				EndIf
			EndIf
			
			If KeyDown(KEY_ESCAPE) Then
				Exit
			EndIf
			
			Try
				Char = ReadString(FileHandle, 1)
			Catch err$
				Notify("Error when reading from source file (" + err$ + ")")
			EndTry
	
		Wend
		Token = tempToken
	End Method
	
	
	Method Tokenize()
		While Not Eof(FileHandle)
			GetNextToken()
			If Len(token)>0 Then ListAddLast(Tokens, Token)
		Wend
	End Method
	
	
	Method Init()
		FileHandle = OpenFile(File,1,0) 'read only
	End Method

	
	Method Delete()
		CloseFile(FileHandle)
		Release Tokens
	End Method

'Constructor	
	Function Create:TTokenizer(FileName : String, Delimiters : String = "',:().~q=+-/#$%~^&*!~r", Whitespace : String = " ~t~n~0")
		Local tempTok:TTokenizer = New TTokenizer
			tempTok.File = FileName
			tempTok.Whitespace = Whitespace
			tempTok.Delimiters = Delimiters
			tempTok.Init()
			tempTok.Tokens = CreateList()
		Return tempTok
	End Function
	
End Type


Type TStringVariable
	Field Identifier : String
	Field Value : String
End Type	


Rem
Type TKeyword
EndRem
Type TKeyword
	Field Keyword : String
	Field Action(Sender:TParser, Token:String)
	Field MiscData : Byte Ptr
End Type


Rem
Type TKeywordsList
EndRem
Type TKeywordsList
	Field Keywords:TList
	
	
	Method AddKeyword(Keyword:String, Action(Sender:TParser, Token:String))'MiscData:Byte Ptr)
		Local tempKeyword:TKeyword = New TKeyword
			tempKeyword.Keyword = Keyword
			tempKeyword.Action = Action
			If Not ListContains(Keywords, tempKeyword) Then			
				ListAddLast(Keywords, tempKeyword)
			Else
				Notify("Keyword already in list (" + Keyword + ")")
			EndIf
	End Method
	
	
	Method Save(FileName:String)

	End Method


	Method Load(FileName:String)
		
	End Method
	
'Constructor
	Function Create:TKeywordsList()
		Local tempSI:TKeywordsList= New TKeywordsList
			tempSI.Keywords = CreateList()
		Return tempSI
	End Function
End Type


Rem
Type TParser
EndRem
Type TParser
	Field Tokenizer : TTokenizer
	Field KeywordList : TKeywordsList
	Field UnknownHandler(Sender:TParser, Token:String)
	Field TokenPos : Short


	Method Init(FileName : String, Delimiters : String = "',:().~q=+-/#$%~^&*!~r", Whitespace : String = " ~t~n~0")
		Tokenizer = TTokenizer.Create(FileName, Delimiters, Whitespace)
		Tokenizer.Tokenize()
	End Method


	Method GetNextToken:String()
		Local Result:String
		If TokenPos < CountList(Tokenizer.Tokens)
			Result = String(Tokenizer.Tokens.ValueAtIndex(TokenPos))
			TokenPos :+ 1
		EndIf
		Return Result
	End Method


	Method Parse()
		Local Token : String
		Local kw : TKeyword
		Local kwFound = False
		
		TokenPos = 0
		
		While TokenPos < CountList(Tokenizer.Tokens)
			
			Token = GetNextToken()
					
			If Not CheckKeywords(Token) Then 'keywords take precedence over vars
				If Not CheckVars(Token) Then 'vars take next precedence
					If UnknownHandler <> Null Then UnknownHandler(Self, Token)
				EndIf
			EndIf
			
		Wend
	End Method
	
	
	Method CheckKeywords(Token : String)
		Local kw : TKeyword
		Local kwFound = False
			For kw = EachIn KeywordList.Keywords
				If Lower(kw.Keyword) = Lower(Token) Then
					If kw.Action <> Null Then kw.Action(Self, Token)
					kwFound = True
					Exit'exit since we found the keyword (no point in running through the rest of the keywords)
				EndIf
			Next
		Return kwFound
	End Method
	
	
	Method CheckVars(Token : String)
		Local sv : TStringVariable
		Local VarFound = False
			
			
		Return VarFound
	End Method


'Constructor
	Function Create:TParser()
		Local tempParser : TParser = New TParser
			tempParser.KeywordList = TKeywordsList.Create()
		Return tempParser
	End Function
End Type


'TEST PARSER
'Rem

Type TSimpleBasic
	Field Parser : TParser
	
	Method _Print(Sender:TParser, token:String)
		Local OutString : String
		'For now, just print the next token
		OutString :+ Sender.GetNextToken()
		Print OutString
	End Method


	Method _HandleUnk(Sender:TParser, token:String)
		Print "Unhandled: " + token
	End Method


	Method _MsgBox(Sender:TParser, token:String)
		Notify(Sender.GetNextToken())
	End Method


	Method _SetVar(Sender:TParser, token:String)
		'assume string type for the moment
		Local tempStrVar:TStringVariable= New TStringVariable
			tempStrVar.Identifier = Sender.GetNextToken()
			If Sender.GetNextToken() = "=" Then
				If Sender.GetNextToken() = "~q" Then
					tempStrVar.Value = Sender.GetNextToken()
					If Sender.GetNextToken() <> "~q" Then Notify("expected ending quote")
				Else
					Notify("expected ~q")
				EndIf
			Else
				Notify("expected =")
			EndIf
		ListAddLast(StringVars, tempStrVar)
	End Method


	Method _GetVar:TStringVariable()
	
	End Method


	Function Create:TSimpleBasic(SourceFile : String)
	'	Parser:TParser = TParser.Create()
	'	Parser.Init(SourceFile)
	'	Parser.KeywordList.AddKeyword("print", _Print)
	'	Parser.KeywordList.AddKeyword("msgbox",_MsgBox)
	'	Parser.KeywordList.AddKeyword("var",_SetVar)
	'	Parser.UnknownHandler = _HandleUnk
	'	Parser.Parse()
	
	End Function

End Type


Global StringVars:TList = CreateList()
	
'Rem

Function _Print(Sender:TParser, token:String)
	Local OutString : String
	'For now, just print the next token
	OutString :+ Sender.GetNextToken()
	Print OutString
End Function


Function _HandleUnk(Sender:TParser, token:String)
	Print "Unhandled: " + token
End Function


Function _MsgBox(Sender:TParser, token:String)
	Notify(Sender.GetNextToken())
End Function


Function _SetVar(Sender:TParser, token:String)
	'assume string type for the moment
	Local tempStrVar:TStringVariable= New TStringVariable
		tempStrVar.Identifier = Sender.GetNextToken()
		If Sender.GetNextToken() = "=" Then
			If Sender.GetNextToken() = "~q" Then
				tempStrVar.Value = Sender.GetNextToken()
				If Sender.GetNextToken() <> "~q" Then Notify("expected ending quote")
			Else
				Notify("expected ~q")
			EndIf
		Else
			Notify("expected =")
		EndIf
	ListAddLast(StringVars, tempStrVar)
	'Print "Var added"
	
End Function


Function _GetVar:TStringVariable()
	
End Function


Local myParser:TParser = TParser.Create()
	myParser.Init("test2.txt")
	myParser.KeywordList.AddKeyword("print", _Print)
	myParser.KeywordList.AddKeyword("msgbox",_MsgBox)
	myParser.KeywordList.AddKeyword("var",_SetVar)
	myParser.UnknownHandler = _HandleUnk
	myParser.Parse()

Release myParser
'EndRem
'EndRem

End



The content of test2.txt:
Print test2
var test = "TestVar"
Print test