Compilador Python para Basic
Compilador Python para Basic
1 Arquivo ”basic.py”
Neste arquivo est´a presente o analisador l´exico, sint´atico e semmˆantico do
com- pilador. Al´em de inlcuir o interpretador do c´odigo e as linhas para
rodar.
2 IMPORTS
from Calculodelinhasecolunas import *
import string
import os
import math
3 CONSTANTES
DIGITS = ’0123456789’
LETTERS = string.ascii_letters
LETTERS_DIGITS = LETTERS + DIGITS
4 ERROS
class Error:
def init (self, pos_start, pos_end, error_name, details):
self.pos_start = pos_start
self.pos_end = pos_end
1
self.error_name = error_name
self.details = details
def as_string(self):
result = f’{self.error_name}: {self.details}\n’
result += f’File {self.pos_start.fn}, line {self.pos_start.ln + 1}’
result += ’\n\n’ + string_with_arrows(self.pos_start.ftxt, self.pos_start, self.pos_end
return result
class IllegalCharError(Error):
def init (self, pos_start, pos_end, details):
super(). init (pos_start, pos_end, ’Illegal Character’, details)
class ExpectedCharError(Error):
def init (self, pos_start, pos_end, details):
super(). init (pos_start, pos_end, ’Expected Character’, details)
class InvalidSyntaxError(Error):
def init (self, pos_start, pos_end, details=’’):
super(). init (pos_start, pos_end, ’Invalid Syntax’, details)
class RTError(Error):
def init (self, pos_start, pos_end, details, context):
super(). init (pos_start, pos_end, ’Runtime Error’, details)
self.context = context
def as_string(self):
result = self.generate_traceback()
result += f’{self.error_name}: {self.details}’
result += ’\n\n’ + string_with_arrows(self.pos_start.ftxt, self.pos_start, self.pos_end
return result
def generate_traceback(self):
result = ’’
pos = self.pos_start
ctx = self.context
while ctx:
result = f’ File {pos.fn}, line {str(pos.ln + 1)}, in {ctx.display_name}\n’ + result
pos = ctx.parent_entry_pos
ctx = ctx.parent
2
5 POSIC¸ A˜ O
class Position:
def init (self, idx, ln, col, fn, ftxt):
self.idx = idx
self.ln = ln
self.col = col
self.fn = fn
self.ftxt = ftxt
if current_char == ’\n’:
self.ln += 1
self.col = 0
return self
def copy(self):
return Position(self.idx, self.ln, self.col, self.fn, self.ftxt)
6 TOKENS
TT_INT = ’INT’
TT_FLOAT = ’FLOAT’
TT_STRING = ’STRING’
TT_IDENTIFIER = ’IDENTIFIER’
TT_KEYWORD = ’KEYWORD’
TT_PLUS = ’PLUS’
TT_MINUS = ’MINUS’
TT_MUL = ’MUL’
TT_DIV = ’DIV’
TT_POW = ’POW’
TT_EQ = ’EQ’
TT_LPAREN = ’LPAREN’
TT_RPAREN = ’RPAREN’
TT_LSQUARE = ’LSQUARE’
TT_RSQUARE = ’RSQUARE’
TT_EE = ’EE’
TT_NE = ’NE’
TT_LT = ’LT’
TT_GT = ’GT’
3
TT_LTE = ’LTE’
TT_GTE = ’GTE’
TT_COMMA = ’COMMA’
TT_ARROW = ’ARROW’
TT_NEWLINE = ’NEWLINE’
TT_EOF = ’EOF’
KEYWORDS = [
’VAR’,
’AND’,
’OR’,
’NOT’,
’IF’,
’ELIF’,
’ELSE’,
’FOR’,
’TO’,
’STEP’,
’WHILE’,
’FUN’,
’THEN’,
’END’,
’RETURN’,
’CONTINUE’,
’BREAK’,
]
class Token:
def init (self, type_, value=None, pos_start=None, pos_end=None):
self.type = type_
self.value = value
if pos_start:
self.pos_start = pos_start.copy()
self.pos_end = pos_start.copy()
self.pos_end.advance()
if pos_end:
self.pos_end = pos_end.copy()
4
7 ANALISADOR LE´ XICO
class Lexer:
def init (self, fn, text):
self.fn = fn
self.text = text
self.pos = Position(-1, 0, -1, fn, text)
self.current_char = None
self.advance()
def advance(self):
self.pos.advance(self.current_char)
self.current_char = self.text[self.pos.idx] if self.pos.idx < len(self.text) else None
def make_tokens(self):
tokens = []
5
tokens.append(Token(TT_POW, pos_start=self.pos))
self.advance()
elif self.current_char == ’(’:
tokens.append(Token(TT_LPAREN, pos_start=self.pos))
self.advance()
elif self.current_char == ’)’:
tokens.append(Token(TT_RPAREN, pos_start=self.pos))
self.advance()
elif self.current_char == ’[’:
tokens.append(Token(TT_LSQUARE, pos_start=self.pos))
self.advance()
elif self.current_char == ’]’:
tokens.append(Token(TT_RSQUARE, pos_start=self.pos))
self.advance()
elif self.current_char == ’!’:
token, error = self.make_not_equals()
if error: return [], error
tokens.append(token)
elif self.current_char == ’=’:
tokens.append(self.make_equals())
elif self.current_char == ’<’:
tokens.append(self.make_less_than())
elif self.current_char == ’>’:
tokens.append(self.make_greater_than())
elif self.current_char == ’,’:
tokens.append(Token(TT_COMMA, pos_start=self.pos))
self.advance()
else:
pos_start = self.pos.copy()
char = self.current_char
self.advance()
return [], IllegalCharError(pos_start, self.pos, "’" + char + "’")
tokens.append(Token(TT_EOF, pos_start=self.pos))
return tokens, None
def make_number(self):
num_str = ’’
dot_count = 0
pos_start = self.pos.copy()
6
self.advance()
if dot_count == 0:
return Token(TT_INT, int(num_str), pos_start, self.pos)
else:
return Token(TT_FLOAT, float(num_str), pos_start, self.pos)
def make_string(self):
string = ’’
pos_start = self.pos.copy()
escape_character = False
self.advance()
escape_characters = {
’n’: ’\n’,
’t’: ’\t’
}
self.advance()
return Token(TT_STRING, string, pos_start, self.pos)
def make_identifier(self):
id_str = ’’
pos_start = self.pos.copy()
def make_minus_or_arrow(self):
tok_type = TT_MINUS
pos_start = self.pos.copy()
7
self.advance()
if self.current_char == ’>’:
self.advance()
tok_type = TT_ARROW
def make_not_equals(self):
pos_start = self.pos.copy()
self.advance()
if self.current_char == ’=’:
self.advance()
return Token(TT_NE, pos_start=pos_start, pos_end=self.pos), None
self.advance()
return None, ExpectedCharError(pos_start, self.pos, "’=’ (after ’!’)")
def make_equals(self):
tok_type = TT_EQ
pos_start = self.pos.copy()
self.advance()
if self.current_char == ’=’:
self.advance()
tok_type = TT_EE
def make_less_than(self):
tok_type = TT_LT
pos_start = self.pos.copy()
self.advance()
if self.current_char == ’=’:
self.advance()
tok_type = TT_LTE
def make_greater_than(self):
tok_type = TT_GT
pos_start = self.pos.copy()
self.advance()
8
if self.current_char == ’=’:
self.advance()
tok_type = TT_GTE
def skip_comment(self):
self.advance()
self.advance()
8 NODES
class NumberNode:
def init (self, tok):
self.tok = tok
self.pos_start = self.tok.pos_start
self.pos_end = self.tok.pos_end
class StringNode:
def init (self, tok):
self.tok = tok
self.pos_start = self.tok.pos_start
self.pos_end = self.tok.pos_end
class ListNode:
def init (self, element_nodes, pos_start, pos_end):
self.element_nodes = element_nodes
self.pos_start = pos_start
self.pos_end = pos_end
class VarAccessNode:
9
def init (self, var_name_tok):
self.var_name_tok = var_name_tok
self.pos_start = self.var_name_tok.pos_start
self.pos_end = self.var_name_tok.pos_end
class VarAssignNode:
def init (self, var_name_tok, value_node):
self.var_name_tok = var_name_tok
self.value_node = value_node
self.pos_start = self.var_name_tok.pos_start
self.pos_end = self.value_node.pos_end
class BinOpNode:
def init (self, left_node, op_tok, right_node):
self.left_node = left_node
self.op_tok = op_tok
self.right_node = right_node
self.pos_start = self.left_node.pos_start
self.pos_end = self.right_node.pos_end
class UnaryOpNode:
def init (self, op_tok, node):
self.op_tok = op_tok
self.node = node
self.pos_start = self.op_tok.pos_start
self.pos_end = node.pos_end
class IfNode:
def init (self, cases, else_case):
self.cases = cases
self.else_case = else_case
self.pos_start = self.cases[0][0].pos_start
self.pos_end = (self.else_case or self.cases[len(self.cases) - 1])[0].pos_end
class ForNode:
10
def init (self, var_name_tok, start_value_node, end_value_node, step_value_node, body_
self.var_name_tok = var_name_tok
self.start_value_node = start_value_node
self.end_value_node = end_value_node
self.step_value_node = step_value_node
self.body_node = body_node
self.should_return_null = should_return_null
self.pos_start = self.var_name_tok.pos_start
self.pos_end = self.body_node.pos_end
class WhileNode:
def init (self, condition_node, body_node, should_return_null):
self.condition_node = condition_node
self.body_node = body_node
self.should_return_null = should_return_null
self.pos_start = self.condition_node.pos_start
self.pos_end = self.body_node.pos_end
class FuncDefNode:
def init (self, var_name_tok, arg_name_toks, body_node, should_auto_return):
self.var_name_tok = var_name_tok
self.arg_name_toks = arg_name_toks
self.body_node = body_node
self.should_auto_return = should_auto_return
if self.var_name_tok:
self.pos_start = self.var_name_tok.pos_start
elif len(self.arg_name_toks) > 0:
self.pos_start = self.arg_name_toks[0].pos_start
else:
self.pos_start = self.body_node.pos_start
self.pos_end = self.body_node.pos_end
class CallNode:
def init (self, node_to_call, arg_nodes):
self.node_to_call = node_to_call
self.arg_nodes = arg_nodes
self.pos_start = self.node_to_call.pos_start
if len(self.arg_nodes) > 0:
self.pos_end = self.arg_nodes[len(self.arg_nodes) - 1].pos_end
else:
11
self.pos_end = self.node_to_call.pos_end
class ReturnNode:
def init (self, node_to_return, pos_start, pos_end):
self.node_to_return = node_to_return
self.pos_start = pos_start
self.pos_end = pos_end
class ContinueNode:
def init (self, pos_start, pos_end):
self.pos_start = pos_start
self.pos_end = pos_end
class BreakNode:
def init (self, pos_start, pos_end):
self.pos_start = pos_start
self.pos_end = pos_end
def register_advancement(self):
self.last_registered_advance_count = 1
self.advance_count += 1
12
def success(self, node):
self.node = node
return self
def advance(self):
self.tok_idx += 1
self.update_current_tok()
return self.current_tok
def update_current_tok(self):
if self.tok_idx >= 0 and self.tok_idx < len(self.tokens):
self.current_tok = self.tokens[self.tok_idx]
def parse(self):
res = self.statements()
if not res.error and self.current_tok.type != TT_EOF:
return res.failure(InvalidSyntaxError(
self.current_tok.pos_start, self.current_tok.pos_end,
"Token cannot appear after previous tokens"
))
return res
###################################
def statements(self):
13
res = ParseResult()
statements = []
pos_start = self.current_tok.pos_start.copy()
statement = res.register(self.statement())
if res.error: return res
statements.append(statement)
more_statements = True
while True:
newline_count = 0
while self.current_tok.type == TT_NEWLINE:
res.register_advancement()
self.advance()
newline_count += 1
if newline_count == 0:
more_statements = False
return res.success(ListNode(
statements,
pos_start,
self.current_tok.pos_end.copy()
))
def statement(self):
res = ParseResult()
pos_start = self.current_tok.pos_start.copy()
if self.current_tok.matches(TT_KEYWORD, ’RETURN’):
res.register_advancement()
self.advance()
expr = res.try_register(self.expr())
14
if not expr:
self.reverse(res.to_reverse_count)
return res.success(ReturnNode(expr, pos_start, self.current_tok.pos_start.copy()))
if self.current_tok.matches(TT_KEYWORD, ’CONTINUE’):
res.register_advancement()
self.advance()
return res.success(ContinueNode(pos_start, self.current_tok.pos_start.copy()))
if self.current_tok.matches(TT_KEYWORD, ’BREAK’):
res.register_advancement()
self.advance()
return res.success(BreakNode(pos_start, self.current_tok.pos_start.copy()))
expr = res.register(self.expr())
if res.error:
return
res.failure(InvalidSyntaxError( self.current_tok.pos_start,
self.current_tok.pos_end,
"Expected ’RETURN’, ’CONTINUE’, ’BREAK’, ’VAR’, ’IF’, ’FOR’, ’WHILE’, ’FUN’, int, f
))
return res.success(expr)
def expr(self):
res = ParseResult()
if self.current_tok.matches(TT_KEYWORD, ’VAR’):
res.register_advancement()
self.advance()
if self.current_tok.type != TT_IDENTIFIER:
return res.failure(InvalidSyntaxError(
self.current_tok.pos_start, self.current_tok.pos_end,
"Expected identifier"
))
var_name = self.current_tok
res.register_advancement()
self.advance()
if self.current_tok.type != TT_EQ:
return res.failure(InvalidSyntaxError(
self.current_tok.pos_start, self.current_tok.pos_end,
"Expected ’=’"
))
res.register_advancement()
15
self.advance()
expr = res.register(self.expr())
if res.error: return res
return res.success(VarAssignNode(var_name, expr))
if res.error:
return
res.failure(InvalidSyntaxError( self.current_tok.pos_start,
self.current_tok.pos_end,
"Expected ’VAR’, ’IF’, ’FOR’, ’WHILE’, ’FUN’, int, float, identifier, ’+’, ’-’, ’(’
))
return res.success(node)
def comp_expr(self):
res = ParseResult()
if self.current_tok.matches(TT_KEYWORD, ’NOT’):
op_tok = self.current_tok
res.register_advancement()
self.advance()
node = res.register(self.comp_expr())
if res.error: return res
return res.success(UnaryOpNode(op_tok, node))
if res.error:
return
res.failure(InvalidSyntaxError( self.current_tok.pos_start,
self.current_tok.pos_end,
"Expected int, float, identifier, ’+’, ’-’, ’(’, ’[’, ’IF’, ’FOR’, ’WHILE’, ’FUN’ o
))
return res.success(node)
def arith_expr(self):
return self.bin_op(self.term, (TT_PLUS, TT_MINUS))
def term(self):
return self.bin_op(self.factor, (TT_MUL, TT_DIV))
def factor(self):
res = ParseResult()
16
tok = self.current_tok
17
if tok.type in (TT_PLUS, TT_MINUS):
res.register_advancement()
self.advance()
factor = res.register(self.factor())
if res.error: return res
return res.success(UnaryOpNode(tok, factor))
return self.power()
def power(self):
return self.bin_op(self.call, (TT_POW, ), self.factor)
def call(self):
res = ParseResult()
atom = res.register(self.atom())
if res.error: return res
if self.current_tok.type == TT_LPAREN:
res.register_advancement()
self.advance()
arg_nodes = []
if self.current_tok.type == TT_RPAREN:
res.register_advancement()
self.advance()
else:
arg_nodes.append(res.register(self.expr()))
if res.error:
return
res.failure(InvalidSyntaxError( self.current_tok.pos_sta
rt, self.current_tok.pos_end,
"Expected ’)’, ’VAR’, ’IF’, ’FOR’, ’WHILE’, ’FUN’, int, float, identifier, ’+’,
))
arg_nodes.append(res.register(self.expr()))
if res.error: return res
if self.current_tok.type != TT_RPAREN:
return res.failure(InvalidSyntaxError(
self.current_tok.pos_start, self.current_tok.pos_end,
f"Expected ’,’ or ’)’"
))
18
res.register_advancement()
self.advance()
return res.success(CallNode(atom, arg_nodes))
return res.success(atom)
def atom(self):
res = ParseResult()
tok = self.current_tok
19
if_expr = res.register(self.if_expr())
if res.error: return res
return res.success(if_expr)
return
res.failure(InvalidSyntaxError( tok.pos_s
tart, tok.pos_end,
"Expected int, float, identifier, ’+’, ’-’, ’(’, ’[’, IF’, ’FOR’, ’WHILE’, ’FUN’"
))
def list_expr(self):
res = ParseResult()
element_nodes = []
pos_start = self.current_tok.pos_start.copy()
if self.current_tok.type != TT_LSQUARE:
return res.failure(InvalidSyntaxError(
self.current_tok.pos_start, self.current_tok.pos_end,
f"Expected ’[’"
))
res.register_advancement()
self.advance()
if self.current_tok.type == TT_RSQUARE:
res.register_advancement()
self.advance()
else:
element_nodes.append(res.register(self.expr()))
if res.error:
return
res.failure(InvalidSyntaxError( self.current_tok.pos_start
, self.current_tok.pos_end,
20
"Expected ’]’, ’VAR’, ’IF’, ’FOR’, ’WHILE’, ’FUN’, int, float, identifier, ’+’, ’
))
element_nodes.append(res.register(self.expr()))
if res.error: return res
if self.current_tok.type != TT_RSQUARE:
return res.failure(InvalidSyntaxError(
self.current_tok.pos_start, self.current_tok.pos_end,
f"Expected ’,’ or ’]’"
))
res.register_advancement()
self.advance()
return res.success(ListNode(
element_nodes,
pos_start,
self.current_tok.pos_end.copy()
))
def if_expr(self):
res = ParseResult()
all_cases = res.register(self.if_expr_cases(’IF’))
if res.error: return res
cases, else_case = all_cases
return res.success(IfNode(cases, else_case))
def if_expr_b(self):
return self.if_expr_cases(’ELIF’)
def if_expr_c(self):
res = ParseResult()
else_case = None
if self.current_tok.matches(TT_KEYWORD, ’ELSE’):
res.register_advancement()
self.advance()
if self.current_tok.type == TT_NEWLINE:
res.register_advancement()
self.advance()
21
statements = res.register(self.statements())
if res.error: return res
else_case = (statements, True)
if self.current_tok.matches(TT_KEYWORD, ’END’):
res.register_advancement()
self.advance()
else:
return
res.failure(InvalidSyntaxError( self.current_tok.pos_sta
rt, self.current_tok.pos_end, "Expected ’END’"
))
else:
expr = res.register(self.statement())
if res.error: return res
else_case = (expr, False)
return res.success(else_case)
def if_expr_b_or_c(self):
res = ParseResult()
cases, else_case = [], None
if self.current_tok.matches(TT_KEYWORD, ’ELIF’):
all_cases = res.register(self.if_expr_b())
if res.error: return res
cases, else_case = all_cases
else:
else_case = res.register(self.if_expr_c())
if res.error: return res
res.register_advancement()
22
self.advance()
condition = res.register(self.expr())
if res.error: return res
res.register_advancement()
self.advance()
if self.current_tok.type == TT_NEWLINE:
res.register_advancement()
self.advance()
statements = res.register(self.statements())
if res.error: return res
cases.append((condition, statements, True))
if self.current_tok.matches(TT_KEYWORD, ’END’):
res.register_advancement()
self.advance()
else:
all_cases = res.register(self.if_expr_b_or_c())
if res.error: return res
new_cases, else_case = all_cases
cases.extend(new_cases)
else:
expr = res.register(self.statement())
if res.error: return res
cases.append((condition, expr, False))
all_cases = res.register(self.if_expr_b_or_c())
if res.error: return res
new_cases, else_case = all_cases
cases.extend(new_cases)
def for_expr(self):
res = ParseResult()
23
return
res.failure(InvalidSyntaxError( self.current_tok.pos_start,
self.current_tok.pos_end, f"Expected ’FOR’"
))
res.register_advancement()
self.advance()
if self.current_tok.type != TT_IDENTIFIER:
return res.failure(InvalidSyntaxError(
self.current_tok.pos_start, self.current_tok.pos_end,
f"Expected identifier"
))
var_name = self.current_tok
res.register_advancement()
self.advance()
if self.current_tok.type != TT_EQ:
return res.failure(InvalidSyntaxError(
self.current_tok.pos_start, self.current_tok.pos_end,
f"Expected ’=’"
))
res.register_advancement()
self.advance()
start_value = res.register(self.expr())
if res.error: return res
res.register_advancement()
self.advance()
end_value = res.register(self.expr())
if res.error: return res
if self.current_tok.matches(TT_KEYWORD, ’STEP’):
res.register_advancement()
self.advance()
24
step_value = res.register(self.expr())
if res.error: return res
else:
step_value = None
res.register_advancement()
self.advance()
if self.current_tok.type == TT_NEWLINE:
res.register_advancement()
self.advance()
body = res.register(self.statements())
if res.error: return res
res.register_advancement()
self.advance()
body = res.register(self.statement())
if res.error: return res
def while_expr(self):
res = ParseResult()
25
res.register_advancement()
self.advance()
condition = res.register(self.expr())
if res.error: return res
res.register_advancement()
self.advance()
if self.current_tok.type == TT_NEWLINE:
res.register_advancement()
self.advance()
body = res.register(self.statements())
if res.error: return res
res.register_advancement()
self.advance()
body = res.register(self.statement())
if res.error: return res
def func_def(self):
res = ParseResult()
26
res.register_advancement()
self.advance()
if self.current_tok.type == TT_IDENTIFIER:
var_name_tok = self.current_tok
res.register_advancement()
self.advance()
if self.current_tok.type != TT_LPAREN:
return res.failure(InvalidSyntaxError(
self.current_tok.pos_start, self.current_tok.pos_end,
f"Expected ’(’"
))
else:
var_name_tok = None
if self.current_tok.type != TT_LPAREN:
return res.failure(InvalidSyntaxError(
self.current_tok.pos_start, self.current_tok.pos_end,
f"Expected identifier or ’(’"
))
res.register_advancement()
self.advance()
arg_name_toks = []
if self.current_tok.type == TT_IDENTIFIER:
arg_name_toks.append(self.current_tok)
res.register_advancement()
self.advance()
if self.current_tok.type != TT_IDENTIFIER:
return res.failure(InvalidSyntaxError(
self.current_tok.pos_start, self.current_tok.pos_end,
f"Expected identifier"
))
arg_name_toks.append(self.current_tok)
res.register_advancement()
self.advance()
if self.current_tok.type != TT_RPAREN:
return res.failure(InvalidSyntaxError(
27
self.current_tok.pos_start, self.current_tok.pos_end,
f"Expected ’,’ or ’)’"
))
else:
if self.current_tok.type != TT_RPAREN:
return res.failure(InvalidSyntaxError(
self.current_tok.pos_start, self.current_tok.pos_end,
f"Expected identifier or ’)’"
))
res.register_advancement()
self.advance()
if self.current_tok.type == TT_ARROW:
res.register_advancement()
self.advance()
body = res.register(self.expr())
if res.error: return res
return res.success(FuncDefNode(
var_name_tok,
arg_name_toks,
body,
True
))
if self.current_tok.type != TT_NEWLINE:
return res.failure(InvalidSyntaxError(
self.current_tok.pos_start, self.current_tok.pos_end,
f"Expected ’->’ or NEWLINE"
))
res.register_advancement()
self.advance()
body = res.register(self.statements())
if res.error: return res
res.register_advancement()
28
self.advance()
return res.success(FuncDefNode(
var_name_tok,
arg_name_toks,
body,
False
))
###################################
res = ParseResult()
left = res.register(func_a())
if res.error: return res
return res.success(left)
11 RESULTADO DO ”RUN”
class RTResult:
def init (self):
self.reset()
def reset(self):
self.value = None
self.error = None
self.func_return_value = None
self.loop_should_continue = False
self.loop_should_break = False
29
self.func_return_value = res.func_return_value
self.loop_should_continue = res.loop_should_continue
self.loop_should_break = res.loop_should_break
return res.value
def success_continue(self):
self.reset()
self.loop_should_continue = True
return self
def success_break(self):
self.reset()
self.loop_should_break = True
return self
def should_return(self):
return (
self.error or
self.func_return_value or
self.loop_should_continue or
self.loop_should_break
)
12 VALORES
class Value:
def init (self):
self.set_pos()
self.set_context()
30
def set_pos(self, pos_start=None, pos_end=None):
self.pos_start = pos_start
self.pos_end = pos_end
return self
31
def ored_by(self, other):
return None, self.illegal_operation(other)
def copy(self):
raise Exception(’No copy method defined’)
def is_true(self):
return False
class Number(Value):
def init (self, value):
super(). init ()
self.value = value
32
def dived_by(self, other):
if isinstance(other, Number):
if other.value == 0:
return None,
RTError( other.pos_start,
other.pos_end, ’Division by
zero’, self.context
)
33
else:
return None, Value.illegal_operation(self, other)
def notted(self):
return Number(1 if self.value == 0 else 0).set_context(self.context), None
def copy(self):
copy = Number(self.value)
copy.set_pos(self.pos_start, self.pos_end)
copy.set_context(self.context)
return copy
def is_true(self):
return self.value != 0
Number.null = Number(0)
Number.false = Number(0)
Number.true = Number(1)
Number.math_PI = Number(math.pi)
class String(Value):
def init (self, value):
34
super(). init ()
self.value = value
def is_true(self):
return len(self.value) > 0
def copy(self):
copy = String(self.value)
copy.set_pos(self.pos_start, self.pos_end)
copy.set_context(self.context)
return copy
class List(Value):
def init (self, elements):
super(). init ()
self.elements = elements
35
except:
return None,
RTError( other.pos_start,
other.pos_end,
’Element at this index could not be removed from list because index is out of bou
self.context
)
else:
return None, Value.illegal_operation(self, other)
def copy(self):
copy = List(self.elements)
copy.set_pos(self.pos_start, self.pos_end)
copy.set_context(self.context)
return copy
class BaseFunction(Value):
def init (self, name):
super(). init ()
self.name = name or "<anonymous>"
36
def generate_new_context(self):
new_context = Context(self.name, self.context, self.pos_start)
new_context.symbol_table = SymbolTable(new_context.parent.symbol_table)
return new_context
return res.success(None)
class Function(BaseFunction):
def init (self, name, body_node, arg_names, should_auto_return):
super(). init (name)
self.body_node = body_node
self.arg_names = arg_names
self.should_auto_return = should_auto_return
37
def execute(self, args):
res = RTResult()
interpreter = Interpreter()
exec_ctx = self.generate_new_context()
def copy(self):
copy = Function(self.name, self.body_node, self.arg_names, self.should_auto_return)
copy.set_context(self.context)
copy.set_pos(self.pos_start, self.pos_end)
return copy
class BuiltInFunction(BaseFunction):
def init (self, name):
super(). init (name)
method_name = f’execute_{self.name}’
method = getattr(self, method_name, self.no_visit_method)
return_value = res.register(method(exec_ctx))
if res.should_return(): return res
return res.success(return_value)
def copy(self):
copy = BuiltInFunction(self.name)
38
copy.set_context(self.context)
copy.set_pos(self.pos_start, self.pos_end)
return copy
#####################################
39
return RTResult().success(Number.true if is_number else Number.false)
execute_is_string.arg_names = ["value"]
list_.elements.append(value)
return RTResult().success(Number.null)
execute_append.arg_names = ["list", "value"]
40
try:
element = list_.elements.pop(index.value)
except:
return RTResult().failure(RTError(
self.pos_start, self.pos_end,
’Element at this index could not be removed from list because index is out of bound
exec_ctx
))
return RTResult().success(element)
execute_pop.arg_names = ["list", "index"]
listA.elements.extend(listB.elements)
return RTResult().success(Number.null)
execute_extend.arg_names = ["listA", "listB"]
return RTResult().success(Number(len(list_.elements)))
execute_len.arg_names = ["list"]
41
def execute_run(self, exec_ctx):
fn = exec_ctx.symbol_table.get("fn")
fn = fn.value
try:
with open(fn, "r") as f:
script = f.read()
except Exception as e:
return RTResult().failure(RTError(
self.pos_start, self.pos_end,
f"Failed to load script \"{fn}\"\n" + str(e),
exec_ctx
))
if error:
return RTResult().failure(RTError(
self.pos_start, self.pos_end,
f"Failed to finish executing script \"{fn}\"\n" +
error.as_string(),
exec_ctx
))
return RTResult().success(Number.null)
execute_run.arg_names = ["fn"]
BuiltInFunction.print = BuiltInFunction("print")
BuiltInFunction.print_ret = BuiltInFunction("print_ret")
BuiltInFunction.input = BuiltInFunction("input")
BuiltInFunction.input_int = BuiltInFunction("input_int")
BuiltInFunction.clear = BuiltInFunction("clear")
BuiltInFunction.is_number = BuiltInFunction("is_number")
BuiltInFunction.is_string = BuiltInFunction("is_string")
BuiltInFunction.is_list = BuiltInFunction("is_list")
BuiltInFunction.is_function = BuiltInFunction("is_function")
BuiltInFunction.append = BuiltInFunction("append")
BuiltInFunction.pop = BuiltInFunction("pop")
42
BuiltInFunction.extend = BuiltInFunction("extend")
BuiltInFunction.len = BuiltInFunction("len")
BuiltInFunction.run = BuiltInFunction("run")
class Context:
def init (self, display_name, parent=None, parent_entry_pos=None):
self.display_name = display_name
self.parent = parent
self.parent_entry_pos = parent_entry_pos
self.symbol_table = None
#######################################
TABELA DE S ´IMBOLOS
#######################################
class SymbolTable:
def init (self, parent=None):
self.symbols = {}
self.parent = parent
14 INTERPRETADOR
class Interpreter:
def visit(self, node, context):
43
method_name = f’visit_{type(node). name }’
method = getattr(self, method_name, self.no_visit_method)
return method(node, context)
###################################
return res.success(
List(elements).set_context(context).set_pos(node.pos_start, node.pos_end)
)
if not value:
return
res.failure(RTError( node.pos_
start, node.pos_end,
f"’{var_name}’ is not defined",
context
))
44
def visit_VarAssignNode(self, node, context):
res = RTResult()
var_name = node.var_name_tok.value
value = res.register(self.visit(node.value_node, context))
if res.should_return(): return res
context.symbol_table.set(var_name, value)
return res.success(value)
if node.op_tok.type == TT_PLUS:
result, error = left.added_to(right)
elif node.op_tok.type == TT_MINUS:
result, error = left.subbed_by(right)
elif node.op_tok.type == TT_MUL:
result, error = left.multed_by(right)
elif node.op_tok.type == TT_DIV:
result, error = left.dived_by(right)
elif node.op_tok.type == TT_POW:
result, error = left.powed_by(right)
elif node.op_tok.type == TT_EE:
result, error = left.get_comparison_eq(right)
elif node.op_tok.type == TT_NE:
result, error = left.get_comparison_ne(right)
elif node.op_tok.type == TT_LT:
result, error = left.get_comparison_lt(right)
elif node.op_tok.type == TT_GT:
result, error = left.get_comparison_gt(right)
elif node.op_tok.type == TT_LTE:
result, error = left.get_comparison_lte(right)
elif node.op_tok.type == TT_GTE:
result, error = left.get_comparison_gte(right)
elif node.op_tok.matches(TT_KEYWORD, ’AND’):
result, error = left.anded_by(right)
elif node.op_tok.matches(TT_KEYWORD, ’OR’):
result, error = left.ored_by(right)
if error:
return res.failure(error)
else:
45
return res.success(result.set_pos(node.pos_start, node.pos_end))
error = None
if node.op_tok.type == TT_MINUS:
number, error = number.multed_by(Number(-1))
elif node.op_tok.matches(TT_KEYWORD, ’NOT’):
number, error = number.notted()
if error:
return res.failure(error)
else:
return res.success(number.set_pos(node.pos_start, node.pos_end))
if condition_value.is_true():
expr_value = res.register(self.visit(expr, context))
if res.should_return(): return res
return res.success(Number.null if should_return_null else expr_value)
if node.else_case:
expr, should_return_null = node.else_case
expr_value = res.register(self.visit(expr, context))
if res.should_return(): return res
return res.success(Number.null if should_return_null else expr_value)
return res.success(Number.null)
46
end_value = res.register(self.visit(node.end_value_node, context))
if res.should_return(): return res
if node.step_value_node:
step_value = res.register(self.visit(node.step_value_node, context))
if res.should_return(): return res
else:
step_value = Number(1)
i = start_value.value
if step_value.value >= 0:
condition = lambda: i < end_value.value
else:
condition = lambda: i > end_value.value
while condition():
context.symbol_table.set(node.var_name_tok.value, Number(i))
i += step_value.value
if res.loop_should_continue:
continue
if res.loop_should_break:
break
elements.append(value)
return res.success(
Number.null if node.should_return_null else
List(elements).set_context(context).set_pos(node.pos_start, node.pos_end)
)
while True:
condition = res.register(self.visit(node.condition_node, context))
if res.should_return(): return res
if not condition.is_true():
break
47
value = res.register(self.visit(node.body_node, context))
if res.should_return() and res.loop_should_continue == False and res.loop_should_brea
if res.loop_should_continue:
continue
if res.loop_should_break:
break
elements.append(value)
return res.success(
Number.null if node.should_return_null else
List(elements).set_context(context).set_pos(node.pos_start, node.pos_end)
)
if node.var_name_tok:
context.symbol_table.set(func_name, func_value)
return res.success(func_value)
return_value = res.register(value_to_call.execute(args))
if res.should_return(): return res
return_value = return_value.copy().set_pos(node.pos_start, node.pos_end).set_context(co
return res.success(return_value)
48
def visit_ReturnNode(self, node, context):
res = RTResult()
if node.node_to_return:
value = res.register(self.visit(node.node_to_return, context))
if res.should_return(): return res
else:
value = Number.null
return res.success_return(value)
15 RUN
global_symbol_table = SymbolTable()
global_symbol_table.set("NULL", Number.null)
global_symbol_table.set("FALSE", Number.false)
global_symbol_table.set("TRUE", Number.true)
global_symbol_table.set("MATH_PI", Number.math_PI)
global_symbol_table.set("PRINT", BuiltInFunction.print)
global_symbol_table.set("PRINT_RET", BuiltInFunction.print_ret)
global_symbol_table.set("INPUT", BuiltInFunction.input)
global_symbol_table.set("INPUT_INT", BuiltInFunction.input_int)
global_symbol_table.set("CLEAR", BuiltInFunction.clear)
global_symbol_table.set("CLS", BuiltInFunction.clear)
global_symbol_table.set("IS_NUM", BuiltInFunction.is_number)
global_symbol_table.set("IS_STR", BuiltInFunction.is_string)
global_symbol_table.set("IS_LIST", BuiltInFunction.is_list)
global_symbol_table.set("IS_FUN", BuiltInFunction.is_function)
global_symbol_table.set("APPEND", BuiltInFunction.append)
global_symbol_table.set("POP", BuiltInFunction.pop)
global_symbol_table.set("EXTEND", BuiltInFunction.extend)
global_symbol_table.set("LEN", BuiltInFunction.len)
global_symbol_table.set("RUN", BuiltInFunction.run)
49
tokens, error = lexer.make_tokens()
if error: return None, error
# Gerar Sint´atica
parser = Parser(tokens)
ast = parser.parse()
if ast.error: return None, ast.error
# Run do programa
interpreter = Interpreter()
context = Context(’<program>’)
context.symbol_table = global_symbol_table
result = interpreter.visit(ast.node, context)
16 Arquivo ”Calculosdelinhasecolunas.py”
def string_with_arrows(text, pos_start, pos_end):
result = ’’
# Calcular ´ındices
idx_start = max(text.rfind(’\n’, 0, pos_start.idx), 0)
idx_end = text.find(’\n’, idx_start + 1)
if idx_end < 0: idx_end = len(text)
# Acrescentar no resultado
result += line + ’\n’
result += ’ ’ * col_start + ’^’ * (col_end - col_start)
# Recalcular ´ındices
idx_start = idx_end
idx_end = text.find(’\n’, idx_start + 1)
if idx_end < 0: idx_end = len(text)
50
17 Arquivo ”execut´avel.py”
import basic
while True:
text = input(’basic > ’)
if text.strip() == "": continue
result, error = basic.run(’<stdin>’, text)
if error:
print(error.as_string())
elif result:
if len(result.elements) == 1:
print(repr(result.elements[0]))
else:
print(repr(result))
EM BASIC:
PRINT ”Hello,
world!
END
EM PYTHON:
print(”Hello, World!”)
51