MPC/mpc.py
Nguyễn Anh Khoa d6be336a0c Refactor code
Change mpc.py to auto generate antlr4 files without having to run manualy. Also add a small command line ultility.
Remove commented import in others files, and update README
2018-12-18 01:06:36 +07:00

138 lines
3.5 KiB
Python

import os
import subprocess
import click
from antlr4 import FileStream, CommonTokenStream
from antlr4.error.ErrorListener import ConsoleErrorListener
from tools.genANTLR4 import generate, regenerate
try:
# dynamic loading of ANTLR4 files
from parser import MPLexer, MPParser # type: ignore
except ImportError:
generate()
from parser import MPLexer, MPParser # type: ignore
from astgen.ASTGeneration import ASTGeneration
from checker.StaticCheck import StaticChecker
from codegen.CodeGenerator import CodeGenerator
Lexer = MPLexer.MPLexer # load from module
Parser = MPParser.MPParser # load from module
ANTLR_JAR = os.environ.get('ANTLR_LIB')
JASMIN_JAR = './external/jasmin.jar'
if ANTLR_JAR is None:
# fall back, not recommended
ANTLR_JAR = './external/antrl4.jar'
class SyntaxException(Exception):
def __init__(self, msg):
self.message = msg
class NewErrorListener(ConsoleErrorListener):
INSTANCE = None
def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e):
raise SyntaxException(
"Error on line " +
str(line) +
" col " +
str(column) +
": " +
offendingSymbol.text)
def compile(inputfile, output):
lexer = Lexer(FileStream(inputfile))
tokens = CommonTokenStream(lexer)
try:
# listener = TestParser.createErrorListener()
listener = NewErrorListener().INSTANCE
parser = Parser(tokens)
parser.removeErrorListeners()
parser.addErrorListener(listener)
tree = parser.program()
except SyntaxException as f:
msg = f.message.split(':')[0].split(' ')
line = int(msg[3])
col = int(msg[5])
error_line = open(inputfile).read()
error_line = error_line.split('\n')[line - 1]
print(error_line)
print('~' * (col) + '^')
print(f.message)
raise f
asttree = ASTGeneration().visit(tree)
checker = StaticChecker(asttree)
checker.check()
path = output
filename = os.path.basename(inputfile).split('.')[0]
jasmin_file = '{}/{}.j'.format(path, filename)
codeGen = CodeGenerator()
codeGen.gen(asttree, path, filename)
subprocess.call(
"java -jar {} {} -d {}".format(JASMIN_JAR, jasmin_file, path),
shell=True,
stderr=subprocess.STDOUT
)
with open('{}/io.class'.format(path), 'wb') as iofile:
iofile.write(open('libs/io.class', 'rb').read())
subprocess.call(
'jar cvfe {0}.jar {0} io.class {0}.class'.format(
filename
),
cwd=path,
shell=True,
stderr=subprocess.STDOUT
)
os.remove(jasmin_file)
os.remove('{}/{}.class'.format(path, filename))
os.remove('{}/io.class'.format(path))
@click.command()
@click.argument('file')
@click.option(
'--output', default='',
help='Where the jar file will be after compile')
@click.option(
'--regen', is_flag=True,
help='Regenerate antlr4 files and exit'
)
def main(file, output, regen):
if regen:
regenerate()
print("ANTLR4 files regenerate succesfully")
return
if output == '':
output = os.path.dirname(file)
else:
# check if directory, create
# if file path, then
pass
print("Compiling {}".format(os.path.relpath(file)))
try:
compile(file, output)
except BaseException as e:
print(e)
exit(1)
print("Compiled successfully")
if __name__ == "__main__":
main()