Shunting-yard Algorithm with functions debugging

五迷三道 提交于 2019-12-14 02:20:06

问题


I want to implement "functions" in the shunting-yard algorithm beside operators and make a little interpreter from the resulting algorithm but syntactic incorrect usage of tokens is ignored by the default algorithm.

is there anyone that has written a interpreter (or not) wanting to help me? that would help a lot of people that are stuck with this problem!

here are some tests listed, the shunting-yard function ignores the wrong usage of tokens in function calls and/or missing operators/operands:

func(,1)
func(2,)
func(,,,,,)
()
(((()))()())
func((),(,))
func(1,2(3,4))
etc...

some research that i read:

http://www.reedbeta.com/blog/2011/12/11/the-shunting-yard-algorithm/
http://en.wikipedia.org/wiki/Shunting-yard_algorithm
http://rosettacode.org/wiki/Parsing/Shunting-yard_algorithm

explanation of my code (vbscript) to test this with a few improvements:

it allows usage of functions(beta)
it gives an error with most of the incorrect syntax
functions can be nested

if there are people that want to share there improvements or have any good ideas then please let me know!

my code:

Function Is_Empty(Stack)
If UBound(Stack) > - 1 Then
Is_Empty = False
Else
Is_Empty = True
End If
End Function
Function Peek(Stack)
If UBound(Stack) > - 1 Then
Peek = Stack(UBound(Stack))
End If
End Function
Function Pop(ByRef Stack)
If UBound(Stack) > - 1 Then
Pop = Stack(UBound(Stack))
ReDim Preserve Stack(UBound(Stack) - 1)
End If
End Function
Sub Push(Item, ByRef Stack)
If UBound(Stack) > - 1 Then
ReDim Preserve Stack(UBound(Stack) + 1)
Stack(UBound(Stack)) = Item
Else
Stack = Array(Item)
End If
End Sub
Set Prec = CreateObject("scripting.dictionary")
With Prec
.Add "+", 1
.Add "-", 1
.Add "*", 2
.Add "/", 2
End With
Function Is_Operator(Op)
Is_Operator = Prec.Exists(Op)
End Function

Set Re = New RegExp
Re.Pattern = "[a-z0-9]+|[+\-/*,()]"
Re.Global = True
Set X = Re.Execute("func (1,1(1,1))")'//here the test code

Stack = Array() : Queue = Array() : Level = 0

For Each Token In X
Select Case Token
Case "func"
Call Push(Token, Stack)
Case "("
If Peek(Stack) = "func" Then
Level = Level + 1
Call Push("#", Queue)
End If
Call Push(Token, Stack)
Case ")"
Do While Not(Peek(Stack) = "(")
If Is_Empty(Stack) Then MsgBox "error: (", 48 : WScript.Quit
Call Push(Pop(Stack), Queue)
Loop
Discard = Pop(Stack)
If Peek(Stack) = "func" Then
Level = Level - 1
If Peek(Queue) = "," Then MsgBox "error: ,", 48 : WScript.Quit
Call Push(Pop(Stack), Queue)
End If
Case ","
If Level = 0 Then MsgBox "error: ,", 48 : WScript.Quit
If Peek(Queue) = "#" Then MsgBox "error: ,", 48 : WScript.Quit
If Peek(Queue) = "," Then MsgBox "error: ,", 48 : WScript.Quit
Do While Not(Peek(Stack) = "(")
If Is_Empty(Stack) Then MsgBox "error: ( or ,", 48 : WScript.Quit
Call Push(Pop(Stack), Queue)
Loop
Call Push(Token, Queue)
Case "+", "-", "*", "/"
A = Token
Do While Is_Operator(Peek(Stack))
B = Peek(Stack)
If Prec(A) < Prec(B) Then
Call Push(Pop(Stack), Queue)
Else
Exit Do
End If
Loop
If Peek(Queue) = "," Then MsgBox "error: wrong operator", 48 : WScript.Quit
Call Push(A, Stack)
Case Else
Call Push(Token, Queue)
End Select
Next
For I = 0 To UBound(Stack)
If Peek(Stack) = "(" Then MsgBox "error: )", 48 : WScript.Quit
Call Push(Pop(Stack), Queue)
Next

MsgBox Join(Queue, "|"),, Level
stack = array()

For Counter = 0 To UBound(Queue)
select case queue(counter)
case "func"
do while not(peek(stack) = "#")
if peek(stack) = "," then
l = l + 1
discart = pop(stack)
elseif is_empty(stack) then
exit do
else
F = F + INT(pop(stack))
end if
loop
discart = pop(stack)
call push(F, stack)
case "+","-","*","/"
B = pop(stack)
if is_empty(stack) then MsgBox "error: not enough values", 48 : WScript.Quit
A = pop(stack)
if not(isnumeric(a) and isnumeric(b)) then MsgBox "error: not numeric", 48 : WScript.Quit
select case queue(Counter)
case "+"
C = int(a) + int(b)
case "-"
C = int(a) - int(b)
case "*"
C = int(a) * int(b)
case "/"
C = int(a) / int(b)
case else
MsgBox "error: " & queue(Counter), 48 : WScript.Quit
end select
call push(c, stack)
case else
Call Push(queue(Counter), Stack)
end select
next
If UBound(Stack) > 0 Then MsgBox "too many values", 48 : WScript.Quit
If is_empty(Stack) Then MsgBox "error: not enough values", 48 : WScript.Quit

msgbox stack(0),0,"result!"

[EDIT] I want the syntax of my interpreter to be almost exactly the same as the BASIC programming language.

example of a BASIC like expression: a + b * (c / func(x, y, func(z))) - d

example of a syntactic wrong expression: 1 + 2 + + 3 3 func(,1,(,2)) ()

my goal: the output of the shunting yard algorithm should be in the right order, and if problems in the syntax are encountered there should be an error: empty brackets "()" or multiple operators/functions/integers after each other or wrong brackets in function calls are not allowed...

so far functions, integers and operators are in the right order if you type the expression the right way!

if it works in vbscript itself, it should work in this algorithm, if not then it should not work in this script ether, and you get an error... that's what i'm trying to do here..

how i want the syntax to be: (between "[]" means optional, ";" is a comment, between "##" is a link to the description with that title...)

#function#:
func([#expression#[, #expression#[, #expression#...]]]) ; 

#number#:
(0-9)+ ; integers from 0 to ...

#operator#:
( ; open bracket, can be a function grouping or part of an expression
) ; closing bracket (see open bracket for details)
  ; bracket rules: must start with an open and stop with a closed bracket,
  ; can be nested but there must be something inside them!
, ; function argument seperator
+ ; plus
- ; minus
* ; multiply (higher prec than + and -)
/ ; divide (same prec as multiply)

#operand#:
#number# or #function#

#expression#:
#operand# [#operator# #operand#[ #operator# #operand#[ and so on...]]]

来源:https://stackoverflow.com/questions/28593987/shunting-yard-algorithm-with-functions-debugging

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!