Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
4 views

Compilador Python para Basic

Uploaded by

guolri21
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views

Compilador Python para Basic

Uploaded by

guolri21
Copyright
© © All Rights Reserved
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