Data update
This commit is contained in:
parent
5150844a7d
commit
4bb20c9b71
7735 changed files with 38060 additions and 199180 deletions
|
|
@ -1,8 +1,8 @@
|
|||
/*
|
||||
hand coded recursive descent parser
|
||||
expr : term ( ( PLUS | MINUS ) term )* ;
|
||||
term : factor ( ( MULT | DIV ) factor )* ;
|
||||
factor : NUMBER | '(' expr ')';
|
||||
expr : term ( ( PLUS | MINUS ) term )* ;
|
||||
term : factor ( ( MULT | DIV ) factor )* ;
|
||||
factor : NUMBER | '(' expr ')';
|
||||
*/
|
||||
|
||||
calcLexer := makeCalcLexer()
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
(def precedence '{* 0, / 0
|
||||
+ 1, - 1})
|
||||
+ 1, - 1})
|
||||
|
||||
(defn order-ops
|
||||
"((A x B) y C) or (A x (B y C)) depending on precedence of x and y"
|
||||
[[A x B y C & more]]
|
||||
(let [ret (if (<= (precedence x)
|
||||
(precedence y))
|
||||
(list (list A x B) y C)
|
||||
(list A x (list B y C)))]
|
||||
(precedence y))
|
||||
(list (list A x B) y C)
|
||||
(list A x (list B y C)))]
|
||||
(if more
|
||||
(recur (concat ret more))
|
||||
ret)))
|
||||
|
|
@ -18,10 +18,10 @@
|
|||
(clojure.walk/postwalk
|
||||
#(if (seq? %)
|
||||
(let [c (count %)]
|
||||
(cond (even? c) (throw (Exception. "Must be an odd number of forms"))
|
||||
(= c 1) (first %)
|
||||
(= c 3) %
|
||||
(>= c 5) (order-ops %)))
|
||||
(cond (even? c) (throw (Exception. "Must be an odd number of forms"))
|
||||
(= c 1) (first %)
|
||||
(= c 3) %
|
||||
(>= c 5) (order-ops %)))
|
||||
%)
|
||||
s))
|
||||
|
||||
|
|
@ -34,16 +34,16 @@
|
|||
add-parens))
|
||||
|
||||
(def ops {'* *
|
||||
'+ +
|
||||
'- -
|
||||
'/ /})
|
||||
'+ +
|
||||
'- -
|
||||
'/ /})
|
||||
|
||||
(def eval-ast
|
||||
(partial clojure.walk/postwalk
|
||||
#(if (seq? %)
|
||||
(let [[a o b] %]
|
||||
((ops o) a b))
|
||||
%)))
|
||||
#(if (seq? %)
|
||||
(let [[a o b] %]
|
||||
((ops o) a b))
|
||||
%)))
|
||||
|
||||
(defn evaluate [s]
|
||||
"Parse and evaluate an infix arithmetic expression"
|
||||
|
|
|
|||
|
|
@ -322,7 +322,7 @@ class Parser
|
|||
}
|
||||
}
|
||||
|
||||
public program()
|
||||
public Program()
|
||||
{
|
||||
var text := new StringWriter();
|
||||
var parser := new Parser();
|
||||
|
|
@ -331,7 +331,7 @@ public program()
|
|||
{
|
||||
try
|
||||
{
|
||||
Console.printLine("=",parser.run(text))
|
||||
Console.printLine("=",parser.run(text as:string))
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,93 +0,0 @@
|
|||
#!/usr/bin/env emacs --script
|
||||
;; -*- mode: emacs-lisp; lexical-binding: t -*-
|
||||
;;> ./arithmetic-evaluation '(1 + 2) * 3'
|
||||
|
||||
(defun advance ()
|
||||
(let ((rtn (buffer-substring-no-properties (point) (match-end 0))))
|
||||
(goto-char (match-end 0))
|
||||
rtn))
|
||||
|
||||
(defvar current-symbol nil)
|
||||
|
||||
(defun next-symbol ()
|
||||
(when (looking-at "[ \t\n]+")
|
||||
(goto-char (match-end 0)))
|
||||
|
||||
(cond
|
||||
((eobp)
|
||||
(setq current-symbol 'eof))
|
||||
((looking-at "[0-9]+")
|
||||
(setq current-symbol (string-to-number (advance))))
|
||||
((looking-at "[-+*/()]")
|
||||
(setq current-symbol (advance)))
|
||||
((looking-at ".")
|
||||
(error "Unknown character '%s'" (advance)))))
|
||||
|
||||
(defun accept (sym)
|
||||
(when (equal sym current-symbol)
|
||||
(next-symbol)
|
||||
t))
|
||||
|
||||
(defun expect (sym)
|
||||
(unless (accept sym)
|
||||
(error "Expected symbol %s, but found %s" sym current-symbol))
|
||||
t)
|
||||
|
||||
(defun p-expression ()
|
||||
" expression = term { ('+' | '-') term } . "
|
||||
(let ((rtn (p-term)))
|
||||
(while (or (equal current-symbol "+") (equal current-symbol "-"))
|
||||
(let ((op current-symbol)
|
||||
(left rtn))
|
||||
(next-symbol)
|
||||
(setq rtn (list op left (p-term)))))
|
||||
rtn))
|
||||
|
||||
(defun p-term ()
|
||||
" term = factor { ('*' | '/') factor } . "
|
||||
(let ((rtn (p-factor)))
|
||||
(while (or (equal current-symbol "*") (equal current-symbol "/"))
|
||||
(let ((op current-symbol)
|
||||
(left rtn))
|
||||
(next-symbol)
|
||||
(setq rtn (list op left (p-factor)))))
|
||||
rtn))
|
||||
|
||||
(defun p-factor ()
|
||||
" factor = constant | variable | '(' expression ')' . "
|
||||
(let (rtn)
|
||||
(cond
|
||||
((numberp current-symbol)
|
||||
(setq rtn current-symbol)
|
||||
(next-symbol))
|
||||
((accept "(")
|
||||
(setq rtn (p-expression))
|
||||
(expect ")"))
|
||||
(t (error "Syntax error")))
|
||||
rtn))
|
||||
|
||||
(defun ast-build (expression)
|
||||
(let (rtn)
|
||||
(with-temp-buffer
|
||||
(insert expression)
|
||||
(goto-char (point-min))
|
||||
(next-symbol)
|
||||
(setq rtn (p-expression))
|
||||
(expect 'eof))
|
||||
rtn))
|
||||
|
||||
(defun ast-eval (v)
|
||||
(pcase v
|
||||
((pred numberp) v)
|
||||
(`("+" ,a ,b) (+ (ast-eval a) (ast-eval b)))
|
||||
(`("-" ,a ,b) (- (ast-eval a) (ast-eval b)))
|
||||
(`("*" ,a ,b) (* (ast-eval a) (ast-eval b)))
|
||||
(`("/" ,a ,b) (/ (ast-eval a) (float (ast-eval b))))
|
||||
(_ (error "Unknown value %s" v))))
|
||||
|
||||
(dolist (arg command-line-args-left)
|
||||
(let ((ast (ast-build arg)))
|
||||
(princ (format " ast = %s\n" ast))
|
||||
(princ (format " value = %s\n" (ast-eval ast)))
|
||||
(terpri)))
|
||||
(setq command-line-args-left nil)
|
||||
|
|
@ -10,7 +10,7 @@ def eval:
|
|||
elif .[-2] == "+" then $v + .[-1]
|
||||
elif .[-2] == "-" then $v - .[-1]
|
||||
else tostring|error
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else .
|
||||
|
|
|
|||
|
|
@ -19,20 +19,20 @@ function eval(expr)
|
|||
|
||||
--arithmetic functions
|
||||
tb = {["+"] = function(a,b) return eval(a) + eval(b) end,
|
||||
["-"] = function(a,b) return eval(a) - eval(b) end,
|
||||
["*"] = function(a,b) return eval(a) * eval(b) end,
|
||||
["/"] = function(a,b) return eval(a) / eval(b) end}
|
||||
["-"] = function(a,b) return eval(a) - eval(b) end,
|
||||
["*"] = function(a,b) return eval(a) * eval(b) end,
|
||||
["/"] = function(a,b) return eval(a) / eval(b) end}
|
||||
|
||||
--you could add ^ or other operators to this pretty easily
|
||||
for i, v in ipairs{"*/", "+-"} do
|
||||
for s, u in ipairs(expr) do
|
||||
local k = type(u) == "string" and C(S(v)):match(u)
|
||||
if k then
|
||||
expr[s-1] = tb[k](expr[s-1],expr[s+1])
|
||||
table.remove(expr, s)
|
||||
table.remove(expr, s)
|
||||
end
|
||||
end
|
||||
local k = type(u) == "string" and C(S(v)):match(u)
|
||||
if k then
|
||||
expr[s-1] = tb[k](expr[s-1],expr[s+1])
|
||||
table.remove(expr, s)
|
||||
table.remove(expr, s)
|
||||
end
|
||||
end
|
||||
end
|
||||
return expr[1]
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,85 +1,85 @@
|
|||
Module CheckAst {
|
||||
class EvalAst {
|
||||
private:
|
||||
Function Ast(&in$) {
|
||||
object Ast=stack, op=stack
|
||||
Do
|
||||
stack Ast {stack .Ast1(&in$)}
|
||||
in$=Trim$(in$)
|
||||
oper$=left$(in$,1)
|
||||
if Instr("+-", oper$)>0 else exit
|
||||
if len(oper$)>0 then stack op {push oper$}
|
||||
in$=Mid$(in$, 2)
|
||||
until len(in$)=0
|
||||
stack Ast {stack op} // dump op to end of stack Ast
|
||||
=Ast
|
||||
}
|
||||
Function Ast1(&in$) {
|
||||
object Ast=stack, op=stack
|
||||
Do
|
||||
stack Ast {stack .Ast2(&in$)}
|
||||
in$=Trim$(in$)
|
||||
oper$=left$(in$,1)
|
||||
if Instr("*/", oper$)>0 else exit
|
||||
if len(oper$)>0 then stack op {push oper$}
|
||||
in$=Mid$(in$, 2)
|
||||
until len(in$)=0
|
||||
stack Ast {stack op}
|
||||
=Ast
|
||||
}
|
||||
Function Ast2(&in$) {
|
||||
in$=Trim$(in$)
|
||||
if Asc(in$)<>40 then =.GetNumber(&in$) : exit
|
||||
in$=Mid$(in$, 2)
|
||||
=.Ast(&in$)
|
||||
in$=Mid$(in$, 2)
|
||||
}
|
||||
Function GetNumber (&in$) {
|
||||
Def ch$, num$
|
||||
Do
|
||||
ch$=left$(in$,1)
|
||||
if instr("0123456789", ch$)>0 else exit
|
||||
num$+=ch$
|
||||
in$=Mid$(in$, 2)
|
||||
until len(in$)=0
|
||||
=stack:=val(num$)
|
||||
}
|
||||
public:
|
||||
value () {
|
||||
=.Ast(![])
|
||||
}
|
||||
}
|
||||
Ast=EvalAst()
|
||||
Expr$ = "1+2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10"
|
||||
// Expr$="1/2+(4-3)/2+1/2"
|
||||
print "Result through eval$:";eval(Expr$)
|
||||
print "Expr :";Expr$
|
||||
mres=Ast(&Expr$)
|
||||
print "RPN :";array(stack(mres))#str$()
|
||||
reg=stack
|
||||
stack mres {
|
||||
while not empty
|
||||
if islet then
|
||||
read op$
|
||||
stack reg {
|
||||
select case op$
|
||||
case "+"
|
||||
push number+number
|
||||
case "-"
|
||||
shift 2:push number-number
|
||||
case "*"
|
||||
push number*number
|
||||
case "/"
|
||||
shift 2:push number/number // shif 2 swap top 2 values
|
||||
end select
|
||||
}
|
||||
else
|
||||
read v
|
||||
stack reg {push v}
|
||||
end if
|
||||
end while
|
||||
}
|
||||
if len(reg)<>1 then Error "Wrong Evaluation"
|
||||
print "Result :";stackitem(reg)
|
||||
class EvalAst {
|
||||
private:
|
||||
Function Ast(&in$) {
|
||||
object Ast=stack, op=stack
|
||||
Do
|
||||
stack Ast {stack .Ast1(&in$)}
|
||||
in$=Trim$(in$)
|
||||
oper$=left$(in$,1)
|
||||
if Instr("+-", oper$)>0 else exit
|
||||
if len(oper$)>0 then stack op {push oper$}
|
||||
in$=Mid$(in$, 2)
|
||||
until len(in$)=0
|
||||
stack Ast {stack op} // dump op to end of stack Ast
|
||||
=Ast
|
||||
}
|
||||
Function Ast1(&in$) {
|
||||
object Ast=stack, op=stack
|
||||
Do
|
||||
stack Ast {stack .Ast2(&in$)}
|
||||
in$=Trim$(in$)
|
||||
oper$=left$(in$,1)
|
||||
if Instr("*/", oper$)>0 else exit
|
||||
if len(oper$)>0 then stack op {push oper$}
|
||||
in$=Mid$(in$, 2)
|
||||
until len(in$)=0
|
||||
stack Ast {stack op}
|
||||
=Ast
|
||||
}
|
||||
Function Ast2(&in$) {
|
||||
in$=Trim$(in$)
|
||||
if Asc(in$)<>40 then =.GetNumber(&in$) : exit
|
||||
in$=Mid$(in$, 2)
|
||||
=.Ast(&in$)
|
||||
in$=Mid$(in$, 2)
|
||||
}
|
||||
Function GetNumber (&in$) {
|
||||
Def ch$, num$
|
||||
Do
|
||||
ch$=left$(in$,1)
|
||||
if instr("0123456789", ch$)>0 else exit
|
||||
num$+=ch$
|
||||
in$=Mid$(in$, 2)
|
||||
until len(in$)=0
|
||||
=stack:=val(num$)
|
||||
}
|
||||
public:
|
||||
value () {
|
||||
=.Ast(![])
|
||||
}
|
||||
}
|
||||
Ast=EvalAst()
|
||||
Expr$ = "1+2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10"
|
||||
// Expr$="1/2+(4-3)/2+1/2"
|
||||
print "Result through eval$:";eval(Expr$)
|
||||
print "Expr :";Expr$
|
||||
mres=Ast(&Expr$)
|
||||
print "RPN :";array(stack(mres))#str$()
|
||||
reg=stack
|
||||
stack mres {
|
||||
while not empty
|
||||
if islet then
|
||||
read op$
|
||||
stack reg {
|
||||
select case op$
|
||||
case "+"
|
||||
push number+number
|
||||
case "-"
|
||||
shift 2:push number-number
|
||||
case "*"
|
||||
push number*number
|
||||
case "/"
|
||||
shift 2:push number/number // shif 2 swap top 2 values
|
||||
end select
|
||||
}
|
||||
else
|
||||
read v
|
||||
stack reg {push v}
|
||||
end if
|
||||
end while
|
||||
}
|
||||
if len(reg)<>1 then Error "Wrong Evaluation"
|
||||
print "Result :";stackitem(reg)
|
||||
}
|
||||
CheckAst
|
||||
|
|
|
|||
|
|
@ -3,60 +3,60 @@ Expr.eval = 0
|
|||
|
||||
BinaryExpr = new Expr
|
||||
BinaryExpr.eval = function()
|
||||
if self.op == "+" then return self.lhs.eval + self.rhs.eval
|
||||
if self.op == "-" then return self.lhs.eval - self.rhs.eval
|
||||
if self.op == "*" then return self.lhs.eval * self.rhs.eval
|
||||
if self.op == "/" then return self.lhs.eval / self.rhs.eval
|
||||
if self.op == "+" then return self.lhs.eval + self.rhs.eval
|
||||
if self.op == "-" then return self.lhs.eval - self.rhs.eval
|
||||
if self.op == "*" then return self.lhs.eval * self.rhs.eval
|
||||
if self.op == "/" then return self.lhs.eval / self.rhs.eval
|
||||
end function
|
||||
binop = function(lhs, op, rhs)
|
||||
e = new BinaryExpr
|
||||
e.lhs = lhs
|
||||
e.op = op
|
||||
e.rhs = rhs
|
||||
return e
|
||||
e = new BinaryExpr
|
||||
e.lhs = lhs
|
||||
e.op = op
|
||||
e.rhs = rhs
|
||||
return e
|
||||
end function
|
||||
|
||||
parseAtom = function(inp)
|
||||
tok = inp.pull
|
||||
if tok >= "0" and tok <= "9" then
|
||||
e = new Expr
|
||||
e.eval = val(tok)
|
||||
while inp and inp[0] >= "0" and inp[0] <= "9"
|
||||
e.eval = e.eval * 10 + val(inp.pull)
|
||||
end while
|
||||
else if tok == "(" then
|
||||
e = parseAddSub(inp)
|
||||
inp.pull // swallow closing ")"
|
||||
return e
|
||||
else
|
||||
print "Unexpected token: " + tok
|
||||
exit
|
||||
end if
|
||||
return e
|
||||
tok = inp.pull
|
||||
if tok >= "0" and tok <= "9" then
|
||||
e = new Expr
|
||||
e.eval = val(tok)
|
||||
while inp and inp[0] >= "0" and inp[0] <= "9"
|
||||
e.eval = e.eval * 10 + val(inp.pull)
|
||||
end while
|
||||
else if tok == "(" then
|
||||
e = parseAddSub(inp)
|
||||
inp.pull // swallow closing ")"
|
||||
return e
|
||||
else
|
||||
print "Unexpected token: " + tok
|
||||
exit
|
||||
end if
|
||||
return e
|
||||
end function
|
||||
|
||||
parseMultDiv = function(inp)
|
||||
next = @parseAtom
|
||||
e = next(inp)
|
||||
while inp and (inp[0] == "*" or inp[0] == "/")
|
||||
e = binop(e, inp.pull, next(inp))
|
||||
end while
|
||||
return e
|
||||
next = @parseAtom
|
||||
e = next(inp)
|
||||
while inp and (inp[0] == "*" or inp[0] == "/")
|
||||
e = binop(e, inp.pull, next(inp))
|
||||
end while
|
||||
return e
|
||||
end function
|
||||
|
||||
parseAddSub = function(inp)
|
||||
next = @parseMultDiv
|
||||
e = next(inp)
|
||||
while inp and (inp[0] == "+" or inp[0] == "-")
|
||||
e = binop(e, inp.pull, next(inp))
|
||||
end while
|
||||
return e
|
||||
next = @parseMultDiv
|
||||
e = next(inp)
|
||||
while inp and (inp[0] == "+" or inp[0] == "-")
|
||||
e = binop(e, inp.pull, next(inp))
|
||||
end while
|
||||
return e
|
||||
end function
|
||||
|
||||
while true
|
||||
s = input("Enter expression: ").replace(" ","")
|
||||
if not s then break
|
||||
inp = split(s, "")
|
||||
ast = parseAddSub(inp)
|
||||
print ast.eval
|
||||
s = input("Enter expression: ").replace(" ","")
|
||||
if not s then break
|
||||
inp = split(s, "")
|
||||
ast = parseAddSub(inp)
|
||||
print ast.eval
|
||||
end while
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class Yaccer(object):
|
|||
def o2( self, operchar ):
|
||||
# Operator character or open paren in state1
|
||||
def openParen(a,b):
|
||||
return 0 # function should not be called
|
||||
return 0 # function should not be called
|
||||
|
||||
opDict= { '+': ( operator.add, 2, 2 ),
|
||||
'-': (operator.sub, 2, 2 ),
|
||||
|
|
@ -56,7 +56,7 @@ class Yaccer(object):
|
|||
# reduce node until matching open paren found
|
||||
self.redeuce( 1 )
|
||||
if len(self.operstak)>0:
|
||||
self.operstak.pop() # pop off open parenthesis
|
||||
self.operstak.pop() # pop off open parenthesis
|
||||
else:
|
||||
print 'Error - no open parenthesis matches close parens.'
|
||||
self.__dict__.update(self.state2)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
Red [ "Arithmetic Evaluator - Hinjo, August 2025"
|
||||
{Using a Modified Shunting-Yard algorithm to produce S-Expression as the AST
|
||||
and a simple S-Expression evaluator (recursive).}
|
||||
Red [
|
||||
Title: "Arithmetic Evaluation"
|
||||
Author: "hinjolicious"
|
||||
Date: "August 2025"
|
||||
Purpose: {
|
||||
Using a Modified Shunting-Yard algorithm to produce S-Expression as the AST
|
||||
and a simple S-Expression evaluator (recursive).
|
||||
}
|
||||
]
|
||||
|
||||
s-expr: function [expr [string!] /trace] [
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
(* AST *)
|
||||
datatype expression =
|
||||
Con of int (* constant *)
|
||||
| Add of expression * expression (* addition *)
|
||||
| Mul of expression * expression (* multiplication *)
|
||||
| Sub of expression * expression (* subtraction *)
|
||||
| Div of expression * expression (* division *)
|
||||
Con of int (* constant *)
|
||||
| Add of expression * expression (* addition *)
|
||||
| Mul of expression * expression (* multiplication *)
|
||||
| Sub of expression * expression (* subtraction *)
|
||||
| Div of expression * expression (* division *)
|
||||
|
||||
(* Evaluator *)
|
||||
fun eval (Con x) = x
|
||||
|
|
@ -15,13 +15,13 @@ fun eval (Con x) = x
|
|||
|
||||
(* Lexer *)
|
||||
datatype token =
|
||||
CON of int
|
||||
| ADD
|
||||
| MUL
|
||||
| SUB
|
||||
| DIV
|
||||
| LPAR
|
||||
| RPAR
|
||||
CON of int
|
||||
| ADD
|
||||
| MUL
|
||||
| SUB
|
||||
| DIV
|
||||
| LPAR
|
||||
| RPAR
|
||||
|
||||
fun lex nil = nil
|
||||
| lex (#"+" :: cs) = ADD :: lex cs
|
||||
|
|
@ -43,7 +43,7 @@ exception Error of string
|
|||
|
||||
fun match (a,ts) t = if null ts orelse hd ts <> t
|
||||
then raise Error "match"
|
||||
else (a, tl ts)
|
||||
else (a, tl ts)
|
||||
|
||||
fun extend (a,ts) p f = let val (a',tr) = p ts in (f(a,a'), tr) end
|
||||
|
||||
|
|
@ -64,6 +64,6 @@ and parseP (CON c :: ts) = (Con c, ts)
|
|||
|
||||
(* Test *)
|
||||
fun lex_parse_eval (str:string) =
|
||||
case parseE (lex (explode str)) of
|
||||
(exp, nil) => eval exp
|
||||
| _ => raise Error "not parseable stuff at the end"
|
||||
case parseE (lex (explode str)) of
|
||||
(exp, nil) => eval exp
|
||||
| _ => raise Error "not parseable stuff at the end"
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ proc s {args} {
|
|||
if [regexp {[()]} $args] {
|
||||
eval s [string map {( "\[s " ) \]} $args]
|
||||
} elseif {"*" in $args} {
|
||||
s [s_group $args *]
|
||||
s [s_group $args *]
|
||||
} elseif {"/" in $args} {
|
||||
s [s_group $args /]
|
||||
s [s_group $args /]
|
||||
} elseif {"+" in $args} {
|
||||
s [s_group $args +]
|
||||
} elseif {"-" in $args} {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue