Create simple calc as test draft

This commit is contained in:
Bartłomiej Pluta
2019-07-10 20:14:05 +02:00
parent 76eabbff0e
commit aefa8e8f3c
5 changed files with 111 additions and 9 deletions

View File

@@ -93,22 +93,50 @@ class Parser:
# leftAssociative -> left | left OP right # leftAssociative -> left | left OP right
@staticmethod @staticmethod
def leftAssociativeOperatorParser(leftParser, operatorTokenType, rightParser, createNode): def leftAssociativeOperatorParser(leftParser, operatorTokenTypes, rightParser, createNode):
from smnp.ast.node.operator import OperatorNode from smnp.ast.node.operator import OperatorNode
def parse(input): def parse(input):
operatorParser = Parser.oneOfTerminals(*operatorTokenTypes, createNode=lambda val, pos: OperatorNode.withChildren([val], pos))
left = leftParser(input) left = leftParser(input)
if left.result: if left.result:
operator = Parser.terminalParser(operatorTokenType, lambda val, pos: OperatorNode.withChildren([val], pos))(input) operator = operatorParser(input)
while operator.result: while operator.result:
right = rightParser(input) right = rightParser(input)
left = ParseResult.OK(createNode(left.node, operator.node, right.node)) 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 left
return ParseResult.FAIL() return ParseResult.FAIL()
return parse 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 # loop -> start item* end
@staticmethod @staticmethod
def loop(startParser, itemParser, endParser, createNode): def loop(startParser, itemParser, endParser, createNode):
@@ -154,6 +182,10 @@ class Parser:
return parse return parse
@staticmethod
def epsilon():
return lambda *args: ParseResult.OK(NoneNode())
@staticmethod @staticmethod
def many(parser, createNode): def many(parser, createNode):
def parse(input): def parse(input):

66
smnp/calc.py Normal file
View 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))

View File

@@ -1,14 +1,12 @@
import sys from smnp.calc import draft
from smnp.error.base import SmnpException from smnp.error.base import SmnpException
from smnp.library.loader import loadStandardLibrary
from smnp.program.interpreter import Interpreter
def main(): def main():
try: try:
stdLibraryEnv = loadStandardLibrary() #stdLibraryEnv = loadStandardLibrary()
Interpreter.interpretFile(sys.argv[1], printTokens=False, printAst=True, execute=False, baseEnvironment=stdLibraryEnv) #Interpreter.interpretFile(sys.argv[1], printTokens=False, printAst=True, execute=False, baseEnvironment=stdLibraryEnv)
draft()
except SmnpException as e: except SmnpException as e:
print(e.message()) print(e.message())

View File

@@ -20,11 +20,14 @@ tokenizers = (
defaultTokenizer(TokenType.CLOSE_SQUARE), defaultTokenizer(TokenType.CLOSE_SQUARE),
defaultTokenizer(TokenType.OPEN_ANGLE), defaultTokenizer(TokenType.OPEN_ANGLE),
defaultTokenizer(TokenType.CLOSE_ANGLE), defaultTokenizer(TokenType.CLOSE_ANGLE),
defaultTokenizer(TokenType.DOUBLE_ASTERISK),
defaultTokenizer(TokenType.ASTERISK), defaultTokenizer(TokenType.ASTERISK),
defaultTokenizer(TokenType.ASSIGN), defaultTokenizer(TokenType.ASSIGN),
defaultTokenizer(TokenType.ARROW), defaultTokenizer(TokenType.ARROW),
defaultTokenizer(TokenType.COMMA), defaultTokenizer(TokenType.COMMA),
defaultTokenizer(TokenType.SLASH),
defaultTokenizer(TokenType.MINUS), defaultTokenizer(TokenType.MINUS),
defaultTokenizer(TokenType.PLUS),
defaultTokenizer(TokenType.DOTS), defaultTokenizer(TokenType.DOTS),
defaultTokenizer(TokenType.AMP), defaultTokenizer(TokenType.AMP),
defaultTokenizer(TokenType.DOT), defaultTokenizer(TokenType.DOT),

View File

@@ -2,6 +2,7 @@ from enum import Enum
class TokenType(Enum): class TokenType(Enum):
DOUBLE_ASTERISK = '**'
OPEN_CURLY = '{' OPEN_CURLY = '{'
CLOSE_CURLY = '}' CLOSE_CURLY = '}'
OPEN_PAREN = '(' OPEN_PAREN = '('
@@ -14,7 +15,9 @@ class TokenType(Enum):
ASSIGN = '=' ASSIGN = '='
ARROW = '->' ARROW = '->'
COMMA = ',' COMMA = ','
SLASH = '/'
MINUS = '-' MINUS = '-'
PLUS = '+'
DOTS = '...' DOTS = '...'
AMP = '&' AMP = '&'
DOT = '.' DOT = '.'