Parser example afx cWindow

Started by Frank Brübach, January 27, 2025, 03:32:40 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Frank Brübach

hello.. I have made last days a simple parser example with freebasic and Winfbe Editor.
all work are in progress.

now I have used afx cWindow class for my parser example too with an inputbox.

' freebasic parser example by lionheart first edition 25-06-2024
' Parser example freebasic, 24+25-01-2025, by lionheart
' part four, running now all fine, many thanks to fxm for help
' complete code example with Input, 27-01-2025
' for example you are using for Input:
'
' a = 2 + 3 * 10 print a ' result 50
' b = 4 + 9 * 20 print b ' result: 260
' c = 6 + 5 * 6 / 4 print c ' 16.5
'
' afx style cWindow, 27-01-2025 with inputbox
'
#define UNICODE
#INCLUDE ONCE "Afx/CWindow.inc"
USING Afx

' Define the Enum and Type
Enum TokenType
    TK_INTEGER
    TK_PLUS
    TK_MINUS
    TK_MULTIPLY
    TK_DIVIDE
    TK_LPAREN
    TK_RPAREN
    TK_ASSIGN
    TK_IDENTIFIER
    TK_PRINT
    TK_EOF
    TK_UNKNOWN
End Enum

Type Token
    Type1 As TokenType
    Value As String
End Type

' IsNumeric() function
Function IsNumeric(ByVal value As String) As Integer
    Static numericChars As cwstr
    numericChars = "0123456789.-"
    If Len(value) = 0 Then Return False

    Dim dotCount As Integer = 0
    For i As Integer = 1 To Len(value)
        Dim c As cwstr = Mid(value, i, 1)
        If InStr(numericChars, c) = 0 Then
            Return False
        ElseIf c = "." Then
            dotCount += 1
            If dotCount > 1 Then
                Return False
            End If
        End If
    Next

    Return True
End Function

' GetTokenType() function
Function GetTokenType(ByVal value As String) As TokenType
    If IsNumeric(value) Then
        Return TK_INTEGER
    ElseIf value = "+" Then
        Return TK_PLUS
    ElseIf value = "-" Then
        Return TK_MINUS
    ElseIf value = "*" Then
        Return TK_MULTIPLY
    ElseIf value = "/" Then
        Return TK_DIVIDE
    ElseIf value = "(" Then
        Return TK_LPAREN
    ElseIf value = ")" Then
        Return TK_RPAREN
    ElseIf value = "=" Then
        Return TK_ASSIGN
    ElseIf value = "print" Then
        Return TK_PRINT
    ElseIf value = "" Then
        Return TK_EOF
    Else
        Return TK_IDENTIFIER
    End If
End Function

' Split() function
Function Split(ByVal inputs As cwstr, tokens2() As Token) As Integer
    Dim token1 As String = ""
    Dim tokenCount As Integer = 0
    Dim i As Integer

    For i = 1 To Len(inputs)
        Dim c As String = Mid(inputs, i, 1)
        If c = " " Then
            If token1 <> "" Then
                ReDim Preserve tokens2(0 To tokenCount)
                tokens2(tokenCount).Value = token1
                tokens2(tokenCount).Type1 = GetTokenType(token1)
                tokenCount += 1
                token1 = ""
            End If
        Else
            token1 += c
        End If
    Next
    If token1 <> "" Then
        ReDim Preserve tokens2(0 To tokenCount)
        tokens2(tokenCount).Value = token1
        tokens2(tokenCount).Type1 = GetTokenType(token1)
    End If

    Return tokenCount
End Function

' EvaluateExpression function
Function EvaluateExpression(ByVal inputs As String) As Double
    Dim tokens() As Token
    Dim tokenCount As Integer = Split(inputs, tokens())

    Dim total As Double = 0
    Dim currentNumber As Double = 0
    Dim operators As cwstr = "+"

    For i As Integer = 0 To UBound(tokens)
        Dim token As Token = tokens(i)

        If token.Type1 = TK_INTEGER Then
            currentNumber = Val(token.Value)
            If operators = "+" Then
                total += currentNumber
            ElseIf operators = "-" Then
                total -= currentNumber
            ElseIf operators = "*" Then
                total *= currentNumber
            ElseIf operators = "/" Then
                If currentNumber <> 0 Then
                    total /= currentNumber
                Else
                    Print "Error: Division by zero"
                    Exit For
                End If
            End If

            operators = "+"
        ElseIf token.Type1 = TK_PLUS Then
            operators = "+"
        ElseIf token.Type1 = TK_MINUS Then
            operators = "-"
        ElseIf token.Type1 = TK_MULTIPLY Then
            operators = "*"
        ElseIf token.Type1 = TK_DIVIDE Then
            operators = "/"
        End If
    Next

    Return total
End Function

' findExpressionEnd()
Function FindExpressionEnd(tokens() As Token, start As Integer) As Integer
    Dim i As Integer
    For i = start To UBound(tokens)
        If tokens(i).Type1 = TK_EOF Or tokens(i).Type1 = TK_PRINT Then
            Return i - 1
        End If
    Next
    Return UBound(tokens)
End Function

Function JoinTokens(tokens() As Token, start As Integer, ends As Integer) As cwstr
    Dim expr As cwstr = ""
    Dim i As Integer
    For i = start To ends
        expr += tokens(i).Value + " "
    Next
    Return Trim(expr)
End Function

' mapTable
Type Map
    keys(any) As cwstr 
    values(Any) As cwstr 
    count As Integer
End Type

' Initialize the map
Function MapInit(ByRef maps As Map) As integer
    maps.count = 0
    ReDim maps.keys(100)
    Redim maps.values(100) 
    Function=1
End Function

' Add a key-value pair to the map
Function MapPut(ByRef maps As Map, key As cwstr, value As cwstr) As Integer
    maps.keys(maps.count) = key
    maps.values(maps.count) = value
    maps.count = maps.count + 1
    Return 0 ' Indicate success
End Function

' Retrieve a value from the map based on a key
Function MapGet(maps As Map, key As cwstr) As cwstr Ptr ' string ptr
    Dim i As Integer
    For i = 0 To maps.count - 1
        If maps.keys(i) = key Then
            Return StrPtr(maps.values(i))
        End If
    Next
    Return 0 ' Indicate failure
End Function

Function CreateMap() As Map
    Dim map As Map
    MapInit map
    Return map
End Function

Function StoreValue(map As Map, key As cwstr, value As Double) As Integer
    Dim result As Integer = MapPut(map, key, Str(value))
    Return result
End Function

' parse function
Function Parse(tokens() As Token) As Integer
    Dim i As Integer
    Dim SymbolTable As Map
    MapInit SymbolTable
    For i = 0 To UBound(tokens)
        Dim token As Token = tokens(i)
        If token.Type1 = TK_IDENTIFIER Then
            If tokens(i + 1).Type1 = TK_ASSIGN Then
                ' Handle variable assignment
                Dim varName As cwstr = token.Value
                Dim exprStart As Integer = i + 2
                Dim exprEnd As Integer = FindExpressionEnd(tokens(), exprStart)
                Dim expr As cwstr = JoinTokens(tokens(), exprStart, exprEnd)
                Dim result As Double = EvaluateExpression(expr)
                ' Store the result in a symbol table
                StoreValue(SymbolTable, varName, result)
                i = exprEnd
            Else
                Print "Error: Expected assignment operator"
                Return -1
            End If
        ElseIf token.Type1 = TK_PRINT Then
            ' Handle print statement Line 239:
            Dim exprStart As Integer
            Dim exprEnd As Integer = FindExpressionEnd(tokens(), exprStart)
            Dim expr As cwstr = JoinTokens(tokens(), exprStart, exprEnd)
            Dim result As Double = EvaluateExpression(expr)
            Print "result "; result
            i = exprEnd + 2
        End If
    Next
    Return 0
End Function

Function GetValue(map As Map, key As cwstr) As Double
    Dim value As cwstr Ptr = MapGet(map, key)
    If value = 0 Then
        Return 0
    Else
        Return Val(*value)
    End If
End Function

' -------------------------- // correct result 50 :-) -------- //
' afxInputBox
'
Dim inputs As cwstr '= "a = 2 + 3 * 10 print a" ' result 50 ok
'Input "make inputs and return: "; inputs
inputs=afxInputbox(0,0,0,"make inputs And Return: ",inputs,"") ';inputs
' b = 4 + 9 * 20 print b ' result: 260 ok
' c = 6 + 5 * 6 / 4 print c ' result ok 16.5
messagebox(NULL,inputs,"result on console output",mb_ok)

' -------------------------- // correct result 50 :-) -------- //

Dim tokens() As Token
Dim tokenCount As Integer = Split(inputs, tokens())

Dim result As Integer = Parse(tokens())

If result = 0 Then
    Print "Execution completed successfully"
Else
    Print "Error: Execution failed"
End If

' Wait for a key press before closing the console
Print "Press any key to continue..."
Sleep
While Inkey <> "" : Wend
' ends
'
'Dim st As cwstr
'st = afxInputBox(0,0,0,"type in","prog inputbox","")
'messagebox(NULL,st,"prog",mb_ok)

Frank Brübach


Made a little Update because I fixed a little substraction minus calculation. Add an Error Message too and a little more

' freebasic parser example by lionheart first edition 25-06-2024
' Parser example freebasic, 24+25-01-2025, by lionheart
' part five, running now all fine, many thanks to fxm for help
' complete code example with Input, 27-01-2025, 28-01-2025
' for example you are using for Input:
'
' b = 4 + 9 * 20 - 10 print b ' result: 250
' c = 6 + 5 * 6 / 4 print c ' 16.5
'
' afx style cWindow, 27-01-2025 with inputbox
' fixed a minus calculation

#define UNICODE
#INCLUDE ONCE "Afx/CWindow.inc"
USING Afx

' Define the Enum and Type
Enum TokenType
    TK_INTEGER
    TK_PLUS
    TK_MINUS
    TK_MULTIPLY
    TK_DIVIDE
    TK_LPAREN
    TK_RPAREN
    TK_ASSIGN
    TK_IDENTIFIER
    TK_PRINT
    TK_EOF
    TK_UNKNOWN
End Enum

Type Token
    Type1 As TokenType
    Value As String
End Type

' IsNumeric() function
Function IsNumeric(ByVal value As String) As Integer
    Static numericChars As cwstr
    numericChars = "0123456789.-"
    If Len(value) = 0 Then Return False

    Dim dotCount As Integer = 0
    For i As Integer = 1 To Len(value)
        Dim c As cwstr = Mid(value, i, 1)
        If InStr(numericChars, c) = 0 Then
            Return False
        ElseIf c = "." Then
            dotCount += 1
            If dotCount > 1 Then
                Return False
            End If
        End If
    Next

    Return True
End Function

' GetTokenType() function
Function GetTokenType(ByVal value As String) As TokenType
    If IsNumeric(value) Then
        Return TK_INTEGER
    ElseIf value = "+" Then
        Return TK_PLUS
    ElseIf value = "-" Then
        Return TK_MINUS
    ElseIf value = "*" Then
        Return TK_MULTIPLY
    ElseIf value = "/" Then
        Return TK_DIVIDE
    ElseIf value = "(" Then
        Return TK_LPAREN
    ElseIf value = ")" Then
        Return TK_RPAREN
    ElseIf value = "=" Then
        Return TK_ASSIGN
    ElseIf value = "print" Then
        Return TK_PRINT
    ElseIf value = "" Then
        Return TK_EOF
    Else
        Return TK_IDENTIFIER
    End If
End Function

' Split() function
Function Split(ByVal inputs As cwstr, tokens2() As Token) As Integer
    Dim token1 As String = ""
    Dim tokenCount As Integer = 0
    Dim i As Integer

    For i = 1 To Len(inputs)
        Dim c As String = Mid(inputs, i, 1)
        If c = " " Then
            If token1 <> "" Then
                ReDim Preserve tokens2(0 To tokenCount)
                tokens2(tokenCount).Value = token1
                tokens2(tokenCount).Type1 = GetTokenType(token1)
                tokenCount += 1
                token1 = ""
            End If
        Else
            token1 += c
        End If
    Next
    If token1 <> "" Then
        ReDim Preserve tokens2(0 To tokenCount)
        tokens2(tokenCount).Value = token1
        tokens2(tokenCount).Type1 = GetTokenType(token1)
    End If

    Return tokenCount
End Function

' EvaluateExpression function
Function EvaluateExpression(ByVal inputs As String) As Double
    Dim tokens() As Token
    Dim tokenCount As Integer = Split(inputs, tokens())

    Dim total As Double = 0
    Dim currentNumber As Double = 0
    Dim operators As cwstr = "+"

    For i As Integer = 0 To UBound(tokens)
        Dim token As Token = tokens(i)

        If token.Type1 = TK_INTEGER Then
            currentNumber = Val(token.Value)
            If operators = "+" Then
                total += currentNumber
            ElseIf operators = "-" Then
                total -= currentNumber
            ElseIf operators = "*" Then
                total *= currentNumber
            ElseIf operators = "/" Then
                If currentNumber <> 0 Then
                    total /= currentNumber
                Else
                    Print "Error: Division by zero"
                    Exit For
                End If
            End If

            operators = "-"
        ElseIf token.Type1 = TK_PLUS Then
            operators = "+"
        ElseIf token.Type1 = TK_MINUS Then
            operators = "-"
        ElseIf token.Type1 = TK_MULTIPLY Then
            operators = "*"
        ElseIf token.Type1 = TK_DIVIDE Then
            operators = "/"
        End If
    Next

    Return total
End Function

' findExpressionEnd()
Function FindExpressionEnd(tokens() As Token, start As Integer) As Integer
    Dim i As Integer
    For i = start To UBound(tokens)
        If tokens(i).Type1 = TK_EOF Or tokens(i).Type1 = TK_PRINT Then
            Return i - 1
        End If
    Next
    Return UBound(tokens)
End Function

Function JoinTokens(tokens() As Token, start As Integer, ends As Integer) As cwstr
    Dim expr As cwstr = ""
    Dim i As Integer
    For i = start To ends
        expr += tokens(i).Value + " "
    Next
    Return Trim(expr)
End Function

' mapTable
Type Map
    keys(any) As cwstr 
    values(Any) As cwstr 
    count As Integer
End Type

' Initialize the map
Function MapInit(ByRef maps As Map) As integer
    maps.count = 0
    ReDim maps.keys(100)
    Redim maps.values(100) 
    Function=1
End Function

' Add a key-value pair to the map
Function MapPut(ByRef maps As Map, key As cwstr, value As cwstr) As Integer
    maps.keys(maps.count) = key
    maps.values(maps.count) = value
    maps.count = maps.count + 1
    Return 0 ' Indicate success
End Function

' Retrieve a value from the map based on a key
Function MapGet(maps As Map, key As cwstr) As cwstr Ptr ' string ptr
    Dim i As Integer
    For i = 0 To maps.count - 1
        If maps.keys(i) = key Then
            Return StrPtr(maps.values(i))
        End If
    Next
    Return 0 ' Indicate failure
End Function

Function CreateMap() As Map
    Dim map As Map
    MapInit map
    Return map
End Function

Function StoreValue(map As Map, key As cwstr, value As Double) As Integer
    Dim result As Integer = MapPut(map, key, Str(value))
    Return result
End Function

' parse function
Function Parse(tokens() As Token) As Integer
    Dim i As Integer
    Dim SymbolTable As Map
    MapInit SymbolTable
    For i = 0 To UBound(tokens)
        Dim token As Token = tokens(i)
        If token.Type1 = TK_IDENTIFIER Then
            If tokens(i + 1).Type1 = TK_ASSIGN Then
                ' Handle variable assignment
                Dim varName As cwstr = token.Value
                Dim exprStart As Integer = i + 2
                Dim exprEnd As Integer = FindExpressionEnd(tokens(), exprStart)
                Dim expr As cwstr = JoinTokens(tokens(), exprStart, exprEnd)
                Dim result As Double = EvaluateExpression(expr)
                ' Store the result in a symbol table
                StoreValue(SymbolTable, varName, result)
                i = exprEnd
            Else
                Print "Error: Expected assignment operator"
                Return -1
            End If
        ElseIf token.Type1 = TK_PRINT Then
            ' Handle print statement Line 239:
            Dim exprStart As Integer
            Dim exprEnd As Integer = FindExpressionEnd(tokens(), exprStart)
            Dim expr As cwstr = JoinTokens(tokens(), exprStart, exprEnd)
            Dim result As Double = EvaluateExpression(expr)
            Print "result "; result
            i = exprEnd + 2
        End If
    Next
    Return 0
End Function

Function GetValue(map As Map, key As cwstr) As Double
    Dim value As cwstr Ptr = MapGet(map, key)
    If value = 0 Then
        Return 0
    Else
        Return Val(*value)
    End If
End Function

' -------------------------- // correct result 50 :-) -------- //
' afxInputBox
'
Dim inputs As cwstr '= "a = 2 + 3 * 10 print a" ' result 50 ok
'Input "make inputs and return: "; inputs
inputs=afxInputbox(0,0,0,"make inputs And Return: ",inputs,"") ';inputs
' b = 4 + 9 * 20 - 10 print b ' result: 250 ok
' c = 6 + 5 * 6 / 4 print c ' result ok 16.5
messagebox(NULL,inputs,"result on console output",mb_ok)

' -------------------------- // correct result 50 :-) -------- //

Dim tokens() As Token
Dim tokenCount As Integer = Split(inputs, tokens())

Dim result As Integer = Parse(tokens())

If result = 0 Then
    Print "Execution completed successfully"
Else
    Print "Error: Execution failed"
End If

' Wait for a key press before closing the console
Print "Press any key to continue..."
Sleep
While Inkey <> "" : Wend
' ends
'
'Dim st As cwstr
'st = afxInputBox(0,0,0,"type in","prog inputbox","")
'messagebox(NULL,st,"prog",mb_ok)