Problem 1¶
Interpret mathematical programs developed in Exercise 11, Problem 1.
Instead of passing in the values for the expression evaluator, the variables are assigned values in the program.
(We exclude the part of the problem related to implementing a REPL as handling the user input/output is out-of-scope of this corpus.)
Classes:
|
Define the token. |
|
Define a regular expression which specifies a token. |
|
Represent a token of the source code. |
|
Represent unary operators. |
|
Represent the associativity of a binary operator. |
|
Specify precedence and associativity. |
|
Represent binary operators. |
|
Represent an identifier of a variable or of a function. |
|
Represent a node of an abstract syntax tree (AST) of a program. |
|
Represent a mathematical expression in an AST. |
|
Represent a constant in AST. |
|
Represent a variable in the AST. |
|
Represent an unary operation in the AST. |
|
Represent a binary operation in the AST. |
|
Enumerate the available functions. |
|
Represent a function call in the AST. |
Represent a statement in the AST. |
|
|
Represent an assignment statement. |
|
Represent a parsed program. |
|
Represent tokens without whitespace. |
Data:
Define rules so that we can map token kind 🠒 regular expression. |
|
Map token kind 🠒 rule to be matched for that token kind. |
|
Express an identifier of a variable or a function. |
Functions:
|
Tokenize the given |
|
Serialize the |
|
Parse the given tokens into an abstract syntax tree of a program. |
|
Convert the AST back to the source code. |
|
Interpret the given program and return the values of the assigned variables. |
- class TokenKind(value)[source]¶
Define the token.
Attributes:
Number literal
Variable (or function) identifier
Operator
Opening parenthesis
Closing parenthesis
Whitespace (including tabs etc.)
Assignment
Semicolon
- NUM = 1¶
Number literal
- VAR = 2¶
Variable (or function) identifier
- OP = 4¶
Operator
- OPEN = 5¶
Opening parenthesis
- CLOSE = 6¶
Closing parenthesis
- WHITESPACE = 7¶
Whitespace (including tabs etc.)
- ASSIGN = 8¶
Assignment
- SEMICOLON = 9¶
Semicolon
- class TokenizationRule(kind: TokenKind, pattern: Pattern[str])[source]¶
Define a regular expression which specifies a token.
Methods:
__init__
(kind, pattern)Initialize with the given values.
__repr__
()Represent the instance as a string for debugging.
- TOKENIZATION = [TokenizationRule(1, re.compile('(inf|(0|[1-9][0-9]*)(\\.[0-9]+)?(e[+\\-]?[0-9]+)?)')), TokenizationRule(2, re.compile('[a-zA-Z_][a-zA-Z_0-9]*')), TokenizationRule(4, re.compile('[+\\-*/^]')), TokenizationRule(5, re.compile('\\(')), TokenizationRule(6, re.compile('\\)')), TokenizationRule(8, re.compile('=')), TokenizationRule(9, re.compile(';')), TokenizationRule(7, re.compile('\\s+', re.MULTILINE))]¶
Define rules so that we can map token kind 🠒 regular expression.
- TOKENIZATION_MAP: Mapping[TokenKind, TokenizationRule] = {<TokenKind.NUM: 1>: TokenizationRule(1, re.compile('(inf|(0|[1-9][0-9]*)(\\.[0-9]+)?(e[+\\-]?[0-9]+)?)')), <TokenKind.VAR: 2>: TokenizationRule(2, re.compile('[a-zA-Z_][a-zA-Z_0-9]*')), <TokenKind.OP: 4>: TokenizationRule(4, re.compile('[+\\-*/^]')), <TokenKind.OPEN: 5>: TokenizationRule(5, re.compile('\\(')), <TokenKind.CLOSE: 6>: TokenizationRule(6, re.compile('\\)')), <TokenKind.ASSIGN: 8>: TokenizationRule(8, re.compile('=')), <TokenKind.SEMICOLON: 9>: TokenizationRule(9, re.compile(';')), <TokenKind.WHITESPACE: 7>: TokenizationRule(7, re.compile('\\s+', re.MULTILINE))}¶
Map token kind 🠒 rule to be matched for that token kind.
- class Token(value: str, start: int, end: int, kind: TokenKind)[source]¶
Represent a token of the source code.
Methods:
__init__
(value, start, end, kind)Initialize with the given values.
__eq__
(other)Compare against
other
of the same class based on all the properties.__repr__
()Represent the instance as a string for debugging.
- __init__(value: str, start: int, end: int, kind: TokenKind) None [source]¶
Initialize with the given values.
- Requires
start < end
len(value) == end - start
TOKENIZATION_MAP[kind].pattern.fullmatch(value)
- tokenize(text: str) List[Token] [source]¶
Tokenize the given
text
.- Ensures
not (len(result) > 0) or result[0].start == 0
(Text tokenized from the start)
not (len(result) > 0) or result[-1].end == len(text)
(Text tokenized till the end)
all( token1.end == token2.start for token1, token2 in common.pairwise(result) )
(Tokens consecutive)
all( token.value == text[token.start:token.end] for token in result )
(Token values correct)
tokens_to_text(result) == text
- tokens_to_text(tokens: Sequence[Token]) str [source]¶
Serialize the
tokens
back into the original text.- Ensures
tokens == tokenize(result)
- class UnOp(value)[source]¶
Represent unary operators.
Attributes:
Unary negative
- MINUS = '-'¶
Unary negative
- class Associativity(value)[source]¶
Represent the associativity of a binary operator.
Attributes:
Left associative
Right associative
- LEFT = 'Left'¶
Left associative
- RIGHT = 'Right'¶
Right associative
- class BinOpInfo(precedence: int, associativity: Associativity)[source]¶
Specify precedence and associativity.
Methods:
__init__
(precedence, associativity)Initialize with the given values.
- __init__(precedence: int, associativity: Associativity) None [source]¶
Initialize with the given values.
- class BinOp(value)[source]¶
Represent binary operators.
Attributes:
Addition
Subtraction
Multiplication
Division
Power
- ADD = '+'¶
Addition
- SUB = '-'¶
Subtraction
- MUL = '*'¶
Multiplication
- DIV = '/'¶
Division
- POW = '^'¶
Power
- IDENTIFIER_RE = re.compile('[a-zA-Z_][a-zA-Z0-9]*')¶
Express an identifier of a variable or a function.
- class Identifier(value: str)[source]¶
Represent an identifier of a variable or of a function.
Methods:
__new__
(cls, value)Enforce the identifier properties on
value
.- static __new__(cls, value: str) Identifier [source]¶
Enforce the identifier properties on
value
.- Requires
IDENTIFIER_RE.fullmatch(value)
- class Node[source]¶
Represent a node of an abstract syntax tree (AST) of a program.
Methods:
__repr__
()Represent the instance as a string for debugging.
- class Expr[source]¶
Represent a mathematical expression in an AST.
Methods:
__repr__
()Represent the instance as a string for debugging.
- class Constant(value: float)[source]¶
Represent a constant in AST.
Methods:
__init__
(value)Initialize with the given values.
__eq__
(other)Compare against
other
of the same class based on the properties.__repr__
()Represent the instance as a string for debugging.
- __init__(value: float) None [source]¶
Initialize with the given values.
- Requires
not math.isnan(value)
value >= 0.0
- class Variable(identifier: Identifier)[source]¶
Represent a variable in the AST.
Methods:
__init__
(identifier)Initialize with the given values.
__eq__
(other)Compare against
other
of the same class based on the properties.__repr__
()Represent the instance as a string for debugging.
- __init__(identifier: Identifier) None [source]¶
Initialize with the given values.
- class UnaryOperation(target: Expr, operator: UnOp)[source]¶
Represent an unary operation in the AST.
Methods:
__init__
(target, operator)Initialize with the given values.
__eq__
(other)Compare against
other
of the same class based on the properties.__repr__
()Represent the instance as a string for debugging.
- class BinaryOperation(left: Expr, operator: BinOp, right: Expr)[source]¶
Represent a binary operation in the AST.
Methods:
__init__
(left, operator, right)Initialize with the given values.
__eq__
(other)Compare against
other
of the same class based on the properties.__repr__
()Represent the instance as a string for debugging.
- class Function(value)[source]¶
Enumerate the available functions.
Attributes:
Sine
Cosine
Tangent
- SIN = 'sin'¶
Sine
- COS = 'cos'¶
Cosine
- TAN = 'tan'¶
Tangent
- class Call(function: Function, argument: Expr)[source]¶
Represent a function call in the AST.
Methods:
__init__
(function, argument)Initialize with the given values.
__eq__
(other)Compare against
other
of the same class based on the properties.__repr__
()Represent the instance as a string for debugging.
- class Statement[source]¶
Represent a statement in the AST.
Methods:
__repr__
()Represent the instance as a string for debugging.
- class Assign(target: Identifier, expr: Expr)[source]¶
Represent an assignment statement.
Methods:
__init__
(target, expr)Initialize with the given values.
__eq__
(other)Compare against
other
of the same class based on the properties.__repr__
()Represent the instance as a string for debugging.
- __init__(target: Identifier, expr: Expr) None [source]¶
Initialize with the given values.
- class Program(body: List[Statement])[source]¶
Represent a parsed program.
Methods:
__init__
(body)Initialize with the given values.
__eq__
(other)Compare against
other
of the same class based on the properties.__repr__
()Represent the instance as a string for debugging.
- class TokensWoWhitespace(tokens: Sequence[Token])[source]¶
Represent tokens without whitespace.
Methods:
__new__
(cls, tokens)Enforce the properties on
tokens
.Get the token(s) at the given index.
__len__
()Return the number of the tokens.
__iter__
()Iterate over the tokens.
- static __new__(cls, tokens: Sequence[Token]) TokensWoWhitespace [source]¶
Enforce the properties on
tokens
.- Requires
all(token.kind != TokenKind.WHITESPACE for token in tokens)
- __getitem__(index: int) Token [source]¶
- __getitem__(index: slice) TokensWoWhitespace
Get the token(s) at the given index.
- parse_program(tokens: Sequence[Token]) Program [source]¶
Parse the given tokens into an abstract syntax tree of a program.
- unparse(program: Program) str [source]¶
Convert the AST back to the source code.
- Ensures
parse_program(tokenize(result)) == program
- interpret(program: Program) Mapping[Identifier, float] [source]¶
Interpret the given program and return the values of the assigned variables.