0% found this document useful (0 votes)
12 views

Compilador Python para Basic

Uploaded by

guolri21
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
12 views

Compilador Python para Basic

Uploaded by

guolri21
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 51

Compilador python para basic

Felipe Marinho 823110744


Patrick Hernani 823124370
Gustavo Damaceno 823116212
Marcelo Damasio 823135127
Gustavo Oliveira RA:823161047
Matheus Rodrigues RA:823158717
June 2024

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

return ’Traceback (most recent call last):\n’ + result

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

def advance(self, current_char=None):


self.idx += 1
self.col += 1

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()

def matches(self, type_, value):


return self.type == type_ and self.value == value

def repr (self):


if self.value: return f’{self.type}:{self.value}’
return f’{self.type}’

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 = []

while self.current_char != None:


if self.current_char in ’ \t’:
self.advance()
elif self.current_char == ’#’:
self.skip_comment()
elif self.current_char in ’;\n’:
tokens.append(Token(TT_NEWLINE, pos_start=self.pos))
self.advance()
elif self.current_char in DIGITS:
tokens.append(self.make_number())
elif self.current_char in LETTERS:
tokens.append(self.make_identifier())
elif self.current_char == ’"’:
tokens.append(self.make_string())
elif self.current_char == ’+’:
tokens.append(Token(TT_PLUS, pos_start=self.pos))
self.advance()
elif self.current_char == ’-’:
tokens.append(self.make_minus_or_arrow())
elif self.current_char == ’*’:
tokens.append(Token(TT_MUL, pos_start=self.pos))
self.advance()
elif self.current_char == ’/’:
tokens.append(Token(TT_DIV, pos_start=self.pos))
self.advance()
elif self.current_char == ’^’:

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()

while self.current_char != None and self.current_char in DIGITS + ’.’:


if self.current_char == ’.’:
if dot_count == 1: break
dot_count += 1
num_str += self.current_char

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’
}

while self.current_char != None and (self.current_char != ’"’ or escape_character):


if escape_character:
string += escape_characters.get(self.current_char, self.current_char)
else:
if self.current_char == ’\\’:
escape_character = True
else:
string += self.current_char
self.advance()
escape_character = False

self.advance()
return Token(TT_STRING, string, pos_start, self.pos)

def make_identifier(self):
id_str = ’’
pos_start = self.pos.copy()

while self.current_char != None and self.current_char in LETTERS_DIGITS + ’_’:


id_str += self.current_char
self.advance()

tok_type = TT_KEYWORD if id_str in KEYWORDS else TT_IDENTIFIER


return Token(tok_type, id_str, pos_start, self.pos)

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

return Token(tok_type, pos_start=pos_start, pos_end=self.pos)

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

return Token(tok_type, pos_start=pos_start, pos_end=self.pos)

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

return Token(tok_type, pos_start=pos_start, pos_end=self.pos)

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

return Token(tok_type, pos_start=pos_start, pos_end=self.pos)

def skip_comment(self):
self.advance()

while self.current_char != ’\n’:


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

def repr (self):


return f’{self.tok}’

class StringNode:
def init (self, tok):
self.tok = tok

self.pos_start = self.tok.pos_start
self.pos_end = self.tok.pos_end

def repr (self):


return f’{self.tok}’

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

def repr (self):


return f’({self.left_node}, {self.op_tok}, {self.right_node})’

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

def repr (self):


return f’({self.op_tok}, {self.node})’

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

9 RESULTADO ANALISADOR SINTA´ TICO


class ParseResult:
def init (self):
self.error = None
self.node = None
self.last_registered_advance_count = 0
self.advance_count = 0
self.to_reverse_count = 0

def register_advancement(self):
self.last_registered_advance_count = 1
self.advance_count += 1

def register(self, res):


self.last_registered_advance_count = res.advance_count
self.advance_count += res.advance_count
if res.error: self.error = res.error
return res.node

def try_register(self, res):


if res.error:
self.to_reverse_count = res.advance_count
return None
return self.register(res)

12
def success(self, node):
self.node = node
return self

def failure(self, error):


if not self.error or self.last_registered_advance_count == 0:
self.error = error
return self

10 ANALISADOR SINTA´ TICO


class Parser:
def init (self, tokens):
self.tokens = tokens
self.tok_idx = -1
self.advance()

def advance(self):
self.tok_idx += 1
self.update_current_tok()
return self.current_tok

def reverse(self, amount=1):


self.tok_idx -= amount
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()

while self.current_tok.type == TT_NEWLINE:


res.register_advancement()
self.advance()

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

if not more_statements: break


statement = res.try_register(self.statement())
if not statement:
self.reverse(res.to_reverse_count)
more_statements = False
continue
statements.append(statement)

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))

node = res.register(self.bin_op(self.comp_expr, ((TT_KEYWORD, ’AND’), (TT_KEYWORD, ’OR’

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))

node = res.register(self.bin_op(self.arith_expr, (TT_EE, TT_NE, TT_LT, TT_GT, TT_LTE,

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, ’+’,
))

while self.current_tok.type == TT_COMMA:


res.register_advancement()
self.advance()

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

if tok.type in (TT_INT, TT_FLOAT):


res.register_advancement()
self.advance()
return res.success(NumberNode(tok))

elif tok.type == TT_STRING:


res.register_advancement()
self.advance()
return res.success(StringNode(tok))

elif tok.type == TT_IDENTIFIER:


res.register_advancement()
self.advance()
return res.success(VarAccessNode(tok))

elif tok.type == TT_LPAREN:


res.register_advancement()
self.advance()
expr = res.register(self.expr())
if res.error: return res
if self.current_tok.type == TT_RPAREN:
res.register_advancement()
self.advance()
return res.success(expr)
else:
return
res.failure(InvalidSyntaxError( self.current_tok.pos_st
art, self.current_tok.pos_end, "Expected ’)’"
))

elif tok.type == TT_LSQUARE:


list_expr = res.register(self.list_expr())
if res.error: return res
return res.success(list_expr)

elif tok.matches(TT_KEYWORD, ’IF’):

19
if_expr = res.register(self.if_expr())
if res.error: return res
return res.success(if_expr)

elif tok.matches(TT_KEYWORD, ’FOR’):


for_expr = res.register(self.for_expr())
if res.error: return res
return res.success(for_expr)

elif tok.matches(TT_KEYWORD, ’WHILE’):


while_expr = res.register(self.while_expr())
if res.error: return res
return res.success(while_expr)

elif tok.matches(TT_KEYWORD, ’FUN’):


func_def = res.register(self.func_def())
if res.error: return res
return res.success(func_def)

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, ’+’, ’
))

while self.current_tok.type == TT_COMMA:


res.register_advancement()
self.advance()

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

return res.success((cases, else_case))

def if_expr_cases(self, case_keyword):


res = ParseResult()
cases = []
else_case = None

if not self.current_tok.matches(TT_KEYWORD, case_keyword):


return res.failure(InvalidSyntaxError(
self.current_tok.pos_start, self.current_tok.pos_end,
f"Expected ’{case_keyword}’"
))

res.register_advancement()

22
self.advance()

condition = res.register(self.expr())
if res.error: return res

if not self.current_tok.matches(TT_KEYWORD, ’THEN’):


return res.failure(InvalidSyntaxError(
self.current_tok.pos_start, self.current_tok.pos_end,
f"Expected ’THEN’"
))

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)

return res.success((cases, else_case))

def for_expr(self):
res = ParseResult()

if not self.current_tok.matches(TT_KEYWORD, ’FOR’):

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

if not self.current_tok.matches(TT_KEYWORD, ’TO’):


return res.failure(InvalidSyntaxError(
self.current_tok.pos_start, self.current_tok.pos_end,
f"Expected ’TO’"
))

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

if not self.current_tok.matches(TT_KEYWORD, ’THEN’):


return res.failure(InvalidSyntaxError(
self.current_tok.pos_start, self.current_tok.pos_end,
f"Expected ’THEN’"
))

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

if not self.current_tok.matches(TT_KEYWORD, ’END’):


return res.failure(InvalidSyntaxError(
self.current_tok.pos_start, self.current_tok.pos_end,
f"Expected ’END’"
))

res.register_advancement()
self.advance()

return res.success(ForNode(var_name, start_value, end_value, step_value, body, True))

body = res.register(self.statement())
if res.error: return res

return res.success(ForNode(var_name, start_value, end_value, step_value, body, False))

def while_expr(self):
res = ParseResult()

if not self.current_tok.matches(TT_KEYWORD, ’WHILE’):


return res.failure(InvalidSyntaxError(
self.current_tok.pos_start, self.current_tok.pos_end,
f"Expected ’WHILE’"
))

25
res.register_advancement()
self.advance()

condition = res.register(self.expr())
if res.error: return res

if not self.current_tok.matches(TT_KEYWORD, ’THEN’):


return res.failure(InvalidSyntaxError(
self.current_tok.pos_start, self.current_tok.pos_end,
f"Expected ’THEN’"
))

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

if not self.current_tok.matches(TT_KEYWORD, ’END’):


return res.failure(InvalidSyntaxError(
self.current_tok.pos_start, self.current_tok.pos_end,
f"Expected ’END’"
))

res.register_advancement()
self.advance()

return res.success(WhileNode(condition, body, True))

body = res.register(self.statement())
if res.error: return res

return res.success(WhileNode(condition, body, False))

def func_def(self):
res = ParseResult()

if not self.current_tok.matches(TT_KEYWORD, ’FUN’):


return res.failure(InvalidSyntaxError(
self.current_tok.pos_start, self.current_tok.pos_end,
f"Expected ’FUN’"
))

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()

while self.current_tok.type == TT_COMMA:


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

if not self.current_tok.matches(TT_KEYWORD, ’END’):


return res.failure(InvalidSyntaxError(
self.current_tok.pos_start, self.current_tok.pos_end,
f"Expected ’END’"
))

res.register_advancement()

28
self.advance()

return res.success(FuncDefNode(
var_name_tok,
arg_name_toks,
body,
False
))

###################################

def bin_op(self, func_a, ops, func_b=None):


if func_b == None:
func_b = func_a

res = ParseResult()
left = res.register(func_a())
if res.error: return res

while self.current_tok.type in ops or (self.current_tok.type, self.current_tok.value) i


op_tok = self.current_tok
res.register_advancement()
self.advance()
right = res.register(func_b())
if res.error: return res
left = BinOpNode(left, op_tok, right)

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

def register(self, res):


self.error = res.error

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(self, value):


self.reset()
self.value = value
return self

def success_return(self, value):


self.reset()
self.func_return_value = value
return self

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 failure(self, error):


self.reset()
self.error = error
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

def set_context(self, context=None):


self.context = context
return self

def added_to(self, other):


return None, self.illegal_operation(other)

def subbed_by(self, other):


return None, self.illegal_operation(other)

def multed_by(self, other):


return None, self.illegal_operation(other)

def dived_by(self, other):


return None, self.illegal_operation(other)

def powed_by(self, other):


return None, self.illegal_operation(other)

def get_comparison_eq(self, other):


return None, self.illegal_operation(other)

def get_comparison_ne(self, other):


return None, self.illegal_operation(other)

def get_comparison_lt(self, other):


return None, self.illegal_operation(other)

def get_comparison_gt(self, other):


return None, self.illegal_operation(other)

def get_comparison_lte(self, other):


return None, self.illegal_operation(other)

def get_comparison_gte(self, other):


return None, self.illegal_operation(other)

def anded_by(self, other):


return None, self.illegal_operation(other)

31
def ored_by(self, other):
return None, self.illegal_operation(other)

def notted(self, other):


return None, self.illegal_operation(other)

def execute(self, args):


return RTResult().failure(self.illegal_operation())

def copy(self):
raise Exception(’No copy method defined’)

def is_true(self):
return False

def illegal_operation(self, other=None):


if not other: other = self
return RTError(
self.pos_start, other.pos_end,
’Illegal operation’,
self.context
)

class Number(Value):
def init (self, value):
super(). init ()
self.value = value

def added_to(self, other):


if isinstance(other, Number):
return Number(self.value + other.value).set_context(self.context), None
else:
return None, Value.illegal_operation(self, other)

def subbed_by(self, other):


if isinstance(other, Number):
return Number(self.value - other.value).set_context(self.context), None
else:
return None, Value.illegal_operation(self, other)

def multed_by(self, other):


if isinstance(other, Number):
return Number(self.value * other.value).set_context(self.context), None
else:
return None, Value.illegal_operation(self, other)

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
)

return Number(self.value / other.value).set_context(self.context), None


else:
return None, Value.illegal_operation(self, other)

def powed_by(self, other):


if isinstance(other, Number):
return Number(self.value ** other.value).set_context(self.context), None
else:
return None, Value.illegal_operation(self, other)

def get_comparison_eq(self, other):


if isinstance(other, Number):
return Number(int(self.value == other.value)).set_context(self.context), None
else:
return None, Value.illegal_operation(self, other)

def get_comparison_ne(self, other):


if isinstance(other, Number):
return Number(int(self.value != other.value)).set_context(self.context), None
else:
return None, Value.illegal_operation(self, other)

def get_comparison_lt(self, other):


if isinstance(other, Number):
return Number(int(self.value < other.value)).set_context(self.context), None
else:
return None, Value.illegal_operation(self, other)

def get_comparison_gt(self, other):


if isinstance(other, Number):
return Number(int(self.value > other.value)).set_context(self.context), None
else:
return None, Value.illegal_operation(self, other)

def get_comparison_lte(self, other):


if isinstance(other, Number):
return Number(int(self.value <= other.value)).set_context(self.context), None

33
else:
return None, Value.illegal_operation(self, other)

def get_comparison_gte(self, other):


if isinstance(other, Number):
return Number(int(self.value >= other.value)).set_context(self.context), None
else:
return None, Value.illegal_operation(self, other)

def anded_by(self, other):


if isinstance(other, Number):
return Number(int(self.value and other.value)).set_context(self.context), None
else:
return None, Value.illegal_operation(self, other)

def ored_by(self, other):


if isinstance(other, Number):
return Number(int(self.value or other.value)).set_context(self.context), None
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

def str (self):


return str(self.value)

def repr (self):


return str(self.value)

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 added_to(self, other):


if isinstance(other, String):
return String(self.value + other.value).set_context(self.context), None
else:
return None, Value.illegal_operation(self, other)

def multed_by(self, other):


if isinstance(other, Number):
return String(self.value * other.value).set_context(self.context), None
else:
return None, Value.illegal_operation(self, other)

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

def str (self):


return self.value

def repr (self):


return f’"{self.value}"’

class List(Value):
def init (self, elements):
super(). init ()
self.elements = elements

def added_to(self, other):


new_list = self.copy()
new_list.elements.append(other)
return new_list, None

def subbed_by(self, other):


if isinstance(other, Number):
new_list = self.copy()
try:
new_list.elements.pop(other.value)
return new_list, None

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 multed_by(self, other):


if isinstance(other, List):
new_list = self.copy()
new_list.elements.extend(other.elements)
return new_list, None
else:
return None, Value.illegal_operation(self, other)

def dived_by(self, other):


if isinstance(other, Number):
try:
return self.elements[other.value], None
except:
return None,
RTError( other.pos_start,
other.pos_end,
’Element at this index could not be retrieved from list because index is out of
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

def str (self):


return ", ".join([str(x) for x in self.elements])

def repr (self):


return f’[{", ".join([repr(x) for x in self.elements])}]’

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

def check_args(self, arg_names, args):


res = RTResult()

if len(args) > len(arg_names):


return res.failure(RTError(
self.pos_start, self.pos_end,
f"{len(args) - len(arg_names)} too many args passed into {self}",
self.context
))

if len(args) < len(arg_names):


return res.failure(RTError(
self.pos_start, self.pos_end,
f"{len(arg_names) - len(args)} too few args passed into {self}",
self.context
))

return res.success(None)

def populate_args(self, arg_names, args, exec_ctx):


for i in range(len(args)):
arg_name = arg_names[i]
arg_value = args[i]
arg_value.set_context(exec_ctx)
exec_ctx.symbol_table.set(arg_name, arg_value)

def check_and_populate_args(self, arg_names, args, exec_ctx):


res = RTResult()
res.register(self.check_args(arg_names, args))
if res.should_return(): return res
self.populate_args(arg_names, args, exec_ctx)
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()

res.register(self.check_and_populate_args(self.arg_names, args, exec_ctx))


if res.should_return(): return res

value = res.register(interpreter.visit(self.body_node, exec_ctx))


if res.should_return() and res.func_return_value == None: return res

ret_value = (value if self.should_auto_return else None) or res.func_return_value or Nu


return res.success(ret_value)

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

def repr (self):


return f"<function {self.name}>"

class BuiltInFunction(BaseFunction):
def init (self, name):
super(). init (name)

def execute(self, args):


res = RTResult()
exec_ctx = self.generate_new_context()

method_name = f’execute_{self.name}’
method = getattr(self, method_name, self.no_visit_method)

res.register(self.check_and_populate_args(method.arg_names, args, exec_ctx))


if res.should_return(): return res

return_value = res.register(method(exec_ctx))
if res.should_return(): return res
return res.success(return_value)

def no_visit_method(self, node, context):


raise Exception(f’No execute_{self.name} method defined’)

def copy(self):
copy = BuiltInFunction(self.name)

38
copy.set_context(self.context)
copy.set_pos(self.pos_start, self.pos_end)
return copy

def repr (self):


return f"<built-in function {self.name}>"

#####################################

def execute_print(self, exec_ctx):


print(str(exec_ctx.symbol_table.get(’value’)))
return RTResult().success(Number.null)
execute_print.arg_names = [’value’]

def execute_print_ret(self, exec_ctx):


return RTResult().success(String(str(exec_ctx.symbol_table.get(’value’))))
execute_print_ret.arg_names = [’value’]

def execute_input(self, exec_ctx):


text = input()
return RTResult().success(String(text))
execute_input.arg_names = []

def execute_input_int(self, exec_ctx):


while True:
text = input()
try:
number = int(text)
break
except ValueError:
print(f"’{text}’ must be an integer. Try again!")
return RTResult().success(Number(number))
execute_input_int.arg_names = []

def execute_clear(self, exec_ctx):


os.system(’cls’ if os.name == ’nt’ else ’cls’)
return RTResult().success(Number.null)
execute_clear.arg_names = []

def execute_is_number(self, exec_ctx):


is_number = isinstance(exec_ctx.symbol_table.get("value"), Number)
return RTResult().success(Number.true if is_number else Number.false)
execute_is_number.arg_names = ["value"]

def execute_is_string(self, exec_ctx):


is_number = isinstance(exec_ctx.symbol_table.get("value"), String)

39
return RTResult().success(Number.true if is_number else Number.false)
execute_is_string.arg_names = ["value"]

def execute_is_list(self, exec_ctx):


is_number = isinstance(exec_ctx.symbol_table.get("value"), List)
return RTResult().success(Number.true if is_number else Number.false)
execute_is_list.arg_names = ["value"]

def execute_is_function(self, exec_ctx):


is_number = isinstance(exec_ctx.symbol_table.get("value"), BaseFunction)
return RTResult().success(Number.true if is_number else Number.false)
execute_is_function.arg_names = ["value"]

def execute_append(self, exec_ctx):


list_ = exec_ctx.symbol_table.get("list")
value = exec_ctx.symbol_table.get("value")

if not isinstance(list_, List):


return RTResult().failure(RTError(
self.pos_start, self.pos_end,
"First argument must be list",
exec_ctx
))

list_.elements.append(value)
return RTResult().success(Number.null)
execute_append.arg_names = ["list", "value"]

def execute_pop(self, exec_ctx):


list_ = exec_ctx.symbol_table.get("list")
index = exec_ctx.symbol_table.get("index")

if not isinstance(list_, List):


return RTResult().failure(RTError(
self.pos_start, self.pos_end,
"First argument must be list",
exec_ctx
))

if not isinstance(index, Number):


return RTResult().failure(RTError(
self.pos_start, self.pos_end,
"Second argument must be number",
exec_ctx
))

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"]

def execute_extend(self, exec_ctx):


listA = exec_ctx.symbol_table.get("listA")
listB = exec_ctx.symbol_table.get("listB")

if not isinstance(listA, List):


return RTResult().failure(RTError(
self.pos_start, self.pos_end,
"First argument must be list",
exec_ctx
))

if not isinstance(listB, List):


return RTResult().failure(RTError(
self.pos_start, self.pos_end,
"Second argument must be list",
exec_ctx
))

listA.elements.extend(listB.elements)
return RTResult().success(Number.null)
execute_extend.arg_names = ["listA", "listB"]

def execute_len(self, exec_ctx):


list_ = exec_ctx.symbol_table.get("list")

if not isinstance(list_, List):


return RTResult().failure(RTError(
self.pos_start, self.pos_end,
"Argument must be list",
exec_ctx
))

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")

if not isinstance(fn, String):


return RTResult().failure(RTError(
self.pos_start, self.pos_end,
"Second argument must be string",
exec_ctx
))

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
))

_, error = run(fn, script)

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")

13 ANALISADOR SEMAˆ NTICO


#######################################
CONTEXTO
#######################################

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

def get(self, name):


value = self.symbols.get(name, None)
if value == None and self.parent:
return self.parent.get(name)
return value

def set(self, name, value):


self.symbols[name] = value

def remove(self, name):


del self.symbols[name]

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)

def no_visit_method(self, node, context):


raise Exception(f’No visit_{type(node). name } method defined’)

###################################

def visit_NumberNode(self, node, context):


return RTResult().success(
Number(node.tok.value).set_context(context).set_pos(node.pos_start, node.pos_end)
)

def visit_StringNode(self, node, context):


return RTResult().success(
String(node.tok.value).set_context(context).set_pos(node.pos_start, node.pos_end)
)

def visit_ListNode(self, node, context):


res = RTResult()
elements = []

for element_node in node.element_nodes:


elements.append(res.register(self.visit(element_node, context)))
if res.should_return(): return res

return res.success(
List(elements).set_context(context).set_pos(node.pos_start, node.pos_end)
)

def visit_VarAccessNode(self, node, context):


res = RTResult()
var_name = node.var_name_tok.value
value = context.symbol_table.get(var_name)

if not value:
return
res.failure(RTError( node.pos_
start, node.pos_end,
f"’{var_name}’ is not defined",
context
))

value = value.copy().set_pos(node.pos_start, node.pos_end).set_context(context)


return res.success(value)

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)

def visit_BinOpNode(self, node, context):


res = RTResult()
left = res.register(self.visit(node.left_node, context))
if res.should_return(): return res
right = res.register(self.visit(node.right_node, context))
if res.should_return(): return res

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))

def visit_UnaryOpNode(self, node, context):


res = RTResult()
number = res.register(self.visit(node.node, context))
if res.should_return(): return res

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))

def visit_IfNode(self, node, context):


res = RTResult()

for condition, expr, should_return_null in node.cases:


condition_value = res.register(self.visit(condition, context))
if res.should_return(): return res

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)

def visit_ForNode(self, node, context):


res = RTResult()
elements = []

start_value = res.register(self.visit(node.start_value_node, context))


if res.should_return(): return res

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

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)
)

def visit_WhileNode(self, node, context):


res = RTResult()
elements = []

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)
)

def visit_FuncDefNode(self, node, context):


res = RTResult()

func_name = node.var_name_tok.value if node.var_name_tok else None


body_node = node.body_node
arg_names = [arg_name.value for arg_name in node.arg_name_toks]
func_value = Function(func_name, body_node, arg_names, node.should_auto_return).set_con

if node.var_name_tok:
context.symbol_table.set(func_name, func_value)

return res.success(func_value)

def visit_CallNode(self, node, context):


res = RTResult()
args = []

value_to_call = res.register(self.visit(node.node_to_call, context))


if res.should_return(): return res
value_to_call = value_to_call.copy().set_pos(node.pos_start, node.pos_end)

for arg_node in node.arg_nodes:


args.append(res.register(self.visit(arg_node, context)))
if res.should_return(): return res

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)

def visit_ContinueNode(self, node, context):


return RTResult().success_continue()

def visit_BreakNode(self, node, context):


return RTResult().success_break()

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)

def run(fn, text):


# Gerar Tokens
lexer = Lexer(fn, text)

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)

return result.value, result.error

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)

# Gerar linha por linhas


line_count = pos_end.ln - pos_start.ln + 1
for i in range(line_count):
# Calcularcolunas
line = text[idx_start:idx_end]
col_start = pos_start.col if i == 0 else 0
col_end = pos_end.col if i == line_count - 1 else len(line) - 1

# 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)

return result.replace(’\t’, ’’)

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))

18 Equivalˆencia entre a linguagem


Python e a linguagem objeto Basic.
Ambos Python e Basic s ˜a o linguagens que possuem o
mesmo obje- tivo principal, auxiliar novos programadores a
aprender os conceitos de c´odigo e programa¸c˜ao
Uma compara¸c˜ao t´ecnica entre as duas linguagens ´e a
forma de re- alizar o Print de um valor, como por exemplo:

EM BASIC:
PRINT ”Hello,
world!
END

EM PYTHON:
print(”Hello, World!”)

51

You might also like