Author Topic: Numeric/String Eval function  (Read 6091 times)

0 Members and 1 Guest are viewing this topic.

Offline Ed Davis

  • Newbie
  • Posts: 40
    • View Profile
Re: Numeric/String Eval function
« Reply #15 on: March 02, 2021, 12:54:01 am »
Hi @Ed Davis

I am trying to understand how you are parsing in Eval and I start around Expect, a couple of lines then goto by Sub or Function someplace else, a couple of lines, then someplace else... and this isn't spaghetti code but the effect on following it for understanding seems the same.

I am naming the opposite of spaghetti code,  shattered code, so refactored, so splintered and broken up... it's a nightmare to follow.

Not saying it's a bad thing, in fact I am wondering if it is some sign of being better for computers and efficiencies even if human understanding is made difficult.

But I am not familiar with the variables yet, it's like watching for first time a sitcom or soap opera that has been going for years.

It is based on this technique:  https://www.engr.mun.ca/~theo/Misc/exp_parsing.htm - specifically Precedence Climbing.  Recursive Descent, Precedence Climbing, Shunting Yard, and Pratt Parsing basically all do the same thing, just expressed differently.  Of all of those, Precedence Climbing is the most understandable to me, so that is why I use it.

Here (updated this morning) is the same general algorithm, boiled down to just the bare essentials - a little over 100 lines of code, not counting comments.  Hopefully, it is much easier to follow.  And after reading the above article, it will make sense.  Or maybe look at this before, and then read the article :)

Code: QB64: [Select]
  1. 'Simple Eval function
  2. '
  3. 'Compiles with QB64 and FreeBasic (-lang qb).
  4. '
  5. 'Accepts */+-^ and parenthesis.
  6. '
  7. 'Precedence:
  8. '   unary +,-
  9. '   *, /
  10. '   +, -
  11. '
  12. 'Example:
  13. '
  14. 'a$ = "1+2*3+(5-1)"
  15. 'print eval#(a$)
  16. '
  17. 'Written by Ed Davis.  Contact: ed_davis2 at that yahoo place.
  18. 'Use at your own risk.
  19. '
  20. option _explicit ' drop the "_" for FreeBasic
  21.  
  22.  
  23. dim shared userstr as string, sym as string
  24.  
  25.     line input "Enter expression:", userstr
  26.     if userstr = "" then exit do
  27.     print eval#
  28.  
  29. ' lexical analyzer functions
  30.  
  31. function isdigit%(ch as string)
  32.     isdigit% = left$(ch, 1) >= "0" and left$(ch, 1) <= "9"
  33.  
  34. function isnumeric%(ch as string)
  35.     isnumeric% = isdigit(ch) or left$(ch, 1) = "."
  36.  
  37. sub takechar
  38.     sym = sym + left$(userstr, 1)
  39.     userstr = right$(userstr, len(userstr) - 1)
  40.  
  41. sub nextsym
  42.     sym = "": userstr = ltrim$(userstr)
  43.     call takechar
  44.     select case sym
  45.         case "(", ")", "+", "-", "*", "/"  'all set
  46.         case "0" to "9"
  47.             while isdigit%(userstr)
  48.                 call takechar
  49.             wend
  50.             if left$(userstr, 1) = "." then
  51.                 call takechar
  52.  
  53.                 while isdigit%(userstr)
  54.                     call takechar
  55.                 wend
  56.             end if
  57.         case "."
  58.             while isdigit%(userstr)
  59.                 call takechar
  60.             wend
  61.         case ""
  62.         case else
  63.             print "unrecognized character:", sym
  64.             sym = ""
  65.     end select
  66.  
  67. ' Main expression parsing routine
  68.     dim n as double, n2 as double, op as string, q as integer, prec as integer
  69.  
  70.     ' handle numeric operands - numbers and unary operators
  71.     prec = 0: if sym = "+" or sym = "-" then prec = 3
  72.     if prec > 0 then
  73.         op = sym: call nextsym
  74.         select case op          ' unary operators
  75.             case "-" : n = -expr#(prec)
  76.             case "+" : n =  expr#(prec)
  77.         end select
  78.     elseif sym = "(" then
  79.         call nextsym: n = expr#(0)
  80.         if sym <> ")" then
  81.             print "expecting ')'"
  82.         else
  83.             call nextsym
  84.         end if
  85.     elseif isnumeric%(sym) then
  86.         n = val(sym): call nextsym
  87.     else
  88.         print "syntax error: expecting a primary, found:", sym
  89.     end if
  90.  
  91.     ' binary operators
  92.     do  ' while binary operator and precedence of sym >= p
  93.         select case sym
  94.             case "+", "-" : prec = 1
  95.             case "*", "/" : prec = 2
  96.             case else :     prec = 0 ' not a binary operator
  97.         end select
  98.  
  99.         if prec = 0 or prec < p then exit do
  100.  
  101.         op = sym: call nextsym: q = prec + 1
  102.  
  103.         n2 = expr#(q)
  104.         select case op
  105.             case "*" : n = n * n2
  106.             case "/" : n = n / n2
  107.             case "+" : n = n + n2
  108.             case "-" : n = n - n2
  109.             case else: print "syntax error: expecting a binary operator, found:", sym
  110.         end select
  111.     loop
  112.  
  113.     expr# = n
  114.  
  115. function eval#
  116.     call nextsym
  117.     eval# = expr#(0)
  118.     if sym <> "" then print "error: extra input found: "; sym; userstr
« Last Edit: March 02, 2021, 07:28:50 am by Ed Davis »

Offline Aurel

  • Forum Regular
  • Posts: 167
    • View Profile
Re: Numeric/String Eval function
« Reply #16 on: March 02, 2021, 01:20:32 am »
Yes Ed like Precedence Climbing but i like Recursive Descent. because i understand that one better
but yes all of them doing the same thing ...
@Ed ..program work fine as usual !!!
« Last Edit: March 02, 2021, 01:34:33 am by Aurel »
//////////////////////////////////////////////////////////////////
https://aurelsoft.ucoz.com
https://www.facebook.com/groups/470369984111370
//////////////////////////////////////////////////////////////////

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Numeric/String Eval function
« Reply #17 on: March 02, 2021, 12:38:42 pm »
@Ed Davis  Oh you've updated this morning, I just had a revelation myself this morning.
https://www.qb64.org/forum/index.php?topic=2308.msg130620#msg130620