September Morn Update

This commit is contained in:
Ingy döt Net 2019-09-12 10:33:56 -07:00
parent 4e2d22a71d
commit aac6731f2c
6856 changed files with 141342 additions and 21127 deletions

View file

@ -1,324 +1,343 @@
import system'routines.
import extensions.
import extensions'text.
import system'routines;
import extensions;
import extensions'text;
class Token
{
object theValue.
object theValue;
int rprop level :: theLevel.
rprop int Level;
constructor new(int aLevel)
[
theValue := StringWriter new.
theLevel := aLevel + 9.
]
constructor new(int level)
{
theValue := new StringWriter();
Level := level + 9;
}
append : aChar
[
theValue << aChar.
]
append(ch)
{
theValue.write(ch)
}
number = theValue toReal.
Number = theValue.toReal();
}
class Node
{
object prop left :: theLeft.
object prop right :: theRight.
int rprop level :: theLevel.
prop object Left;
prop object Right;
rprop int Level;
constructor new(int aLevel)
[
theLevel := aLevel.
]
constructor new(int level)
{
Level := level
}
}
class SummaryNode :: Node
class SummaryNode : Node
{
constructor new(int aLevel)
<= new(aLevel + 1).
constructor new(int level)
<= new(level + 1);
number = theLeft number + theRight number.
Number = Left.Number + Right.Number;
}
class DifferenceNode :: Node
class DifferenceNode : Node
{
constructor new(int aLevel)
<= new(aLevel + 1).
constructor new(int level)
<= new(level + 1);
number = theLeft number - theRight number.
Number = Left.Number - Right.Number;
}
class ProductNode :: Node
class ProductNode : Node
{
constructor new(int aLevel)
<= new(aLevel + 2).
constructor new(int level)
<= new(level + 2);
number = theLeft number * theRight number.
Number = Left.Number * Right.Number;
}
class FractionNode :: Node
class FractionNode : Node
{
constructor new(int aLevel)
<= new(aLevel + 2).
constructor new(int level)
<= new(level + 2);
number = theLeft number / theRight number.
Number = Left.Number / Right.Number;
}
class Expression
{
int rprop level :: theLevel.
object prop top :: theTop.
rprop int Level;
prop object Top;
constructor new(int aLevel)
[
theLevel := aLevel
]
constructor new(int level)
{
Level := level
}
right = theTop.
prop object Right
{
get() = Top;
set right:aNode [ theTop := aNode ]
set(object node)
{
Top := node
}
}
number => theTop.
get Number() => Top;
}
singleton operatorState
{
eval(ch)
[
{
ch =>
$40 [ // (
^ target newBracket; gotoStarting
];
! [
^ target newToken; append:ch; gotoToken
].
]
$40 { // (
^ __target.newBracket().gotoStarting()
}
: {
^ __target.newToken().append(ch).gotoToken()
}
}
}
singleton tokenState
{
eval(ch)
[
{
ch =>
$41 [ // )
^ target closeBracket; gotoToken
];
$42 [ // *
^ target newProduct; gotoOperator
];
$43 [ // +
^ target newSummary; gotoOperator
];
$45 [ // -
^ target newDifference; gotoOperator
];
$47 [ // /
^ target newFraction; gotoOperator
];
! [
^ target append:ch
].
]
$41 { // )
^ __target.closeBracket().gotoToken()
}
$42 { // *
^ __target.newProduct().gotoOperator()
}
$43 { // +
^ __target.newSummary().gotoOperator()
}
$45 { // -
^ __target.newDifference().gotoOperator()
}
$47 { // /
^ __target.newFraction().gotoOperator()
}
: {
^ __target.append:ch
}
}
}
singleton startState
{
eval(ch)
[
{
ch =>
$40 [ // (
^ target newBracket; gotoStarting
];
$45 [ // -
^ target newToken; append:"0"; newDifference; gotoOperator
];
! [
^ target newToken; append:ch; gotoToken
].
]
$40 { // (
^ __target.newBracket().gotoStarting()
}
$45 { // -
^ __target.newToken().append("0").newDifference().gotoOperator()
}
: {
^ __target.newToken().append:ch.gotoToken()
}
}
}
class Scope
{
object theState.
int theLevel.
object theParser.
object theToken.
object theExpression.
object theState;
int theLevel;
object theParser;
object theToken;
object theExpression;
constructor new:aParser
[
theState := startState.
theLevel := 0.
theExpression := Expression new(0).
theParser := aParser.
]
constructor new(parser)
{
theState := startState;
theLevel := 0;
theExpression := Expression.new(0);
theParser := parser
}
newToken
[
theToken := theParser appendToken(theExpression, theLevel).
]
newToken()
{
theToken := theParser.appendToken(theExpression, theLevel)
}
newSummary
[
theToken := nil.
newSummary()
{
theToken := nil;
theParser appendSummary(theExpression, theLevel).
]
theParser.appendSummary(theExpression, theLevel)
}
newDifference
[
theToken := nil.
newDifference()
{
theToken := nil;
theParser appendDifference(theExpression, theLevel)
]
theParser.appendDifference(theExpression, theLevel)
}
newProduct
[
theToken := nil.
newProduct()
{
theToken := nil;
theParser appendProduct(theExpression, theLevel)
]
theParser.appendProduct(theExpression, theLevel)
}
newFraction
[
theToken := nil.
newFraction()
{
theToken := nil;
theParser appendFraction(theExpression, theLevel)
]
theParser.appendFraction(theExpression, theLevel)
}
newBracket
[
theToken := nil.
newBracket()
{
theToken := nil;
theLevel := theLevel + 10.
theLevel := theLevel + 10;
theParser appendSubexpression(theExpression, theLevel).
]
theParser.appendSubexpression(theExpression, theLevel)
}
closeBracket
[
closeBracket()
{
if (theLevel < 10)
[ InvalidArgumentException new:"Invalid expression"; raise ].
{ InvalidArgumentException.new:"Invalid expression".raise() };
theLevel := theLevel - 10
]
}
append:ch
[
if((ch >= $48) && (ch < $58))
[ theToken append:ch ];
[ InvalidArgumentException new:"Invalid expression"; raise ]
]
append(ch)
{
if(ch >= $48 && ch < $58)
{
theToken.append:ch
}
else
{
InvalidArgumentException.new:"Invalid expression".raise()
}
}
append(literal aLiteral)
[
aLiteral forEach(:ch)[ self append:ch ]
]
append(string s)
{
s.forEach:(ch){ self.append:ch }
}
gotoStarting
[
gotoStarting()
{
theState := startState
]
}
gotoToken
[
gotoToken()
{
theState := tokenState
]
}
gotoOperator
[
gotoOperator()
{
theState := operatorState
]
}
number => theExpression.
get Number() => theExpression;
dispatch => theState.
dispatch() => theState;
}
class Parser
{
appendToken(object anExpression, int aLevel)
[
var aToken := Token new(aLevel).
appendToken(object expression, int level)
{
var token := Token.new(level);
anExpression top := self append(anExpression top, aToken).
expression.Top := self.append(expression.Top, token);
^ aToken
]
^ token
}
appendSummary(object anExpression, int aLevel)
[
anExpression top := self append(anExpression top, SummaryNode new(aLevel)).
]
appendSummary(object expression, int level)
{
expression.Top := self.append(expression.Top, SummaryNode.new(level))
}
appendDifference(object anExpression, int aLevel)
[
anExpression top := self append(anExpression top, DifferenceNode new(aLevel)).
]
appendDifference(object expression, int level)
{
expression.Top := self.append(expression.Top, DifferenceNode.new(level))
}
appendProduct(object anExpression, int aLevel)
[
anExpression top := self append(anExpression top, ProductNode new(aLevel)).
]
appendProduct(object expression, int level)
{
expression.Top := self.append(expression.Top, ProductNode.new(level))
}
appendFraction(object anExpression, int aLevel)
[
anExpression top := self append(anExpression top, FractionNode new(aLevel))
]
appendFraction(object expression, int level)
{
expression.Top := self.append(expression.Top, FractionNode.new(level))
}
appendSubexpression(object anExpression, int aLevel)
[
anExpression top := self append(anExpression top, Expression new(aLevel)).
]
appendSubexpression(object expression, int level)
{
expression.Top := self.append(expression.Top, Expression.new(level))
}
append(object aLastNode, object aNewNode)
[
if(nil == aLastNode)
[ ^ aNewNode ].
append(object lastNode, object newNode)
{
if(nil == lastNode)
{ ^ newNode };
if (aNewNode level <= aLastNode level)
[ aNewNode left := aLastNode. ^ aNewNode ].
if (newNode.Level <= lastNode.Level)
{ newNode.Left := lastNode; ^ newNode };
var aParent := aLastNode.
var aCurrent := aLastNode right.
while ((nil != aCurrent) && (aNewNode level > aCurrent level))
[ aParent := aCurrent. aCurrent := aCurrent right. ].
var parent := lastNode;
var current := lastNode.Right;
while (nil != current && newNode.Level > current.Level)
{ parent := current; current := current.Right };
if (nil == aCurrent)
[ aParent right := aNewNode. ];
[ aNewNode left := aCurrent. aParent right := aNewNode ].
if (nil == current)
{
parent.Right := newNode
}
else
{
newNode.Left := current; parent.Right := newNode
};
^ aLastNode
]
^ lastNode
}
run : aText
[
var aScope := Scope new(self).
run(text)
{
var scope := Scope.new(self);
aText forEach(:ch)[ aScope eval:ch ].
text.forEach:(ch){ scope.eval:ch };
^ aScope number
]
^ scope.Number
}
}
public program
[
var aText := StringWriter new.
var aParser := Parser new.
public program()
{
var text := new StringWriter();
var parser := new Parser();
$(console readLine; saveTo:aText; length > 0) doWhile:
[
try(console printLine("=",aParser run:aText))
while (console.readLine().saveTo(text).Length > 0)
{
try
{
on(Exception e)
[
console writeLine:"Invalid Expression"
]
}.
console.printLine("=",parser.run:text)
}
catch(Exception e)
{
console.writeLine(e.Printable)
aText clear
]
]
//console.writeLine:"Invalid Expression"
};
text.clear()
}
}

View file

@ -0,0 +1,151 @@
import strutils
import os
#--
# Lexer
#--
type
TokenKind = enum
tokNumber
tokPlus = "+", tokMinus = "-", tokStar = "*", tokSlash = "/"
tokLPar, tokRPar
tokEnd
Token = object
case kind: TokenKind
of tokNumber: value: float
else: discard
proc lex(input: string): seq[Token] =
# Here we go through the entire input string and collect all the tokens into
# a sequence.
var pos = 0
while pos < input.len:
case input[pos]
of '0'..'9':
# Digits consist of three parts: the integer part, the delimiting decimal
# point, and the decimal part.
var numStr = ""
while pos < input.len and input[pos] in Digits:
numStr.add(input[pos])
inc(pos)
if pos < input.len and input[pos] == '.':
numStr.add('.')
inc(pos)
while pos < input.len and input[pos] in Digits:
numStr.add(input[pos])
inc(pos)
result.add(Token(kind: tokNumber, value: numStr.parseFloat()))
of '+': inc(pos); result.add(Token(kind: tokPlus))
of '-': inc(pos); result.add(Token(kind: tokMinus))
of '*': inc(pos); result.add(Token(kind: tokStar))
of '/': inc(pos); result.add(Token(kind: tokSlash))
of '(': inc(pos); result.add(Token(kind: tokLPar))
of ')': inc(pos); result.add(Token(kind: tokRPar))
of ' ': inc(pos)
else: raise newException(ArithmeticError,
"Unexpected character '" & input[pos] & '\'')
# We append an 'end' token to the end of our token sequence, to mark where the
# sequence ends.
result.add(Token(kind: tokEnd))
#--
# Parser
#--
type
ExprKind = enum
exprNumber
exprBinary
Expr = ref object
case kind: ExprKind
of exprNumber: value: float
of exprBinary:
left, right: Expr
operator: TokenKind
proc `$`(ex: Expr): string =
# This proc returns a lisp representation of the expression.
case ex.kind
of exprNumber: $ex.value
of exprBinary: '(' & $ex.operator & ' ' & $ex.left & ' ' & $ex.right & ')'
var
# The input to the program is provided via command line parameters.
tokens = lex(commandLineParams().join(" "))
pos = 0
# This table stores the precedence level of each infix operator. For tokens
# this does not apply to, the precedence is set to 0.
const Precedence: array[low(TokenKind)..high(TokenKind), int] = [
tokNumber: 0,
tokPlus: 1,
tokMinus: 1,
tokStar: 2,
tokSlash: 2,
tokLPar: 0,
tokRPar: 0,
tokEnd: 0
]
# We use a Pratt parser, so the two primary components are the prefix part, and
# the infix part. We start with a prefix token, and when we're done, we continue
# with an infix token.
proc parse(prec = 0): Expr
proc parseNumber(token: Token): Expr =
result = Expr(kind: exprNumber, value: token.value)
proc parseParen(token: Token): Expr =
result = parse()
if tokens[pos].kind != tokRPar:
raise newException(ArithmeticError, "Unbalanced parenthesis")
inc(pos)
proc parseBinary(left: Expr, token: Token): Expr =
result = Expr(kind: exprBinary, left: left, right: parse(),
operator: token.kind)
proc parsePrefix(token: Token): Expr =
case token.kind
of tokNumber: result = parseNumber(token)
of tokLPar: result = parseParen(token)
else: discard
proc parseInfix(left: Expr, token: Token): Expr =
case token.kind
of tokPlus, tokMinus, tokStar, tokSlash: result = parseBinary(left, token)
else: discard
proc parse(prec = 0): Expr =
# This procedure is the heart of a Pratt parser, it puts the whole expression
# together into one abstract syntax tree, properly dealing with precedence.
var token = tokens[pos]
inc(pos)
result = parsePrefix(token)
while prec < Precedence[tokens[pos].kind]:
token = tokens[pos]
if token.kind == tokEnd:
# When we hit the end token, we're done.
break
inc(pos)
result = parseInfix(result, token)
let ast = parse()
proc `==`(ex: Expr): float =
# This proc recursively evaluates the given expression.
result =
case ex.kind
of exprNumber: ex.value
of exprBinary:
case ex.operator
of tokPlus: ==ex.left + ==ex.right
of tokMinus: ==ex.left - ==ex.right
of tokStar: ==ex.left * ==ex.right
of tokSlash: ==ex.left / ==ex.right
else: 0.0
# In the end, we print out the result.
echo ==ast

View file

@ -1,6 +1,7 @@
#lang racket
(require parser-tools/yacc parser-tools/lex
(require parser-tools/yacc
parser-tools/lex
(prefix-in ~ parser-tools/lex-sre))
(define-tokens value-tokens (NUM))
@ -30,6 +31,6 @@
(define (calc str)
(define i (open-input-string str))
(displayln (parse (λ() (lex i)))))
(displayln (parse (λ () (lex i)))))
(calc "(1 + 2 * 3) - (1+2)*-3")

View file

@ -0,0 +1,172 @@
//! Simple calculator parser and evaluator
/// Binary operator
#[derive(Debug)]
pub enum Operator {
Add,
Substract,
Multiply,
Divide
}
/// A node in the tree
#[derive(Debug)]
pub enum Node {
Value(f64),
SubNode(Box<Node>),
Binary(Operator, Box<Node>,Box<Node>),
}
/// parse a string into a node
pub fn parse(txt :&str) -> Option<Node> {
let chars = txt.chars().filter(|c| *c != ' ').collect();
parse_expression(&chars, 0).map(|(_,n)| n)
}
/// parse an expression into a node, keeping track of the position in the character vector
fn parse_expression(chars: &Vec<char>, pos: usize) -> Option<(usize,Node)> {
match parse_start(chars, pos) {
Some((new_pos, first)) => {
match parse_operator(chars, new_pos) {
Some((new_pos2,op)) => {
if let Some((new_pos3, second)) = parse_expression(chars, new_pos2) {
Some((new_pos3, combine(op, first, second)))
} else {
None
}
},
None => Some((new_pos,first)),
}
},
None => None,
}
}
/// combine nodes to respect associativity rules
fn combine(op: Operator, first: Node, second: Node) -> Node {
match second {
Node::Binary(op2,v21,v22) => if precedence(&op)>=precedence(&op2) {
Node::Binary(op2,Box::new(combine(op,first,*v21)),v22)
} else {
Node::Binary(op,Box::new(first),Box::new(Node::Binary(op2,v21,v22)))
},
_ => Node::Binary(op,Box::new(first),Box::new(second)),
}
}
/// a precedence rank for operators
fn precedence(op: &Operator) -> usize {
match op{
Operator::Multiply | Operator::Divide => 2,
_ => 1
}
}
/// try to parse from the start of an expression (either a parenthesis or a value)
fn parse_start(chars: &Vec<char>, pos: usize) -> Option<(usize,Node)> {
match start_parenthesis(chars, pos){
Some (new_pos) => {
let r = parse_expression(chars, new_pos);
end_parenthesis(chars, r)
},
None => parse_value(chars, pos),
}
}
/// match a starting parentheseis
fn start_parenthesis(chars: &Vec<char>, pos: usize) -> Option<usize>{
if pos<chars.len() && chars[pos] == '(' {
Some(pos+1)
} else {
None
}
}
/// match an end parenthesis, if successful will create a sub node contained the wrapped expression
fn end_parenthesis(chars: &Vec<char>, wrapped :Option<(usize,Node)>) -> Option<(usize,Node)>{
match wrapped {
Some((pos, node)) => if pos<chars.len() && chars[pos] == ')' {
Some((pos+1,Node::SubNode(Box::new(node))))
} else {
None
},
None => None,
}
}
/// parse a value: an decimal with an optional minus sign
fn parse_value(chars: &Vec<char>, pos: usize) -> Option<(usize,Node)>{
let mut new_pos = pos;
if new_pos<chars.len() && chars[new_pos] == '-' {
new_pos = new_pos+1;
}
while new_pos<chars.len() && (chars[new_pos]=='.' || (chars[new_pos] >= '0' && chars[new_pos] <= '9')) {
new_pos = new_pos+1;
}
if new_pos>pos {
if let Ok(v) = dbg!(chars[pos..new_pos].iter().collect::<String>()).parse() {
Some((new_pos,Node::Value(v)))
} else {
None
}
} else {
None
}
}
/// parse an operator
fn parse_operator(chars: &Vec<char>, pos: usize) -> Option<(usize,Operator)> {
if pos<chars.len() {
let ops_with_char = vec!(('+',Operator::Add),('-',Operator::Substract),('*',Operator::Multiply),('/',Operator::Divide));
for (ch,op) in ops_with_char {
if chars[pos] == ch {
return Some((pos+1, op));
}
}
}
None
}
/// eval a string
pub fn eval(txt :&str) -> f64 {
match parse(txt) {
Some(t) => eval_term(&t),
None => panic!("Cannot parse {}",txt),
}
}
/// eval a term, recursively
fn eval_term(t: &Node) -> f64 {
match t {
Node::Value(v) => *v,
Node::SubNode(t) => eval_term(t),
Node::Binary(Operator::Add,t1,t2) => eval_term(t1) + eval_term(t2),
Node::Binary(Operator::Substract,t1,t2) => eval_term(t1) - eval_term(t2),
Node::Binary(Operator::Multiply,t1,t2) => eval_term(t1) * eval_term(t2),
Node::Binary(Operator::Divide,t1,t2) => eval_term(t1) / eval_term(t2),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_eval(){
assert_eq!(2.0,eval("2"));
assert_eq!(4.0,eval("2+2"));
assert_eq!(11.0/4.0, eval("2+3/4"));
assert_eq!(2.0, eval("2*3-4"));
assert_eq!(3.0, eval("1+2*3-4"));
assert_eq!(89.0/6.0, eval("2*(3+4)+5/6"));
assert_eq!(14.0, eval("2 * (3 -1) + 2 * 5"));
assert_eq!(7000.0, eval("2 * (3 + (4 * 5 + (6 * 7) * 8) - 9) * 10"));
assert_eq!(-9.0/4.0, eval("2*-3--4+-.25"));
assert_eq!(1.5, eval("1 - 5 * 2 / 20 + 1"));
assert_eq!(3.5, eval("2 * (3 + ((5) / (7 - 11)))"));
}
}