Add tasks for all the new languages

This commit is contained in:
Tina Müller 2016-12-05 23:44:36 +01:00
parent 9dc3c2bb62
commit bba7bfd280
13208 changed files with 134745 additions and 0 deletions

View file

@ -0,0 +1,233 @@
PROGRAM EVAL
!
! arithmetic expression evaluator
!
!$KEY
LABEL 98,100,110
DIM STACK$[50]
PROCEDURE DISEGNA_STACK
!$RCODE="LOCATE 3,1"
!$RCODE="COLOR 0,7"
PRINT(TAB(35);"S T A C K";TAB(79);)
!$RCODE="COLOR 7,0"
FOR TT=1 TO 38 DO
IF TT>=20 THEN
!$RCODE="LOCATE 3+TT-19,40"
ELSE
!$RCODE="LOCATE 3+TT,1"
END IF
IF TT=NS THEN PRINT(">";) ELSE PRINT(" ";) END IF
PRINT(RIGHT$(STR$(TT),2);"³ ";STACK$[TT];" ")
END FOR
REPEAT
GET(Z$)
UNTIL LEN(Z$)<>0
END PROCEDURE
PROCEDURE COMPATTA_STACK
IF NS>1 THEN
R=1
WHILE R<NS DO
IF INSTR(OP_LIST$,STACK$[R])=0 AND INSTR(OP_LIST$,STACK$[R+1])=0 THEN
FOR R1=R TO NS-1 DO
STACK$[R1]=STACK$[R1+1]
END FOR
NS=NS-1
END IF
R=R+1
END WHILE
END IF
DISEGNA_STACK
END PROCEDURE
PROCEDURE CALC_ARITM
L=NS1
WHILE L<=NS2 DO
IF STACK$[L]="^" THEN
IF L>=NS2 THEN GOTO 100 END IF
N1#=VAL(STACK$[L-1]) N2#=VAL(STACK$[L+1]) NOP=NOP-1
IF STACK$[L]="^" THEN
RI#=N1#^N2#
END IF
STACK$[L-1]=STR$(RI#)
N=L
WHILE N<=NS2-2 DO
STACK$[N]=STACK$[N+2]
N=N+1
END WHILE
NS2=NS2-2
L=NS1-1
END IF
L=L+1
END WHILE
L=NS1
WHILE L<=NS2 DO
IF STACK$[L]="*" OR STACK$[L]="/" THEN
IF L>=NS2 THEN GOTO 100 END IF
N1#=VAL(STACK$[L-1]) N2#=VAL(STACK$[L+1]) NOP=NOP-1
IF STACK$[L]="*" THEN RI#=N1#*N2# ELSE RI#=N1#/N2# END IF
STACK$[L-1]=STR$(RI#)
N=L
WHILE N<=NS2-2 DO
STACK$[N]=STACK$[N+2]
N=N+1
END WHILE
NS2=NS2-2
L=NS1-1
END IF
L=L+1
END WHILE
L=NS1
WHILE L<=NS2 DO
IF STACK$[L]="+" OR STACK$[L]="-" THEN
EXIT IF L>=NS2
N1#=VAL(STACK$[L-1]) N2#=VAL(STACK$[L+1]) NOP=NOP-1
IF STACK$[L]="+" THEN RI#=N1#+N2# ELSE RI#=N1#-N2# END IF
STACK$[L-1]=STR$(RI#)
N=L
WHILE N<=NS2-2 DO
STACK$[N]=STACK$[N+2]
N=N+1
END WHILE
NS2=NS2-2
L=NS1-1
END IF
L=L+1
END WHILE
100:
IF NOP<2 THEN ! operator priority
DB#=VAL(STACK$[NS1])
ELSE
IF NOP<3 THEN
DB#=VAL(STACK$[NS1+2])
ELSE
DB#=VAL(STACK$[NS1+4])
END IF
END IF
END PROCEDURE
PROCEDURE SVOLGI_PAR
NPA=NPA-1
FOR J=NS TO 1 STEP -1 DO
EXIT IF STACK$[J]="("
END FOR
IF J=0 THEN
NS1=1 NS2=NS CALC_ARITM
NERR=7
ELSE
FOR R=J TO NS-1 DO
STACK$[R]=STACK$[R+1]
END FOR
NS1=J NS2=NS-1 CALC_ARITM
IF NS1=2 THEN NS1=1 STACK$[1]=STACK$[2] END IF
NS=NS1
COMPATTA_STACK
END IF
END PROCEDURE
BEGIN
OP_LIST$="+-*/^("
NOP=0 NPA=0 NS=1 K$=""
STACK$[1]="@" ! init stack
PRINT(CHR$(12);)
INPUT(LINE,EXPRESSION$)
FOR W=1 TO LEN(EXPRESSION$) DO
LOOP
CODE=ASC(MID$(EXPRESSION$,W,1))
IF (CODE>=48 AND CODE<=57) OR CODE=46 THEN
K$=K$+CHR$(CODE)
W=W+1 IF W>LEN(EXPRESSION$) THEN GOTO 98 END IF
ELSE
EXIT IF K$=""
IF NS>1 OR (NS=1 AND STACK$[1]<>"@") THEN NS=NS+1 END IF
IF FLAG=0 THEN STACK$[NS]=K$ ELSE STACK$[NS]=STR$(VAL(K$)*FLAG) END IF
K$="" FLAG=0
EXIT
END IF
END LOOP
IF CODE=43 THEN K$="+" END IF
IF CODE=45 THEN K$="-" END IF
IF CODE=42 THEN K$="*" END IF
IF CODE=47 THEN K$="/" END IF
IF CODE=94 THEN K$="^" END IF
CASE CODE OF
43,45,42,47,94->
IF MID$(EXPRESSION$,W+1,1)="-" THEN FLAG=-1 W=W+1 END IF
IF INSTR(OP_LIST$,STACK$[NS])<>0 THEN
NERR=5
ELSE
NS=NS+1 STACK$[NS]=K$ NOP=NOP+1
IF NOP>=2 THEN
FOR J=NS TO 1 STEP -1 DO
IF STACK$[J]<>"(" THEN
CONTINUE FOR
END IF
IF J<NS-2 THEN
EXIT
ELSE
GOTO 110
END IF
END FOR
NS1=J+1 NS2=NS CALC_ARITM
NS=NS2 STACK$[NS]=K$
REGISTRO_X#=VAL(STACK$[NS-1])
END IF
END IF
110:
END ->
40->
IF NS>1 OR (NS=1 AND STACK$[1]<>"@") THEN NS=NS+1 END IF
STACK$[NS]="(" NPA=NPA+1
IF MID$(EXPRESSION$,W+1,1)="-" THEN FLAG=-1 W=W+1 END IF
END ->
41->
SVOLGI_PAR
IF NERR=7 THEN
NERR=0 NOP=0 NPA=0 NS=1
ELSE
IF NERR=0 OR NERR=1 THEN
DB#=VAL(STACK$[NS])
REGISTRO_X#=DB#
ELSE
NOP=0 NPA=0 NS=1
END IF
END IF
END ->
OTHERWISE
NERR=8
END CASE
K$=""
DISEGNA_STACK
END FOR
98:
IF K$<>"" THEN
IF NS>1 OR (NS=1 AND STACK$[1]<>"@") THEN NS=NS+1 END IF
IF FLAG=0 THEN STACK$[NS]=K$ ELSE STACK$[NS]=STR$(VAL(K$)*FLAG) END IF
END IF
DISEGNA_STACK
IF INSTR(OP_LIST$,STACK$[NS])<>0 THEN
NERR=6
ELSE
WHILE NPA<>0 DO
SVOLGI_PAR
END WHILE
IF NERR<>7 THEN NS1=1 NS2=NS CALC_ARITM END IF
END IF
NS=1 NOP=0 NPA=0
!$RCODE="LOCATE 23,1"
IF NERR>0 THEN PRINT("Internal Error #";NERR) ELSE PRINT("Value is ";DB#) END IF
END PROGRAM

View file

@ -0,0 +1,195 @@
'Arithmetic evaluation
'
'Create a program which parses and evaluates arithmetic expressions.
'
'Requirements
'
' * An abstract-syntax tree (AST) for the expression must be created from parsing the
' input.
' * The AST must be used in evaluation, also, so the input may not be directly evaluated
' (e.g. by calling eval or a similar language feature.)
' * The expression will be a string or list of symbols like "(1+3)*7".
' * The four symbols + - * / must be supported as binary operators with conventional
' precedence rules.
' * Precedence-control parentheses must also be supported.
'
'Standard mathematical precedence should be followed:
'
' Parentheses
' Multiplication/Division (left to right)
' Addition/Subtraction (left to right)
'
' test cases:
' 2*-3--4+-0.25 : returns -2.25
' 1 + 2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10 : returns 71
enum
false = 0
true = -1
end enum
enum Symbol
unknown_sym
minus_sym
plus_sym
lparen_sym
rparen_sym
number_sym
mul_sym
div_sym
unary_minus_sym
unary_plus_sym
done_sym
eof_sym
end enum
type Tree
as Tree ptr leftp, rightp
op as Symbol
value as double
end type
dim shared sym as Symbol
dim shared tokenval as double
dim shared usr_input as string
declare function expr(byval p as integer) as Tree ptr
function isdigit(byval ch as string) as long
return ch <> "" and Asc(ch) >= Asc("0") and Asc(ch) <= Asc("9")
end function
sub error_msg(byval msg as string)
print msg
system
end sub
' tokenize the input string
sub getsym()
do
if usr_input = "" then
line input usr_input
usr_input += chr(10)
endif
dim as string ch = mid(usr_input, 1, 1) ' get the next char
usr_input = mid(usr_input, 2) ' remove it from input
sym = unknown_sym
select case ch
case " ": continue do
case chr(10), "": sym = done_sym: return
case "+": sym = plus_sym: return
case "-": sym = minus_sym: return
case "*": sym = mul_sym: return
case "/": sym = div_sym: return
case "(": sym = lparen_sym: return
case ")": sym = rparen_sym: return
case else
if isdigit(ch) then
dim s as string = ""
dim dot as integer = 0
do
s += ch
if ch = "." then dot += 1
ch = mid(usr_input, 1, 1) ' get the next char
usr_input = mid(usr_input, 2) ' remove it from input
loop while isdigit(ch) orelse ch = "."
if ch = "." or dot > 1 then error_msg("bogus number")
usr_input = ch + usr_input ' prepend the char to input
tokenval = val(s)
sym = number_sym
end if
return
end select
loop
end sub
function make_node(byval op as Symbol, byval leftp as Tree ptr, byval rightp as Tree ptr) as Tree ptr
dim t as Tree ptr
t = callocate(len(Tree))
t->op = op
t->leftp = leftp
t->rightp = rightp
return t
end function
function is_binary(byval op as Symbol) as integer
select case op
case mul_sym, div_sym, plus_sym, minus_sym: return true
case else: return false
end select
end function
function prec(byval op as Symbol) as integer
select case op
case unary_minus_sym, unary_plus_sym: return 100
case mul_sym, div_sym: return 90
case plus_sym, minus_sym: return 80
case else: return 0
end select
end function
function primary as Tree ptr
dim t as Tree ptr = 0
select case sym
case minus_sym, plus_sym
dim op as Symbol = sym
getsym()
t = expr(prec(unary_minus_sym))
if op = minus_sym then return make_node(unary_minus_sym, t, 0)
if op = plus_sym then return make_node(unary_plus_sym, t, 0)
case lparen_sym
getsym()
t = expr(0)
if sym <> rparen_sym then error_msg("expecting rparen")
getsym()
return t
case number_sym
t = make_node(sym, 0, 0)
t->value = tokenval
getsym()
return t
case else: error_msg("expecting a primary")
end select
end function
function expr(byval p as integer) as Tree ptr
dim t as Tree ptr = primary()
while is_binary(sym) andalso prec(sym) >= p
dim t1 as Tree ptr
dim op as Symbol = sym
getsym()
t1 = expr(prec(op) + 1)
t = make_node(op, t, t1)
wend
return t
end function
function eval(byval t as Tree ptr) as double
if t <> 0 then
select case t->op
case minus_sym: return eval(t->leftp) - eval(t->rightp)
case plus_sym: return eval(t->leftp) + eval(t->rightp)
case mul_sym: return eval(t->leftp) * eval(t->rightp)
case div_sym: return eval(t->leftp) / eval(t->rightp)
case unary_minus_sym: return -eval(t->leftp)
case unary_plus_sym: return eval(t->leftp)
case number_sym: return t->value
case else: error_msg("unexpected tree node")
end select
end if
return 0
end function
do
getsym()
if sym = eof_sym then exit do
if sym = done_sym then continue do
dim t as Tree ptr = expr(0)
print"> "; eval(t)
if sym = eof_sym then exit do
if sym <> done_sym then error_msg("unexpected input")
loop

View file

@ -0,0 +1,218 @@
sequence opstack = {} -- atom elements are literals,
-- sequence elements are subexpressions
-- on completion length(opstack) should be 1
object token
constant op_p_p = 0 -- 1: expressions stored as op,p1,p2
-- p_op_p -- 0: expressions stored as p1,op,p2
-- p_p_op -- -1: expressions stored as p1,p2,op
object op = 0 -- 0 if none, else "+", "-", "*", "/", "^", "%", or "u-"
string s -- the expression being parsed
integer ch
integer sidx
procedure err(string msg)
printf(1,"%s\n%s^ %s\n\nPressEnter...",{s,repeat(' ',sidx-1),msg})
{} = wait_key()
abort(0)
end procedure
procedure nxtch(object msg="eof")
sidx += 1
if sidx>length(s) then
if string(msg) then err(msg) end if
ch = -1
else
ch = s[sidx]
end if
end procedure
procedure skipspaces()
while find(ch," \t\r\n")!=0 do nxtch(0) end while
end procedure
procedure get_token()
atom n, fraction
integer dec
skipspaces()
if ch=-1 then token = "eof" return end if
if ch>='0' and ch<='9' then
n = ch-'0'
while 1 do
nxtch(0)
if ch<'0' or ch>'9' then exit end if
n = n*10+ch-'0'
end while
if ch='.' then
dec = 1
fraction = 0
while 1 do
nxtch(0)
if ch<'0' or ch>'9' then exit end if
fraction = fraction*10 + ch-'0'
dec *= 10
end while
n += fraction/dec
end if
-- if find(ch,"eE") then -- you get the idea
-- end if
token = n
return
end if
if find(ch,"+-/*()^%")=0 then err("syntax error") end if
token = s[sidx..sidx]
nxtch(0)
return
end procedure
procedure Match(string t)
if token!=t then err(t&" expected") end if
get_token()
end procedure
procedure PopFactor()
object p2 = opstack[$]
if op="u-" then
if op_p_p=1 then -- op_p_p
opstack[$] = {op,0,p2}
elsif op_p_p=0 then -- p_op_p
opstack[$] = {0,op,p2}
else -- -1 -- p_p_op
opstack[$] = {0,p2,op}
end if
else
opstack = opstack[1..$-1]
if op_p_p=1 then -- op_p_p
opstack[$] = {op,opstack[$],p2}
elsif op_p_p=0 then -- p_op_p
opstack[$] = {opstack[$],op,p2}
else -- -1 -- p_p_op
opstack[$] = {opstack[$],p2,op}
end if
end if
op = 0
end procedure
procedure PushFactor(atom t)
if op!=0 then PopFactor() end if
opstack = append(opstack,t)
end procedure
procedure PushOp(string t)
if op!=0 then PopFactor() end if
op = t
end procedure
procedure Factor()
if atom(token) then
PushFactor(token)
if ch!=-1 then
get_token()
end if
elsif token="-" then
get_token()
-- Factor()
Expr(3) -- makes "-3^2" yield -9 (ie -(3^2)) not 9 (ie (-3)^2).
if op!=0 then PopFactor() end if
if integer(opstack[$]) then
opstack[$] = -opstack[$]
else
PushOp("u-")
end if
elsif token="(" then
get_token()
Expr(0)
Match(")")
elsif token="+" then -- (ignore)
nxtch()
Factor()
else
err("syntax error")
end if
end procedure
constant {operators,
precedence,
associativity} = columnize({{"^",3,0},
{"%",2,1},
{"*",2,1},
{"/",2,1},
{"+",1,1},
{"-",1,1},
$})
procedure Expr(integer p)
--
-- Parse an expression, using precedence climbing.
--
-- p is the precedence level we should parse to, eg/ie
-- 4: Factor only (may as well just call Factor)
-- 3: "" and ^
-- 2: "" and *,/,%
-- 1: "" and +,-
-- 0: full expression (effectively the same as 1)
-- obviously, parentheses override any setting of p.
--
integer k, thisp
Factor()
while 1 do
k = find(token,operators) -- *,/,+,-
if k=0 then exit end if
thisp = precedence[k]
if thisp<p then exit end if
get_token()
Expr(thisp+associativity[k])
PushOp(operators[k])
end while
end procedure
function eval(object s)
object lhs, rhs
string op
if atom(s) then
return s
end if
if op_p_p=1 then -- op_p_p
{op,lhs,rhs} = s
elsif op_p_p=0 then -- p_op_p
{lhs,op,rhs} = s
else -- -1 -- p_p_op
{lhs,rhs,op} = s
end if
if sequence(lhs) then lhs = eval(lhs) end if
if sequence(rhs) then rhs = eval(rhs) end if
if op="+" then
return lhs+rhs
elsif op="-" then
return lhs-rhs
elsif op="*" then
return lhs*rhs
elsif op="/" then
return lhs/rhs
elsif op="^" then
return power(lhs,rhs)
elsif op="%" then
return remainder(lhs,rhs)
elsif op="u-" then
return -rhs
else
?9/0
end if
end function
s = "3+4+5+6*7/1*5^2^3"
sidx = 0
nxtch()
get_token()
Expr(0)
if op!=0 then PopFactor() end if
if length(opstack)!=1 then err("some error") end if
puts(1,"AST (flat): ")
?opstack[1]
puts(1,"AST (tree):\n")
ppEx(opstack[1],{pp_Nest,6})
puts(1,"result: ")
?eval(opstack[1])
{} = wait_key()

View file

@ -0,0 +1,56 @@
func evalArithmeticExp(s) {
func evalExp(s) {
func operate(s, op) {
s.split(op).map{|c| c.to_num }.reduce(op);
}
func add(s) {
operate(s.sub(/^\+/,'').sub(/\++/,'+'), '+');
}
func subtract(s) {
s.gsub!(/(\+-|-\+)/,'-');
if (s ~~ /--/) {
return(add(s.sub(/--/,'+')));
}
var b = s.split('-');
b.len == 3 ? (-1*b[1].to_num - b[2].to_num)
: operate(s, '-');
}
s.gsub!(/[()]/,'').gsub!(/-\+/, '-');
var reM = /\*/;
var reMD = %r"(\d+\.?\d*\s*[*/]\s*[+-]?\d+\.?\d*)";
var reA = /\d\+/;
var reAS = /(-?\d+\.?\d*\s*[+-]\s*[+-]?\d+\.?\d*)/;
while (var match = reMD.match(s)) {
match[0] ~~ reM
? s.sub!(reMD, operate(match[0], '*').to_s)
: s.sub!(reMD, operate(match[0], '/').to_s);
}
while (var match = reAS.match(s)) {
match[0] ~~ reA
? s.sub!(reAS, add(match[0]).to_s)
: s.sub!(reAS, subtract(match[0]).to_s);
}
return s;
}
var rePara = /(\([^\(\)]*\))/;
s.split!.join!('').sub!(/^\+/,'');
while (var match = s.match(rePara)) {
s.sub!(rePara, evalExp(match[0]));
}
return evalExp(s).to_num;
}

View file

@ -0,0 +1,13 @@
for expr,res in [
['2+3' => 5],
['-4-3' => -7],
['-+2+3/4' => -1.25],
['2*3-4' => 2],
['2*(3+4)+2/4' => 2/4 + 14],
['2*-3--4+-0.25' => -2.25],
['2 * (3 + (4 * 5 + (6 * 7) * 8) - 9) * 10' => 7000],
] { 
var num = evalArithmeticExp(expr);
assert_eq(num, res);
"%-45s == %10g\n".printf(expr, num);
}