languages_and_translators/final_lang/fort.py

427 lines
7.9 KiB
Python

import ply.lex as lex
import ply.yacc as yacc
import sys
from stack import Stack
resultQuadruplets = []
quadrupletIndex = 1
# Auxiliary stacks.
operandsStack = []
operatorsStack = []
jumpsStack = []
auxStack = []
avail = []
for i in range(50):
avail.append('T' + str(i))
# Operations related to the table of symbols
symbolsNames = []
symbolsTypes = []
symbols = {}
# # Implementation using lists.
# def addSymbol(name, symbolType):
# symbolsNames.append(name)
# symbolsTypes.append(symbolType)
# Implementation using a dictionary
def addSymbol(name, symbolType):
initialValue = 0 if symbolType == 'integer' else 0.0
symbols[name] = [symbolType, initialValue]
def peek(list):
if (len(list) == 0):
return None
return list[len(list) - 1]
tokens = [
'doubleColon',
'coma',
'openBra',
'closedBra',
'int',
'rea',
'parens',
'openParen',
'closedParen',
'string',
'plus',
'minus',
'mul',
'div',
'or',
'and',
'not',
'equals',
'doubleEquals',
'notEquals',
'less',
'more',
'lessEquals',
'moreEquals',
'id',
'program',
'end',
'read',
'print',
'if',
'then',
'else',
'elif',
'do',
'swap',
'exit',
'integer',
'real',
'subroutine',
]
reserved = {
'program' : 'program',
'end' : 'end',
'read' : 'read',
'print' : 'print',
'if' : 'if',
'then' : 'then',
'else' : 'else',
'elif' : 'elif',
'do' : 'do',
'swap' : 'swap',
'exit' : 'exit',
'integer' : 'integer',
'real' : 'real',
'subroutine' : 'subroutine',
}
t_doubleColon = r'::'
t_coma = r','
t_openBra = r'\['
t_closedBra = r'\]'
t_parens = r'\(\)'
t_openParen = r'\('
t_closedParen = r'\)'
t_plus = r'\+'
t_minus = r'-'
t_mul = r'\*'
t_string = r'\'[a-zA-Z0-9 \t\r\n\f()\[\]\&\!\@\#\$\%\^\-\=\+\/\,]*\''
t_or = r'\.or\.'
t_and = r'\.and\.'
t_not = r'\.not\.'
t_doubleEquals = r'\=\='
t_equals = r'\='
t_notEquals = r'\/\='
t_div = r'\/'
t_lessEquals = r'\<\='
t_less = r'\<'
t_moreEquals = r'\>\='
t_more = r'\>'
t_ignore = ' \t\r\n\f\v'
def t_rea(t):
r'\d+\.\d+'
t.value = float(t.value)
return t
def t_int(t):
r'\d+'
t.value = int(t.value)
return t
def t_id(t):
r'[a-zA-Z_][a-zA-Z_0-9]*'
if t.value in reserved:
t.type = reserved[ t.value ]
else:
t.type = 'id'
return t
def t_error(t):
print("Illegal character!")
print(t)
t.lexer.skip(1)
lexer = lex.lex()
def p_programa(p):
'''
programa : program id V F B end program
'''
print('+++ Valid program')
def p_V(p):
'''
V : V Tipo Dim doubleColon Rid
|
'''
# Adds all the variables for this production into the
# symbols table.
if (len(p) > 1):
for name in p[5]:
addSymbol(name, p[2])
def p_Rid(p):
'''
Rid : id
| Rid coma id
'''
# p[0] will contain an list with all the variable
# names for this production in string format.
if (len(p) == 2):
p[0] = [p[1]]
else:
p[0] = p[1] + [p[3]]
def p_Tipo(p):
'''
Tipo : integer
| real
'''
# p[0] will contain the type in string format
p[0] = p[1]
def p_Dim(p):
'''
Dim : openBra int closedBra
| openBra int closedBra openBra int closedBra
|
'''
def p_F(p):
'''
F : F subroutine id B end subroutine
|
'''
def p_B(p):
'''
B : B S
|
'''
def p_S(p):
'''
S : Dimensional action_7 equals EA action_8
| id parens
| read RDimensional
| print RDimOrString
| if Relif ElseOrEmpty end if
| do id equals EA coma EA IntOrEmpty then B end do
| do then B end do
| swap Dimensional coma Dimensional
| exit
'''
# Adjust the action to support matrices
def p_Dimensional(p):
'''
Dimensional : id DimensionsOrEmpty
'''
p[0] = p[1]
def p_DimensionsOrEmpty(p):
'''
DimensionsOrEmpty : openParen EA ComaEAOrEmpty closedParen
|
'''
def p_ComaEAOrEmpty(p):
'''
ComaEAOrEmpty : coma EA
|
'''
def p_RDimensional(p):
'''
RDimensional : Dimensional
| RDimensional coma Dimensional
'''
def p_RDimOrString(p):
'''
RDimOrString : DimOrString
| RDimOrString coma DimOrString
'''
def p_DimOrString(p):
'''
DimOrString : Dimensional
| string
'''
def p_Relif(p):
'''
Relif : openParen EL closedParen then B
| Relif elif openParen EL closedParen then B
'''
def p_ElseOrEmpty(p):
'''
ElseOrEmpty : else B
|
'''
def p_IntOrEmpty(p):
'''
IntOrEmpty : coma int
|
'''
def p_EA(p):
'''
EA : MultDiv
| EA SumOrSub action_3 MultDiv action_4
'''
def p_SumOrSub(p):
'''
SumOrSub : plus
| minus
'''
p[0] = p[1]
def p_MultDiv(p):
'''
MultDiv : EAParens
| MultDiv MDSymbols action_5 EAParens action_6
'''
def p_MDSymbols(p):
'''
MDSymbols : mul
| div
'''
p[0] = p[1]
def p_EAParens(p):
'''
EAParens : EItem
| openParen EA closedParen
'''
def p_EL(p):
'''
EL : AND
| EL or AND
'''
def p_AND(p):
'''
AND : Equality
| AND and Equality
'''
def p_Equality(p):
'''
Equality : EItem EQSymbols EItem
| openParen EL closedParen
| not EL
'''
def p_EItem(p):
'''
EItem : Dimensional action_1
| int action_2
| rea action_2
'''
def p_EQSymbols(p):
'''
EQSymbols : less
| more
| doubleEquals
| notEquals
| lessEquals
| moreEquals
'''
def p_action_1(p):
"action_1 :"
operandsStack.append(p[-1])
def p_action_2(p):
"action_2 :"
operandsStack.append(p[-1])
def p_action_3(p):
"action_3 :"
operatorsStack.append(p[-1])
def p_action_4(p):
"action_4 :"
if (peek(operatorsStack) == '+' or peek(operatorsStack) == '-'):
global quadrupletIndex
operator = operatorsStack.pop()
operand2 = operandsStack.pop()
operand1 = operandsStack.pop()
temp = avail.pop(0)
operandsStack.append(temp)
resultQuadruplets.append(str(operator) + ' ' + str(operand1) + ' ' + str(operand2) + ' ' + str(temp) + '\n')
quadrupletIndex += 1
def p_action_5(p):
"action_5 :"
operatorsStack.append(p[-1])
def p_action_6(p):
"action_6 :"
if (peek(operatorsStack) == '*' or peek(operatorsStack) == '/'):
global quadrupletIndex
operator = operatorsStack.pop()
operand2 = operandsStack.pop()
operand1 = operandsStack.pop()
temp = avail.pop(0)
operandsStack.append(temp)
resultQuadruplets.append(str(operator) + ' ' + str(operand1) + ' ' + str(operand2) + ' ' + str(temp) + '\n')
quadrupletIndex += 1
def p_action_7(p):
"action_7 :"
operandsStack.append(p[-1])
def p_action_8(p):
"action_8 :"
operand2 = operandsStack.pop()
operand1 = operandsStack.pop()
resultQuadruplets.append('= ' + str(operand2) + ' ' + str(operand1) + '\n')
def p_error(p):
print('XXX Invalid program')
print(p)
parser = yacc.yacc()
if (len(sys.argv) > 1):
programName = sys.argv[1]
programFile = open(programName, "r")
resultFile = open(programName + '.out', "w+")
# This is neccessary because the read method parses literal ends
# of lines as \\n instead of \n.
program = programFile.read().replace('\\n', '\n')
parser.parse(program)
print(resultQuadruplets)
print(symbols)
resultFile.writelines(resultQuadruplets)
# Close the files.
programFile.close()
resultFile.close()
else:
raise Exception('''
No file name was provided.
Please add the file name as a command line argument
Example: fort.py test.fort
''')