Create simple calc as test draft
This commit is contained in:
@@ -93,22 +93,50 @@ class Parser:
|
||||
|
||||
# leftAssociative -> left | left OP right
|
||||
@staticmethod
|
||||
def leftAssociativeOperatorParser(leftParser, operatorTokenType, rightParser, createNode):
|
||||
def leftAssociativeOperatorParser(leftParser, operatorTokenTypes, rightParser, createNode):
|
||||
from smnp.ast.node.operator import OperatorNode
|
||||
|
||||
def parse(input):
|
||||
operatorParser = Parser.oneOfTerminals(*operatorTokenTypes, createNode=lambda val, pos: OperatorNode.withChildren([val], pos))
|
||||
left = leftParser(input)
|
||||
if left.result:
|
||||
operator = Parser.terminalParser(operatorTokenType, lambda val, pos: OperatorNode.withChildren([val], pos))(input)
|
||||
operator = operatorParser(input)
|
||||
while operator.result:
|
||||
right = rightParser(input)
|
||||
left = ParseResult.OK(createNode(left.node, operator.node, right.node))
|
||||
operator = Parser.terminalParser(operatorTokenType, lambda val, pos: OperatorNode.withChildren([val], pos))(input)
|
||||
operator = operatorParser(input)
|
||||
return left
|
||||
|
||||
return ParseResult.FAIL()
|
||||
|
||||
return parse
|
||||
|
||||
@staticmethod
|
||||
def oneOfTerminals(*tokenTypes, createNode=None):
|
||||
return Parser.oneOf(*[ Parser.terminalParser(expectedType, createNode=createNode) for expectedType in tokenTypes ])
|
||||
|
||||
# leftAssociative -> left OP right | right
|
||||
@staticmethod
|
||||
def leftAssociativeOperatorOrRightParser(leftParser, operatorTokenType, rightParser, createNode):
|
||||
from smnp.ast.node.operator import OperatorNode
|
||||
def parse(input):
|
||||
left = leftParser(input)
|
||||
oneAtLeast = False
|
||||
if left.result:
|
||||
operator = Parser.terminalParser(operatorTokenType, lambda val, pos: OperatorNode.withChildren([val], pos))(input)
|
||||
while operator.result:
|
||||
oneAtLeast = True
|
||||
right = rightParser(input)
|
||||
left = ParseResult.OK(createNode(left.node, operator.node, right.node))
|
||||
operator = Parser.terminalParser(operatorTokenType, lambda val, pos: OperatorNode.withChildren([val], pos))(input)
|
||||
|
||||
if oneAtLeast:
|
||||
return left
|
||||
|
||||
return ParseResult.FAIL()
|
||||
|
||||
return Parser.oneOf(parse, rightParser)
|
||||
|
||||
# loop -> start item* end
|
||||
@staticmethod
|
||||
def loop(startParser, itemParser, endParser, createNode):
|
||||
@@ -154,6 +182,10 @@ class Parser:
|
||||
|
||||
return parse
|
||||
|
||||
@staticmethod
|
||||
def epsilon():
|
||||
return lambda *args: ParseResult.OK(NoneNode())
|
||||
|
||||
@staticmethod
|
||||
def many(parser, createNode):
|
||||
def parse(input):
|
||||
|
||||
66
smnp/calc.py
Normal file
66
smnp/calc.py
Normal file
@@ -0,0 +1,66 @@
|
||||
from smnp.ast.node.model import Node
|
||||
from smnp.ast.parser import Parser
|
||||
from smnp.token.tokenizer import tokenize
|
||||
from smnp.token.type import TokenType
|
||||
|
||||
|
||||
class Atom(Node):
|
||||
def __init__(self, value, pos):
|
||||
super().__init__(pos)
|
||||
self.children = [value]
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
return self[0]
|
||||
|
||||
class Operation(Node):
|
||||
def __init__(self, left, op, right, pos):
|
||||
super().__init__(pos)
|
||||
self.children = [left, op, right]
|
||||
|
||||
@property
|
||||
def left(self):
|
||||
return self[0]
|
||||
|
||||
@property
|
||||
def operator(self):
|
||||
return self[1]
|
||||
|
||||
@property
|
||||
def right(self):
|
||||
return self[2]
|
||||
|
||||
def atom(input):
|
||||
return Parser.terminalParser(TokenType.INTEGER, lambda val, pos: Atom(val, pos))(input)
|
||||
|
||||
def chain(input):
|
||||
return Parser.leftAssociativeOperatorParser(atom, [TokenType.DOT], atom, lambda left, op, right: Operation(left, op, right, op.pos))(input)
|
||||
|
||||
def factor(input):
|
||||
return Parser.leftAssociativeOperatorParser(chain, [TokenType.DOUBLE_ASTERISK], chain, lambda left, op, right: Operation(left, op, right, op.pos))(input)
|
||||
|
||||
def term(input):
|
||||
return Parser.leftAssociativeOperatorParser(factor, [TokenType.ASTERISK, TokenType.SLASH], factor, lambda left, op, right: Operation(left, op, right, op.pos))(input)
|
||||
|
||||
def expr(input):
|
||||
return Parser.leftAssociativeOperatorParser(term, [TokenType.PLUS, TokenType.MINUS], term, lambda left, op, right: Operation(left, op, right, op.pos))(input)
|
||||
|
||||
def evaluate(node):
|
||||
if type(node) == Atom:
|
||||
return node.value
|
||||
lhs = evaluate(node.left)
|
||||
rhs = evaluate(node.right)
|
||||
return {
|
||||
"+": int(lhs) + int(rhs),
|
||||
"*": int(lhs) * int(rhs),
|
||||
"-": int(lhs) - int(rhs),
|
||||
"/": int(lhs) / int(rhs),
|
||||
"**": int(lhs) ** int(rhs)
|
||||
}[node.operator.value]
|
||||
|
||||
def draft():
|
||||
|
||||
tokens = tokenize(['2 + 2 * 2 / 2'])
|
||||
node = expr(tokens).node
|
||||
node.print()
|
||||
print(evaluate(node))
|
||||
10
smnp/main.py
10
smnp/main.py
@@ -1,14 +1,12 @@
|
||||
import sys
|
||||
|
||||
from smnp.calc import draft
|
||||
from smnp.error.base import SmnpException
|
||||
from smnp.library.loader import loadStandardLibrary
|
||||
from smnp.program.interpreter import Interpreter
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
stdLibraryEnv = loadStandardLibrary()
|
||||
Interpreter.interpretFile(sys.argv[1], printTokens=False, printAst=True, execute=False, baseEnvironment=stdLibraryEnv)
|
||||
#stdLibraryEnv = loadStandardLibrary()
|
||||
#Interpreter.interpretFile(sys.argv[1], printTokens=False, printAst=True, execute=False, baseEnvironment=stdLibraryEnv)
|
||||
draft()
|
||||
|
||||
except SmnpException as e:
|
||||
print(e.message())
|
||||
|
||||
@@ -20,11 +20,14 @@ tokenizers = (
|
||||
defaultTokenizer(TokenType.CLOSE_SQUARE),
|
||||
defaultTokenizer(TokenType.OPEN_ANGLE),
|
||||
defaultTokenizer(TokenType.CLOSE_ANGLE),
|
||||
defaultTokenizer(TokenType.DOUBLE_ASTERISK),
|
||||
defaultTokenizer(TokenType.ASTERISK),
|
||||
defaultTokenizer(TokenType.ASSIGN),
|
||||
defaultTokenizer(TokenType.ARROW),
|
||||
defaultTokenizer(TokenType.COMMA),
|
||||
defaultTokenizer(TokenType.SLASH),
|
||||
defaultTokenizer(TokenType.MINUS),
|
||||
defaultTokenizer(TokenType.PLUS),
|
||||
defaultTokenizer(TokenType.DOTS),
|
||||
defaultTokenizer(TokenType.AMP),
|
||||
defaultTokenizer(TokenType.DOT),
|
||||
|
||||
@@ -2,6 +2,7 @@ from enum import Enum
|
||||
|
||||
|
||||
class TokenType(Enum):
|
||||
DOUBLE_ASTERISK = '**'
|
||||
OPEN_CURLY = '{'
|
||||
CLOSE_CURLY = '}'
|
||||
OPEN_PAREN = '('
|
||||
@@ -14,7 +15,9 @@ class TokenType(Enum):
|
||||
ASSIGN = '='
|
||||
ARROW = '->'
|
||||
COMMA = ','
|
||||
SLASH = '/'
|
||||
MINUS = '-'
|
||||
PLUS = '+'
|
||||
DOTS = '...'
|
||||
AMP = '&'
|
||||
DOT = '.'
|
||||
|
||||
Reference in New Issue
Block a user