Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Endlich geschafft. Ich möchte hier meinen Postfix-Parser vorstellen (der code ist nen bischen undurchsichtig, aber wer was über Postfix-Parser weis, sollte durchschauen).
Ich hab seit 1-2 Jahren mich mit so nem Parser beschäftigt, doch es nie richtig hinbekommen.
;/ infix
;a + b * c + (d * e + f) * g
;a + b * c + d * e + f * g
;/ postfix
;a b c * + d e * f + g * +
;a b c * + d e * + f g * +
EnableExplicit
Define Infix.s = "a+b*c+(d*e+f)*g"
Define s.s{1}
Macro m_IsOperand
s = "a" Or s = "b" Or s = "c" Or s = "d" Or s = "e" Or s = "f" Or s = "g"
EndMacro
Macro m_IsOperator
s = "+" Or s = "*"
EndMacro
Define operand_left.s{1}
Define operand_right.s{1}
Define operator.s{1}
Define diference.l
Define ToOperatorStack.b
Procedure.l GetOperatorPriority(operator.s)
Select operator
Case "+" : ProcedureReturn 1
Case "*" : ProcedureReturn 2
EndSelect
EndProcedure
Structure Stack
clip_level.l
s.s{1}
EndStructure
NewList Stack.s{1}() ; Initialisiere Stack
NewList OperatorStack.Stack()
NewList Output.s{1}()
Define n.l, clip_level.l
For n = 1 To Len(Infix); DO Lese Postfix-Ausdruck Symbol für Symbol
s = Mid(Infix, n, 1)
Debug s
If m_IsOperand ;IF nächstes Symbol ein Operand THEN
AddElement(Stack()) : Stack() = s ;push Operand
ElseIf s = "("
clip_level + 1
Debug "CKIP +1"
ElseIf s = ")"
clip_level - 1
Debug "CKIP -1"
ElseIf m_IsOperator ;IF nächstes Symbol ein Operator THEN
Debug "OP--------"
If CountList(Stack()) <> 0
operand_left = Stack() : DeleteElement(Stack(), #True)
AddElement(Output()) : Output() = operand_left
Else
operand_left = ""
EndIf
operator = s
ToOperatorStack = #True
s = Mid(Infix, n+1, 1)
If m_IsOperand
n + 1
ToOperatorStack = #False
operand_right = s
AddElement(Output()) : Output() = operand_right
EndIf
diference = 0
s = Mid(Infix, n+1, 1)
If ToOperatorStack Or ( (m_IsOperator) And GetOperatorPriority(operator) < GetOperatorPriority(s) )
AddElement(OperatorStack()) : OperatorStack()\s = operator : OperatorStack()\clip_level = clip_level
diference + 1
Else
AddElement(Output()) : Output() = operator
EndIf
If CountList(OperatorStack())-diference
SelectElement(OperatorStack(), CountList(OperatorStack())-1-diference)
Repeat
If OperatorStack()\clip_level = clip_level And (Not GetOperatorPriority(OperatorStack()\s) < GetOperatorPriority(s))
Debug "AddOutputFromOp.Stack "+OperatorStack()\s+" "+Str(OperatorStack()\clip_level)+" = "+Str(clip_level)
AddElement(Output()) : Output() = OperatorStack()\s
DeleteElement(OperatorStack(), #True)
Else
Break
EndIf
Until PreviousElement(OperatorStack()) = 0
EndIf
EndIf;FI
Next ;OD
Debug "RESULT ---------------------------"
;Schlussresultat auf dem Stack
ForEach Output()
Debug Output()
Next
Verbesserungsvorschläge sind herzlich willkommen. Wer lust hat, den Code schönder zu schreiben (und zu kommentieren) wird herzlich dazu "eingelanden"
Ich habe das mal als Recursive Descent Parser umgesetzt. Der Code
macht im Prinzip auch nichts anderes als dein Code, dürfte sich aber
ein bisschen leichter erweitern lassen. Die Fehlerbehandlung ist zwar
nicht perfekt, aber in den meisten Fällen funktioniert sie.
Dein Beispiel ist gut, aber für meine verhältnisse etwas unpraktisch.
Ich habe nur bewusst mit Operatoren-Priotität gearbeitet, da ich es unsinn finde, das ganze mit bis zu 9 verschiedenen Prioritäten alles in eine Procedure zu fassen.
Ich weis, das es bei meinem Parser etwas schwer ist, Operatoren wie '=' und ! einzubauen, aber man hat, wenn man es geschaft hat, eine schöne, kleine Procedure, die alle expressions ausführen kann (und keinen haufen von vielen verschachtelten Proceduren).