Matheparser
Übersicht

![]() |
NoobodyBetreff: Matheparser |
![]() Antworten mit Zitat ![]() |
---|---|---|
Wie der Titel schon andeutet, habe ich im Laufe der vergangenen Woche einen Algorithmus programmiert, der mathematische Ausdrücke, die als String vorliegen, berechnet (beispielsweise "4+2*3"). Er beherrscht die mathematischen Grundrechenarten Addition, Subtraktion, Multiplikation und Division, sowie Potenzrechnung (z.B. "4^3") und boolsche Operatoren ("23 >= 22").
Selbstverständlich können auch beliebig verschachtelte Klammern verwendet werden. Das Rechensystem arbeitet der Genauigkeit zuliebe grundsätzlich mit Integern. Taucht aber im Term irgendwo eine Float - Zahl auf, wird von dort an mit Floats gerechnet. Beispielsweise würde "3+24/5-6^2" ein Integer - Resultat liefern, "3+24/5.-6^2" hingegen liefert ein Float - Resultat. Desweiteren beherrscht der Rechner Variablen, eine Berechnung der Form "(X/25.)^Variable" ist also ohne weiteres möglich. Der Wert der Variablen kann vor jeder Berechnung neu gesetzt werden, zusammen mit ihrem Typ (Int oder Float). Falls kein Wert gesetzt wurde, haben Variablen standardmässig den Typ Int und den Wert 0. Die Bedienung gestaltet sich denkbar einfach: Ein neuer Term wird durch TTerm.Tokenize erstellt; übergeben wird dabei der mathematische Ausdruck und zurückgeliefert wird ein TTerm - Objekt. Durch die Methode Calculate berechnet das Objekt den mathematischen Ausdruck und liefert dabei entweder TTerm.SYM_INTEGER oder TTerm.SYM_FLOAT zurück - je nach dem, ob das Ergebnis ein Integer oder ein Float ist. Das Ergebnis kann dann in den Feldern ResultInt bzw. ResultFloat abgeholt werden. Wert und Typ von Variablen lassen sich durch die Methoden SetInt bzw. SetFloat setzen. Der erste Parameter ist dabei der Name der Variable, der zweite Parameter der Wert, der der Variable zugewiesen werden soll. Man sollte dabei beachten, dass Variablen case sensitive sind - "Foo" und "foo" sind also nicht dasselbe! Das erste Beispiel zeigt die grundlegende Verwendung sowie die Unterscheidung von Int bzw. Float - Resultaten Code: [AUSKLAPPEN] SuperStrict
Local Term:TTerm = TTerm.Tokenize( "-( ( 2*4^3 > 0 )*34 + 1/( IntVariable - 3*FloatVariable ) + Pi*100 )" ) Term.SetInt( "IntVariable", 25 ) Term.SetFloat( "Pi", 3.14159 ) Term.SetFloat( "FloatVariable", 0.154 ) PrintResult( Term ) 'Das Resultat wird ein Float sein, da sowohl Pi als auch FloatVariable als Float festgelegt wurden Term.SetInt( "IntVariable", 25 ) Term.SetInt( "Pi", 3 ) Term.SetInt( "FloatVariable", 1 ) 'Wenn man nun alle Variablen als Int festsetzt und im Term selbst keine Dezimalzahlen vorkommen, wird nur mit Ints gerechnet PrintResult( Term ) 'Das Resultat wird also ein Integer sein Term.PrintPrefixNotation() 'Um das ganze zu veranschaulichen, wird der Term in der erzeugten Präfixnotation ausgegeben. End Function PrintResult( Term:TTerm ) 'Beispielsfunktion, die einen Term ausrechnen lässt und das Resultat auswertet Local ResultType:Int = Term.Calculate() If ResultType = TTerm.SYM_INTEGER Then Print "Integer result: " + Term.ResultInt Else Print "Float result: " + Term.ResultFloat EndIf End Function '------------------------------------------------------------------------------ Type TTerm Const SYM_PLUS:Int = 1 Const SYM_MINUS:Int = 2 Const SYM_TIMES:Int = 3 Const SYM_DIVIDE:Int = 4 Const SYM_POWEROF:Int = 5 Const SYM_LEFTPARAN:Int = 6 Const SYM_RIGHTPARAN:Int = 7 Const SYM_GREATER:Int = 8 Const SYM_SMALLER:Int = 9 Const SYM_EQUAL:Int = 10 Const SYM_GREATEREQUAL:Int = 11 Const SYM_SMALLEREQUAL:Int = 12 Const SYM_INTEGER:Int = 128 Const SYM_FLOAT:Int = 129 Const SYM_OPERATOR:Int = 130 Const SYM_IDENTIFIER:Int = 131 Global Precedence:Int[] = [ SYM_GREATER, SYM_SMALLER, SYM_EQUAL, SYM_GREATEREQUAL, SYM_SMALLEREQUAL, SYM_PLUS, SYM_MINUS, SYM_TIMES, SYM_DIVIDE, SYM_POWEROF ] Field TermPos:Int Field TermPrefix:Int[ 1024 ] Field TermIdentifier:String[ 64 ] Field TermIdentValue:Int[ 64, 2 ] Field ResultInt:Int Field ResultFloat:Float Function Tokenize:TTerm( SourceTerm:String ) Local Term:TTerm = New TTerm Local SymbolIndex:Int, StringIndex:Int Local TermSymbol:Int[ 1024 ] While Term.TermPos < SourceTerm.Length Local SymbolType:Int = Term.GetSymbol( SourceTerm ) TermSymbol[ SymbolIndex ] = SymbolType SymbolIndex :+ 1 If SymbolType = SYM_INTEGER Then TermSymbol[ SymbolIndex ] = Term.GetInteger( SourceTerm ) SymbolIndex :+ 1 ElseIf SymbolType = SYM_FLOAT Then TermSymbol[ SymbolIndex ] = FloatToInt( Term.GetFloat( SourceTerm ) ) SymbolIndex :+ 1 ElseIf SymbolType = SYM_IDENTIFIER Then TermSymbol[ SymbolIndex ] = StringIndex Term.TermIdentifier[ StringIndex ] = Term.GetIdentifier( SourceTerm ) Term.TermIdentValue[ StringIndex, 0 ] = SYM_INTEGER SymbolIndex :+ 1 StringIndex :+ 1 ElseIf SymbolIndex = 1 Or TermSymbol[ SymbolIndex - 2 ] = SYM_LEFTPARAN Then If SymbolType = SYM_MINUS Then 'Unäres Minus/Plus abfangen - führt sonst zur Endlosrekursion TermSymbol[ SymbolIndex - 1 ] = SYM_INTEGER TermSymbol[ SymbolIndex + 0 ] = 0 TermSymbol[ SymbolIndex + 1 ] = SYM_MINUS SymbolIndex :+ 2 ElseIf SymbolType = SYM_PLUS Then SymbolIndex :- 1 EndIf EndIf Wend TermSymbol = TermSymbol[ .. SymbolIndex ] Term.TermPrefix = Term.ParseSymbols( TermSymbol ) Return Term End Function Method ParseSymbols:Int[]( Symbols:Int[] ) Local Prefix:Int[] For Local i:Int = 0 To Precedence.Length - 1 Local Index:Int = FindSymbol( Symbols, Precedence[ i ] ) If Index >= 0 Then Local Operand1:Int[] = Self.ParseSymbols( Symbols[ .. Index ] ) Local Operand2:Int[] = Self.ParseSymbols( Symbols[ Index + 1 .. ] ) Prefix = [ Precedence[ i ] ] + Operand1 + Operand2 Symbols = Symbols[ Index + 1 + Operand2.Length .. ] Exit ElseIf i = Precedence.Length - 1 If Symbols[ 0 ] = SYM_LEFTPARAN Then Return Self.ParseSymbols( Symbols[ 1 .. Symbols.Length - 1 ] ) Else Return Symbols EndIf EndIf Next Return Prefix End Method Method GetSymbol:Int( SourceTerm:String ) Local Char:String = Self.GetNextChar( SourceTerm ) While Char = " " Char = Self.GetNextChar( SourceTerm ) Wend Select Char Case "+" Return SYM_PLUS Case "-" Return SYM_MINUS Case "*" Return SYM_TIMES Case "/" Return SYM_DIVIDE Case "(" Return SYM_LEFTPARAN Case ")" Return SYM_RIGHTPARAN Case "^" Return SYM_POWEROF Case ">" If Self.GetNextChar( SourceTerm ) = "=" Then Return SYM_GREATEREQUAL Else Self.TermPos :- 1 Return SYM_GREATER EndIf Case "<" If Self.GetNextChar( SourceTerm ) = "=" Then Return SYM_SMALLEREQUAL Else Self.TermPos :- 1 Return SYM_SMALLER EndIf Case "=" Select Self.GetNextChar( SourceTerm ) Case ">" Return SYM_GREATEREQUAL Case "<" Return SYM_SMALLEREQUAL Default Self.TermPos :- 1 Return SYM_EQUAL End Select Default Self.TermPos :- 1 If IsChar( Char ) Then Return SYM_IDENTIFIER If IsDigit( Char ) Then If Self.CheckForFloat( SourceTerm ) Then Return SYM_FLOAT Else Return SYM_INTEGER EndIf EndIf End Select End Method Method GetIdentifier:String( SourceTerm:String ) Local Output:String, Char:String = Self.GetNextChar( SourceTerm ) While IsChar( Char ) Or IsDigit( Char ) Output = Output + Char Char = Self.GetNextChar( SourceTerm ) Wend Self.TermPos :- 1 Return Output End Method Method GetInteger:Int( SourceTerm:String ) Local Output:Int, Char:String = Self.GetNextChar( SourceTerm ) While IsDigit( Char ) Output = Output*10 + Char.ToInt() Char = Self.GetNextChar( SourceTerm ) Wend Self.TermPos :- 1 Return Output End Method Method GetFloat:Float( SourceTerm:String ) Local Output:Float, Char:String = Self.GetNextChar( SourceTerm ) While IsDigit( Char ) Output = Output*10 + Char.ToInt() Char = Self.GetNextChar( SourceTerm ) Wend Local Exponent:Float = 1 While IsDigit( Char ) Or Char = "." Output = Output + Char.ToInt()*Exponent Exponent :/ 10 Char = Self.GetNextChar( SourceTerm ) Wend Self.TermPos :- 1 Return Output End Method Method GetNextChar:String( SourceTerm:String ) Local Char:String = SourceTerm[ Self.TermPos .. Self.TermPos + 1 ] Self.TermPos :+ 1 Return Char End Method Method SetInt( Identifier:String, Value:Int ) For Local i:Int = 0 To Self.TermIdentifier.Length - 1 If Self.TermIdentifier[ i ] = Identifier Then Self.TermIdentValue[ i, 0 ] = SYM_INTEGER Self.TermIdentValue[ i, 1 ] = Value Return EndIf Next Throw "Identifier '" + Identifier + "' not contained in this term" End Method Method SetFloat( Identifier:String, Value:Float ) For Local i:Int = 0 To Self.TermIdentifier.Length - 1 If Self.TermIdentifier[ i ] = Identifier Then Self.TermIdentValue[ i, 0 ] = SYM_FLOAT Self.TermIdentValue[ i, 1 ] = FloatToInt( Value ) Return EndIf Next Throw "Identifier '" + Identifier + "' not contained in this term" End Method Method CheckForFloat:Int( SourceTerm:String ) Local OldPos:Int = Self.TermPos, Char:String = Self.GetNextChar( SourceTerm ) While IsDigit( Char ) Char = Self.GetNextChar( SourceTerm ) Wend Self.TermPos = OldPos If Char = "." Then Return True Else Return False End Method Method Calculate:Int() Local Stack:Int[ 128 ], StackPointer:Int, OperandCount:Int Self.ResultInt = 0 Self.ResultFloat = 0 For Local i:Int = 0 To Self.TermPrefix.Length - 1 If IsTerminal( Self.TermPrefix[ i ] ) Then OperandCount :+ 1 If Self.TermPrefix[ i ] = SYM_INTEGER Or Self.TermPrefix[ i ] = SYM_FLOAT Then Stack[ StackPointer + 1 ] = Self.TermPrefix[ i + 1 ] Stack[ StackPointer ] = Self.TermPrefix[ i ] ElseIf Self.TermPrefix[ i ] = SYM_IDENTIFIER Then Stack[ StackPointer + 1 ] = Self.TermIdentValue[ Self.TermPrefix[ i + 1 ], 1 ] Stack[ StackPointer ] = Self.TermIdentValue[ Self.TermPrefix[ i + 1 ], 0 ] EndIf i :+ 1 While OperandCount = 2 Local SP:Int = StackPointer, ResultType:Int = SYM_INTEGER Select Stack[ StackPointer - 3 ] Case SYM_PLUS If Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = Stack[ SP - 1 ] + Stack[ SP + 1 ] .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) + Stack[ SP + 1 ] ) .. ElseIf Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( Stack[ SP - 1 ] + IntToFloat( Stack[ SP + 1 ] ) ) .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) + IntToFloat( Stack[ SP + 1 ] ) ) Case SYM_MINUS If Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = Stack[ SP - 1 ] - Stack[ SP + 1 ] .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) - Stack[ SP + 1 ] ) .. ElseIf Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( Stack[ SP - 1 ] - IntToFloat( Stack[ SP + 1 ] ) ) .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) - IntToFloat( Stack[ SP + 1 ] ) ) Case SYM_TIMES If Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = Stack[ SP - 1 ] * Stack[ SP + 1 ] .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) * Stack[ SP + 1 ] ) .. ElseIf Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( Stack[ SP - 1 ] * IntToFloat( Stack[ SP + 1 ] ) ) .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) * IntToFloat( Stack[ SP + 1 ] ) ) Case SYM_DIVIDE If Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = Stack[ SP - 1 ] / Stack[ SP + 1 ] .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) / Stack[ SP + 1 ] ) .. ElseIf Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( Stack[ SP - 1 ] / IntToFloat( Stack[ SP + 1 ] ) ) .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) / IntToFloat( Stack[ SP + 1 ] ) ) Case SYM_POWEROF If Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = Stack[ SP - 1 ] ^ Stack[ SP + 1 ] .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) ^ Stack[ SP + 1 ] ) .. ElseIf Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( Stack[ SP - 1 ] ^ IntToFloat( Stack[ SP + 1 ] ) ) .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) ^ IntToFloat( Stack[ SP + 1 ] ) ) Case SYM_GREATER If Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = Stack[ SP - 1 ] > Stack[ SP + 1 ] .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) > Stack[ SP + 1 ] ) .. ElseIf Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( Stack[ SP - 1 ] > IntToFloat( Stack[ SP + 1 ] ) ) .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) > IntToFloat( Stack[ SP + 1 ] ) ) Case SYM_SMALLER If Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = Stack[ SP - 1 ] < Stack[ SP + 1 ] .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) < Stack[ SP + 1 ] ) .. ElseIf Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( Stack[ SP - 1 ] < IntToFloat( Stack[ SP + 1 ] ) ) .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) < IntToFloat( Stack[ SP + 1 ] ) ) Case SYM_EQUAL If Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = Stack[ SP - 1 ] = Stack[ SP + 1 ] .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) = Stack[ SP + 1 ] ) .. ElseIf Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( Stack[ SP - 1 ] = IntToFloat( Stack[ SP + 1 ] ) ) .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) = IntToFloat( Stack[ SP + 1 ] ) ) Case SYM_GREATEREQUAL If Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = Stack[ SP - 1 ] >= Stack[ SP + 1 ] .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) >= Stack[ SP + 1 ] ) .. ElseIf Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( Stack[ SP - 1 ] >= IntToFloat( Stack[ SP + 1 ] ) ) .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) >= IntToFloat( Stack[ SP + 1 ] ) ) Case SYM_SMALLEREQUAL If Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = Stack[ SP - 1 ] <= Stack[ SP + 1 ] .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) <= Stack[ SP + 1 ] ) .. ElseIf Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( Stack[ SP - 1 ] <= IntToFloat( Stack[ SP + 1 ] ) ) .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) <= IntToFloat( Stack[ SP + 1 ] ) ) End Select If Stack[ StackPointer ] = SYM_FLOAT Or Stack[ StackPointer - 2 ] = SYM_FLOAT Then Stack[ StackPointer - 4 ] = SYM_FLOAT Else Stack[ StackPointer - 4 ] = SYM_INTEGER EndIf StackPointer :- 4 If StackPointer >= 2 And IsTerminal( Stack[ StackPointer - 2 ] ) Then OperandCount = 2 Else OperandCount = 1 Wend StackPointer :+ 2 Else Stack[ StackPointer ] = SYM_OPERATOR Stack[ StackPointer + 1 ] = Self.TermPrefix[ i ] StackPointer :+ 2 OperandCount = 0 EndIf Next If Stack[ 0 ] = SYM_INTEGER Then Self.ResultInt = Stack[ 1 ] Else Self.ResultFloat = IntToFloat( Stack[ 1 ] ) EndIf Return Stack[ 0 ] End Method Function IsDigit:Int( Char:String ) If Asc( Char ) >= 48 And Asc( Char ) <= 57 Then Return True End Function Function IsChar:Int( Char:String ) If Asc( Char ) >=65 And Asc( Char ) <= 90 Then Return True If Asc( Char ) >=97 And Asc( Char ) <= 122 Then Return True End Function Function IsTerminal:Int( Symbol:Int ) If Symbol = SYM_INTEGER Or Symbol = SYM_FLOAT Or Symbol = SYM_IDENTIFIER Then Return True End Function Function FindSymbol:Int( Symbols:Int[], SoughtSymbol:Int, StartIndex:Int = 0 ) Local NestLevel:Int For Local i:Int = StartIndex To Symbols.Length - 1 If Symbols[ i ] = SoughtSymbol And NestLevel = 0 Then Return i ElseIf IsTerminal( Symbols[ i ] ) Then i :+ 1 ElseIf Symbols[ i ] = SYM_LEFTPARAN NestLevel :+ 1 ElseIf Symbols[ i ] = SYM_RIGHTPARAN NestLevel :- 1 If NestLevel < 0 Then Return -1 EndIf Next Return -1 End Function Function FloatToInt:Int( Source:Float ) Return ( Int Ptr ( Varptr Source ) )[ 0 ] End Function Function IntToFloat:Float( Source:Int ) Return ( Float Ptr ( Varptr Source ) )[ 0 ] End Function Method PrintPrefixNotation() For Local i:Int = 0 To Self.TermPrefix.Length - 1 Select Self.TermPrefix[ i ] Case SYM_PLUS WriteStdout "+ " Case SYM_MINUS WriteStdout "- " Case SYM_TIMES WriteStdout "* " Case SYM_DIVIDE WriteStdout "/ " Case SYM_LEFTPARAN WriteStdout "( " Case SYM_RIGHTPARAN WriteStdout ") " Case SYM_POWEROF WriteStdout "^ " Case SYM_GREATER WriteStdout "> " Case SYM_SMALLER WriteStdout "< " Case SYM_EQUAL WriteStdout "= " Case SYM_GREATEREQUAL WriteStdout ">= " Case SYM_SMALLEREQUAL WriteStdout "<= " Case SYM_INTEGER i :+ 1 WriteStdout Self.TermPrefix[ i ] + " " Case SYM_FLOAT i :+ 1 WriteStdout IntToFloat( Self.TermPrefix[ i ] ) + " " Case SYM_IDENTIFIER i :+ 1 WriteStdout Self.TermIdentifier[ Self.TermPrefix[ i ] ] + " " End Select Next Print "" End Method End Type Das zweite Beispiel macht einen kleinen Stresstest und zeichnet vier verschiedene Graphen mithilfe des Termsystems Code: [AUSKLAPPEN] SuperStrict
Const GWIDTH:Int = 800 Const GHEIGHT:Int = 600 Graphics GWIDTH, GHEIGHT, 0, 2 Local Graph1:TTerm = TTerm.Tokenize( "-(((X-400)*Scale)^2-300)" ) 'Quadratische Funktion (x^2) Local Graph2:TTerm = TTerm.Tokenize( "-(1/((X-400)*Scale)-300)" ) 'Reziproke Funktion (1/x) Local Graph3:TTerm = TTerm.Tokenize( "-(2^((X-400)*Scale)-300)" ) 'Exponentielle Funktion (2^x) Local Graph4:TTerm = TTerm.Tokenize( "-200*(X<=(800/2))+400" ) 'Boolsche Funktion (x<=400) Graph1.SetFloat( "Scale", 0.05 ) Graph2.SetFloat( "Scale", 0.0001 ) Graph3.SetFloat( "Scale", 0.03 ) Local Timer:TTimer = CreateTimer( 60 ) While Not KeyHit( KEY_ESCAPE ) Cls Local Counter:Int = MilliSecs() PlotGraph( Graph1, 5, 255, 0, 0 ) PlotGraph( Graph2, 5, 0, 255, 0 ) PlotGraph( Graph3, 5, 0, 0, 255 ) PlotGraph( Graph4, 5, 255, 255, 0 ) SetColor 255, 255, 255 DrawText "Render/Rechenzeit: " + ( MilliSecs() - Counter ), 0, 0 Flip 0 WaitTimer Timer Wend Function PlotGraph( Term:TTerm, DrawStep:Int = 5, R:Int = 255, G:Int = 255, B:Int = 255 ) 'Beispielsfunktion, die einen Graph zeichnet Local OldY:Float, CurrentY:Float SetColor R, G, B For Local X:Int = 0 To GWIDTH/DrawStep Term.SetFloat( "X", X*DrawStep ) Local ResultType:Int = Term.Calculate() If ResultType = TTerm.SYM_INTEGER CurrentY = Term.ResultInt Else CurrentY = Term.ResultFloat EndIf If X > 0 Then DrawLine ( X - 1 )*DrawStep, OldY, X*DrawStep, CurrentY OldY = CurrentY Next End Function '---------------------------------------------------------------------------- Type TTerm Const SYM_PLUS:Int = 1 Const SYM_MINUS:Int = 2 Const SYM_TIMES:Int = 3 Const SYM_DIVIDE:Int = 4 Const SYM_POWEROF:Int = 5 Const SYM_LEFTPARAN:Int = 6 Const SYM_RIGHTPARAN:Int = 7 Const SYM_GREATER:Int = 8 Const SYM_SMALLER:Int = 9 Const SYM_EQUAL:Int = 10 Const SYM_GREATEREQUAL:Int = 11 Const SYM_SMALLEREQUAL:Int = 12 Const SYM_INTEGER:Int = 128 Const SYM_FLOAT:Int = 129 Const SYM_OPERATOR:Int = 130 Const SYM_IDENTIFIER:Int = 131 Global Precedence:Int[] = [ SYM_GREATER, SYM_SMALLER, SYM_EQUAL, SYM_GREATEREQUAL, SYM_SMALLEREQUAL, SYM_PLUS, SYM_MINUS, SYM_TIMES, SYM_DIVIDE, SYM_POWEROF ] Field TermPos:Int Field TermPrefix:Int[ 1024 ] Field TermIdentifier:String[ 64 ] Field TermIdentValue:Int[ 64, 2 ] Field ResultInt:Int Field ResultFloat:Float Function Tokenize:TTerm( SourceTerm:String ) Local Term:TTerm = New TTerm Local SymbolIndex:Int, StringIndex:Int Local TermSymbol:Int[ 1024 ] While Term.TermPos < SourceTerm.Length Local SymbolType:Int = Term.GetSymbol( SourceTerm ) TermSymbol[ SymbolIndex ] = SymbolType SymbolIndex :+ 1 If SymbolType = SYM_INTEGER Then TermSymbol[ SymbolIndex ] = Term.GetInteger( SourceTerm ) SymbolIndex :+ 1 ElseIf SymbolType = SYM_FLOAT Then TermSymbol[ SymbolIndex ] = FloatToInt( Term.GetFloat( SourceTerm ) ) SymbolIndex :+ 1 ElseIf SymbolType = SYM_IDENTIFIER Then TermSymbol[ SymbolIndex ] = StringIndex Term.TermIdentifier[ StringIndex ] = Term.GetIdentifier( SourceTerm ) Term.TermIdentValue[ StringIndex, 0 ] = SYM_INTEGER SymbolIndex :+ 1 StringIndex :+ 1 ElseIf SymbolIndex = 1 Or TermSymbol[ SymbolIndex - 2 ] = SYM_LEFTPARAN Then If SymbolType = SYM_MINUS Then 'Unäres Minus/Plus abfangen - führt sonst zur Endlosrekursion TermSymbol[ SymbolIndex - 1 ] = SYM_INTEGER TermSymbol[ SymbolIndex + 0 ] = 0 TermSymbol[ SymbolIndex + 1 ] = SYM_MINUS SymbolIndex :+ 2 ElseIf SymbolType = SYM_PLUS Then SymbolIndex :- 1 EndIf EndIf Wend TermSymbol = TermSymbol[ .. SymbolIndex ] Term.TermPrefix = Term.ParseSymbols( TermSymbol ) Return Term End Function Method ParseSymbols:Int[]( Symbols:Int[] ) Local Prefix:Int[] For Local i:Int = 0 To Precedence.Length - 1 Local Index:Int = FindSymbol( Symbols, Precedence[ i ] ) If Index >= 0 Then Local Operand1:Int[] = Self.ParseSymbols( Symbols[ .. Index ] ) Local Operand2:Int[] = Self.ParseSymbols( Symbols[ Index + 1 .. ] ) Prefix = [ Precedence[ i ] ] + Operand1 + Operand2 Symbols = Symbols[ Index + 1 + Operand2.Length .. ] Exit ElseIf i = Precedence.Length - 1 If Symbols[ 0 ] = SYM_LEFTPARAN Then Return Self.ParseSymbols( Symbols[ 1 .. Symbols.Length - 1 ] ) Else Return Symbols EndIf EndIf Next Return Prefix End Method Method GetSymbol:Int( SourceTerm:String ) Local Char:String = Self.GetNextChar( SourceTerm ) While Char = " " Char = Self.GetNextChar( SourceTerm ) Wend Select Char Case "+" Return SYM_PLUS Case "-" Return SYM_MINUS Case "*" Return SYM_TIMES Case "/" Return SYM_DIVIDE Case "(" Return SYM_LEFTPARAN Case ")" Return SYM_RIGHTPARAN Case "^" Return SYM_POWEROF Case ">" If Self.GetNextChar( SourceTerm ) = "=" Then Return SYM_GREATEREQUAL Else Self.TermPos :- 1 Return SYM_GREATER EndIf Case "<" If Self.GetNextChar( SourceTerm ) = "=" Then Return SYM_SMALLEREQUAL Else Self.TermPos :- 1 Return SYM_SMALLER EndIf Case "=" Select Self.GetNextChar( SourceTerm ) Case ">" Return SYM_GREATEREQUAL Case "<" Return SYM_SMALLEREQUAL Default Self.TermPos :- 1 Return SYM_EQUAL End Select Default Self.TermPos :- 1 If IsChar( Char ) Then Return SYM_IDENTIFIER If IsDigit( Char ) Then If Self.CheckForFloat( SourceTerm ) Then Return SYM_FLOAT Else Return SYM_INTEGER EndIf EndIf End Select End Method Method GetIdentifier:String( SourceTerm:String ) Local Output:String, Char:String = Self.GetNextChar( SourceTerm ) While IsChar( Char ) Or IsDigit( Char ) Output = Output + Char Char = Self.GetNextChar( SourceTerm ) Wend Self.TermPos :- 1 Return Output End Method Method GetInteger:Int( SourceTerm:String ) Local Output:Int, Char:String = Self.GetNextChar( SourceTerm ) While IsDigit( Char ) Output = Output*10 + Char.ToInt() Char = Self.GetNextChar( SourceTerm ) Wend Self.TermPos :- 1 Return Output End Method Method GetFloat:Float( SourceTerm:String ) Local Output:Float, Char:String = Self.GetNextChar( SourceTerm ) While IsDigit( Char ) Output = Output*10 + Char.ToInt() Char = Self.GetNextChar( SourceTerm ) Wend Local Exponent:Float = 1 While IsDigit( Char ) Or Char = "." Output = Output + Char.ToInt()*Exponent Exponent :/ 10 Char = Self.GetNextChar( SourceTerm ) Wend Self.TermPos :- 1 Return Output End Method Method GetNextChar:String( SourceTerm:String ) Local Char:String = SourceTerm[ Self.TermPos .. Self.TermPos + 1 ] Self.TermPos :+ 1 Return Char End Method Method SetInt( Identifier:String, Value:Int ) For Local i:Int = 0 To Self.TermIdentifier.Length - 1 If Self.TermIdentifier[ i ] = Identifier Then Self.TermIdentValue[ i, 0 ] = SYM_INTEGER Self.TermIdentValue[ i, 1 ] = Value Return EndIf Next Throw "Identifier '" + Identifier + "' not contained in this term" End Method Method SetFloat( Identifier:String, Value:Float ) For Local i:Int = 0 To Self.TermIdentifier.Length - 1 If Self.TermIdentifier[ i ] = Identifier Then Self.TermIdentValue[ i, 0 ] = SYM_FLOAT Self.TermIdentValue[ i, 1 ] = FloatToInt( Value ) Return EndIf Next Throw "Identifier '" + Identifier + "' not contained in this term" End Method Method CheckForFloat:Int( SourceTerm:String ) Local OldPos:Int = Self.TermPos, Char:String = Self.GetNextChar( SourceTerm ) While IsDigit( Char ) Char = Self.GetNextChar( SourceTerm ) Wend Self.TermPos = OldPos If Char = "." Then Return True Else Return False End Method Method Calculate:Int() Local Stack:Int[ 128 ], StackPointer:Int, OperandCount:Int Self.ResultInt = 0 Self.ResultFloat = 0 For Local i:Int = 0 To Self.TermPrefix.Length - 1 If IsTerminal( Self.TermPrefix[ i ] ) Then OperandCount :+ 1 If Self.TermPrefix[ i ] = SYM_INTEGER Or Self.TermPrefix[ i ] = SYM_FLOAT Then Stack[ StackPointer + 1 ] = Self.TermPrefix[ i + 1 ] Stack[ StackPointer ] = Self.TermPrefix[ i ] ElseIf Self.TermPrefix[ i ] = SYM_IDENTIFIER Then Stack[ StackPointer + 1 ] = Self.TermIdentValue[ Self.TermPrefix[ i + 1 ], 1 ] Stack[ StackPointer ] = Self.TermIdentValue[ Self.TermPrefix[ i + 1 ], 0 ] EndIf i :+ 1 While OperandCount = 2 Local SP:Int = StackPointer, ResultType:Int = SYM_INTEGER Select Stack[ StackPointer - 3 ] Case SYM_PLUS If Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = Stack[ SP - 1 ] + Stack[ SP + 1 ] .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) + Stack[ SP + 1 ] ) .. ElseIf Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( Stack[ SP - 1 ] + IntToFloat( Stack[ SP + 1 ] ) ) .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) + IntToFloat( Stack[ SP + 1 ] ) ) Case SYM_MINUS If Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = Stack[ SP - 1 ] - Stack[ SP + 1 ] .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) - Stack[ SP + 1 ] ) .. ElseIf Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( Stack[ SP - 1 ] - IntToFloat( Stack[ SP + 1 ] ) ) .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) - IntToFloat( Stack[ SP + 1 ] ) ) Case SYM_TIMES If Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = Stack[ SP - 1 ] * Stack[ SP + 1 ] .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) * Stack[ SP + 1 ] ) .. ElseIf Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( Stack[ SP - 1 ] * IntToFloat( Stack[ SP + 1 ] ) ) .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) * IntToFloat( Stack[ SP + 1 ] ) ) Case SYM_DIVIDE If Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = Stack[ SP - 1 ] / Stack[ SP + 1 ] .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) / Stack[ SP + 1 ] ) .. ElseIf Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( Stack[ SP - 1 ] / IntToFloat( Stack[ SP + 1 ] ) ) .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) / IntToFloat( Stack[ SP + 1 ] ) ) Case SYM_POWEROF If Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = Stack[ SP - 1 ] ^ Stack[ SP + 1 ] .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) ^ Stack[ SP + 1 ] ) .. ElseIf Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( Stack[ SP - 1 ] ^ IntToFloat( Stack[ SP + 1 ] ) ) .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) ^ IntToFloat( Stack[ SP + 1 ] ) ) Case SYM_GREATER If Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = Stack[ SP - 1 ] > Stack[ SP + 1 ] .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) > Stack[ SP + 1 ] ) .. ElseIf Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( Stack[ SP - 1 ] > IntToFloat( Stack[ SP + 1 ] ) ) .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) > IntToFloat( Stack[ SP + 1 ] ) ) Case SYM_SMALLER If Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = Stack[ SP - 1 ] < Stack[ SP + 1 ] .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) < Stack[ SP + 1 ] ) .. ElseIf Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( Stack[ SP - 1 ] < IntToFloat( Stack[ SP + 1 ] ) ) .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) < IntToFloat( Stack[ SP + 1 ] ) ) Case SYM_EQUAL If Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = Stack[ SP - 1 ] = Stack[ SP + 1 ] .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) = Stack[ SP + 1 ] ) .. ElseIf Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( Stack[ SP - 1 ] = IntToFloat( Stack[ SP + 1 ] ) ) .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) = IntToFloat( Stack[ SP + 1 ] ) ) Case SYM_GREATEREQUAL If Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = Stack[ SP - 1 ] >= Stack[ SP + 1 ] .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) >= Stack[ SP + 1 ] ) .. ElseIf Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( Stack[ SP - 1 ] >= IntToFloat( Stack[ SP + 1 ] ) ) .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) >= IntToFloat( Stack[ SP + 1 ] ) ) Case SYM_SMALLEREQUAL If Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = Stack[ SP - 1 ] <= Stack[ SP + 1 ] .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_INTEGER Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) <= Stack[ SP + 1 ] ) .. ElseIf Stack[ SP - 2 ] = SYM_INTEGER And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( Stack[ SP - 1 ] <= IntToFloat( Stack[ SP + 1 ] ) ) .. ElseIf Stack[ SP - 2 ] = SYM_FLOAT And Stack[ SP ] = SYM_FLOAT Then Stack[ SP - 3 ] = FloatToInt( IntToFloat( Stack[ SP - 1 ] ) <= IntToFloat( Stack[ SP + 1 ] ) ) End Select If Stack[ StackPointer ] = SYM_FLOAT Or Stack[ StackPointer - 2 ] = SYM_FLOAT Then Stack[ StackPointer - 4 ] = SYM_FLOAT Else Stack[ StackPointer - 4 ] = SYM_INTEGER EndIf StackPointer :- 4 If StackPointer >= 2 And IsTerminal( Stack[ StackPointer - 2 ] ) Then OperandCount = 2 Else OperandCount = 1 Wend StackPointer :+ 2 Else Stack[ StackPointer ] = SYM_OPERATOR Stack[ StackPointer + 1 ] = Self.TermPrefix[ i ] StackPointer :+ 2 OperandCount = 0 EndIf Next If Stack[ 0 ] = SYM_INTEGER Then Self.ResultInt = Stack[ 1 ] Else Self.ResultFloat = IntToFloat( Stack[ 1 ] ) EndIf Return Stack[ 0 ] End Method Function IsDigit:Int( Char:String ) If Asc( Char ) >= 48 And Asc( Char ) <= 57 Then Return True End Function Function IsChar:Int( Char:String ) If Asc( Char ) >=65 And Asc( Char ) <= 90 Then Return True If Asc( Char ) >=97 And Asc( Char ) <= 122 Then Return True End Function Function IsTerminal:Int( Symbol:Int ) If Symbol = SYM_INTEGER Or Symbol = SYM_FLOAT Or Symbol = SYM_IDENTIFIER Then Return True End Function Function FindSymbol:Int( Symbols:Int[], SoughtSymbol:Int, StartIndex:Int = 0 ) Local NestLevel:Int For Local i:Int = StartIndex To Symbols.Length - 1 If Symbols[ i ] = SoughtSymbol And NestLevel = 0 Then Return i ElseIf IsTerminal( Symbols[ i ] ) Then i :+ 1 ElseIf Symbols[ i ] = SYM_LEFTPARAN NestLevel :+ 1 ElseIf Symbols[ i ] = SYM_RIGHTPARAN NestLevel :- 1 If NestLevel < 0 Then Return -1 EndIf Next Return -1 End Function Function FloatToInt:Int( Source:Float ) Return ( Int Ptr ( Varptr Source ) )[ 0 ] End Function Function IntToFloat:Float( Source:Int ) Return ( Float Ptr ( Varptr Source ) )[ 0 ] End Function Method PrintPrefixNotation() For Local i:Int = 0 To Self.TermPrefix.Length - 1 Select Self.TermPrefix[ i ] Case SYM_PLUS WriteStdout "+ " Case SYM_MINUS WriteStdout "- " Case SYM_TIMES WriteStdout "* " Case SYM_DIVIDE WriteStdout "/ " Case SYM_LEFTPARAN WriteStdout "( " Case SYM_RIGHTPARAN WriteStdout ") " Case SYM_POWEROF WriteStdout "^ " Case SYM_GREATER WriteStdout "> " Case SYM_SMALLER WriteStdout "< " Case SYM_EQUAL WriteStdout "= " Case SYM_GREATEREQUAL WriteStdout ">= " Case SYM_SMALLEREQUAL WriteStdout "<= " Case SYM_INTEGER i :+ 1 WriteStdout Self.TermPrefix[ i ] + " " Case SYM_FLOAT i :+ 1 WriteStdout IntToFloat( Self.TermPrefix[ i ] ) + " " Case SYM_IDENTIFIER i :+ 1 WriteStdout Self.TermIdentifier[ Self.TermPrefix[ i ] ] + " " End Select Next Print "" End Method End Type Anders als meine damalige Umsetzung in BB basiert dieser Algorithmus auf der Präfixnotation und läuft daher um einiges schneller. Ausserdem macht die Berechnungsfunktion eine Unterscheidung von Int und Float, weswegen viel genauere Resultate möglich sind. |
||
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun |
Übersicht


Powered by phpBB © 2001 - 2006, phpBB Group