Just realized its not exception handling but it wouldnt be too hard to change to (just throw the object). Its been awhile since I have looked at this code so sorry for the misinformation.
Add a parameter to the ParseLALR routine which is a boolean I called allowErrors (pretty self explanatory).
Public Class ParserError
Public Token As Token
Public Position As Position
End Class
Of course, initialize the class somewhere in the code.
'===== The Parser Error information.
Private m_ParserError As New ParserError 'Holds the Parser Error information
I wanted to keep the same accessibility to what you (Devin) used. So somewhere in the code, make the object accessible:
<Description("Get the Parse Error Information")> _
Public Function ParserError() As ParserError
Return m_ParserError
End Function
Now the next part can most-likely be modified to be more efficient. This approach seems to work well for me but I have no problems if you all want to modify it.
In the ParseLALR routine, you did setup the syntax error portion, what I did was add a while loop to basically skip tokens till it started a new line in which it SHOULD (depending on the grammar that is) be a new rule. The good thing is even if that is not the case, it will fail out again and repeat until it can successfully find a good starting point.
Remember I wanted to populate the object with useful information which allowed my application to seek to the source code given the location. So you will see all this in the code:
Result = ParseResult.SyntaxError
If AllowErrors Then
Dim NextLine As Boolean
NextLine = False
While Not NextLine
Try
If TypeOf m_Stack.Top().Data Is GOLD.Reduction AndAlso m_CurrentPosition.Line = CType(m_Stack.Top().Data, GOLD.Reduction).Item(0).Position().Line Then
m_Stack.Pop()
m_CurrentLALR = m_Stack.Top().State
ElseIf m_CurrentPosition.Line = m_Stack.Top().Position().Line Then
m_Stack.Pop()
m_CurrentLALR = m_Stack.Top().State
Else
NextLine = True
m_ParserError.Position = New Position
m_ParserError.Position.CharPos = m_CurrentPosition.CharPos
m_ParserError.Position.Line = m_CurrentPosition.Line
m_ParserError.Position.Column = m_CurrentPosition.Column
m_ParserError.Token = m_InputTokens.Pop()
m_CurrentPosition.Line = m_CurrentPosition.Line + 1
m_CurrentPosition.Column = 0
m_CurrentPosition.CharPos = 0
m_SysPosition.Column = 0
m_SysPosition.CharPos = 0
m_SysPosition.Line = m_SysPosition.Line + 1
End If
Catch ex As Exception
NextLine = True
m_ParserError.Position = New Position
m_ParserError.Position.CharPos = m_CurrentPosition.CharPos
m_ParserError.Position.Line = m_CurrentPosition.Line
m_ParserError.Position.Column = m_CurrentPosition.Column
m_ParserError.Token = m_Stack.Pop()
m_CurrentPosition.Line = m_CurrentPosition.Line + 1
m_CurrentPosition.Column = 0
m_CurrentPosition.CharPos = 0
m_SysPosition.Column = 0
m_SysPosition.CharPos = 0
m_SysPosition.Line = m_SysPosition.Line + 1
End Try
End While
End If
I will attach the Parser.vb file. Again, this was my attempt to understand what the Engine was actually doing. There is most-likely a better way to check the location then looking at the first item of the stack (which is why there is a try-catch surrounding the majority of the loop).
In my own code which used Gold Parser, I created a class which holds parsing info. This is bound to a UI object so the user can view the error on the source itself:
output.Message = "Unexpected Token: '" + args.UnexpectedToken.Text + "'";