init
This commit is contained in:
commit
bed5a47d55
611
.gitignore
vendored
Normal file
611
.gitignore
vendored
Normal file
@ -0,0 +1,611 @@
|
|||||||
|
|
||||||
|
# Created by https://www.gitignore.io/api/vim,python,eclipse,netbeans,sublimetext,visualstudio,visualstudiocode
|
||||||
|
# Edit at https://www.gitignore.io/?templates=vim,python,eclipse,netbeans,sublimetext,visualstudio,visualstudiocode
|
||||||
|
|
||||||
|
### Eclipse ###
|
||||||
|
|
||||||
|
.metadata
|
||||||
|
bin/
|
||||||
|
tmp/
|
||||||
|
*.tmp
|
||||||
|
*.bak
|
||||||
|
*.swp
|
||||||
|
*~.nib
|
||||||
|
local.properties
|
||||||
|
.settings/
|
||||||
|
.loadpath
|
||||||
|
.recommenders
|
||||||
|
|
||||||
|
# External tool builders
|
||||||
|
.externalToolBuilders/
|
||||||
|
|
||||||
|
# Locally stored "Eclipse launch configurations"
|
||||||
|
*.launch
|
||||||
|
|
||||||
|
# PyDev specific (Python IDE for Eclipse)
|
||||||
|
*.pydevproject
|
||||||
|
|
||||||
|
# CDT-specific (C/C++ Development Tooling)
|
||||||
|
.cproject
|
||||||
|
|
||||||
|
# CDT- autotools
|
||||||
|
.autotools
|
||||||
|
|
||||||
|
# Java annotation processor (APT)
|
||||||
|
.factorypath
|
||||||
|
|
||||||
|
# PDT-specific (PHP Development Tools)
|
||||||
|
.buildpath
|
||||||
|
|
||||||
|
# sbteclipse plugin
|
||||||
|
.target
|
||||||
|
|
||||||
|
# Tern plugin
|
||||||
|
.tern-project
|
||||||
|
|
||||||
|
# TeXlipse plugin
|
||||||
|
.texlipse
|
||||||
|
|
||||||
|
# STS (Spring Tool Suite)
|
||||||
|
.springBeans
|
||||||
|
|
||||||
|
# Code Recommenders
|
||||||
|
.recommenders/
|
||||||
|
|
||||||
|
# Annotation Processing
|
||||||
|
.apt_generated/
|
||||||
|
|
||||||
|
# Scala IDE specific (Scala & Java development for Eclipse)
|
||||||
|
.cache-main
|
||||||
|
.scala_dependencies
|
||||||
|
.worksheet
|
||||||
|
|
||||||
|
### Eclipse Patch ###
|
||||||
|
# Eclipse Core
|
||||||
|
.project
|
||||||
|
|
||||||
|
# JDT-specific (Eclipse Java Development Tools)
|
||||||
|
.classpath
|
||||||
|
|
||||||
|
# Annotation Processing
|
||||||
|
.apt_generated
|
||||||
|
|
||||||
|
.sts4-cache/
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
**/nbproject/private/
|
||||||
|
build/
|
||||||
|
nbbuild/
|
||||||
|
dist/
|
||||||
|
nbdist/
|
||||||
|
.nb-gradle/
|
||||||
|
|
||||||
|
### Python ###
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
develop-eggs/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# celery beat schedule file
|
||||||
|
celerybeat-schedule
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
### Python Patch ###
|
||||||
|
.venv/
|
||||||
|
|
||||||
|
### SublimeText ###
|
||||||
|
# Cache files for Sublime Text
|
||||||
|
*.tmlanguage.cache
|
||||||
|
*.tmPreferences.cache
|
||||||
|
*.stTheme.cache
|
||||||
|
|
||||||
|
# Workspace files are user-specific
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
|
# Project files should be checked into the repository, unless a significant
|
||||||
|
# proportion of contributors will probably not be using Sublime Text
|
||||||
|
# *.sublime-project
|
||||||
|
|
||||||
|
# SFTP configuration file
|
||||||
|
sftp-config.json
|
||||||
|
|
||||||
|
# Package control specific files
|
||||||
|
Package Control.last-run
|
||||||
|
Package Control.ca-list
|
||||||
|
Package Control.ca-bundle
|
||||||
|
Package Control.system-ca-bundle
|
||||||
|
Package Control.cache/
|
||||||
|
Package Control.ca-certs/
|
||||||
|
Package Control.merged-ca-bundle
|
||||||
|
Package Control.user-ca-bundle
|
||||||
|
oscrypto-ca-bundle.crt
|
||||||
|
bh_unicode_properties.cache
|
||||||
|
|
||||||
|
# Sublime-github package stores a github token in this file
|
||||||
|
# https://packagecontrol.io/packages/sublime-github
|
||||||
|
GitHub.sublime-settings
|
||||||
|
|
||||||
|
### Vim ###
|
||||||
|
# Swap
|
||||||
|
[._]*.s[a-v][a-z]
|
||||||
|
[._]*.sw[a-p]
|
||||||
|
[._]s[a-rt-v][a-z]
|
||||||
|
[._]ss[a-gi-z]
|
||||||
|
[._]sw[a-p]
|
||||||
|
|
||||||
|
# Session
|
||||||
|
Session.vim
|
||||||
|
|
||||||
|
# Temporary
|
||||||
|
.netrwhist
|
||||||
|
*~
|
||||||
|
# Auto-generated tag files
|
||||||
|
tags
|
||||||
|
# Persistent undo
|
||||||
|
[._]*.un~
|
||||||
|
|
||||||
|
### VisualStudioCode ###
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
|
||||||
|
### VisualStudioCode Patch ###
|
||||||
|
# Ignore all local history of files
|
||||||
|
.history
|
||||||
|
|
||||||
|
### VisualStudio ###
|
||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
##
|
||||||
|
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.rsuser
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Ll]og/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# Visual Studio 2017 auto generated files
|
||||||
|
Generated\ Files/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUNIT
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# JustCode is a .NET coding add-in
|
||||||
|
.JustCode
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/[Pp]ackages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/[Pp]ackages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/[Pp]ackages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
*.appx
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Including strong name files can present a security risk
|
||||||
|
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||||
|
#*.snk
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
# ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true
|
||||||
|
**/wwwroot/lib/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
ServiceFabricBackup/
|
||||||
|
*.rptproj.bak
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
*.rptproj.rsuser
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# JetBrains Rider
|
||||||
|
.idea/
|
||||||
|
*.sln.iml
|
||||||
|
|
||||||
|
# CodeRush personal settings
|
||||||
|
.cr/personal
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Tabs Studio
|
||||||
|
*.tss
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# OpenCover UI analysis results
|
||||||
|
OpenCover/
|
||||||
|
|
||||||
|
# Azure Stream Analytics local run output
|
||||||
|
ASALocalRun/
|
||||||
|
|
||||||
|
# MSBuild Binary and Structured Log
|
||||||
|
*.binlog
|
||||||
|
|
||||||
|
# NVidia Nsight GPU debugger configuration file
|
||||||
|
*.nvuser
|
||||||
|
|
||||||
|
# MFractors (Xamarin productivity tool) working folder
|
||||||
|
.mfractor/
|
||||||
|
|
||||||
|
# Local History for Visual Studio
|
||||||
|
.localhistory/
|
||||||
|
|
||||||
|
# End of https://www.gitignore.io/api/vim,python,eclipse,netbeans,sublimetext,visualstudio,visualstudiocode
|
||||||
|
|
||||||
|
|
||||||
|
**/.DS_Store
|
||||||
|
tests/
|
||||||
|
**/*.jar
|
||||||
|
**/*.mp
|
||||||
|
parser/.antlr4
|
||||||
|
parser/*.tokens
|
||||||
|
parser/*.interp
|
||||||
|
parser/MPLexer.py
|
||||||
|
parser/MPParser.py
|
||||||
|
parser/MPVisitor.py
|
36
README.md
Normal file
36
README.md
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# MP Compiler
|
||||||
|
|
||||||
|
From my Principle of Programming Languages assignment, I have created a compiler for the MP language. The assignment phase is divided to 4 phases, from doing Lexer, Parser, AST generation to Static Checker and Jasmin Code generation.
|
||||||
|
|
||||||
|
The assignment code structure is quite ugle, so I re-organized the code, adding some more steps to make the code look nicer and compile a \*.mp file to a jar file.
|
||||||
|
|
||||||
|
Given the mp file as follows:
|
||||||
|
|
||||||
|
```mp
|
||||||
|
// hello.mp
|
||||||
|
procedure main();
|
||||||
|
begin
|
||||||
|
putString("Hello World");
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
Compile and run the file by issuing these commands:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
python mpc.py hello.mp
|
||||||
|
java -jar hello.jar
|
||||||
|
```
|
||||||
|
|
||||||
|
More documentation is being built.
|
||||||
|
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
Because I was having serious deadlines at the end of the semester, I drop on working on ArrayCell, which will be added later.
|
||||||
|
|
||||||
|
Because the lexer and parser are given by the famous `ANTLR4` engine, there should exists a path to antlr4.jar on the environment variable `ANTLR_LIB` or else, the program will use the antlr4 file in the external folder.
|
||||||
|
|
||||||
|
Before running `mpc.py`, you must be sure that you have generate neccessary files from ANTLR4.
|
||||||
|
```shell
|
||||||
|
python genANTRL4.py
|
||||||
|
```
|
402
astgen/ASTGeneration.py
Normal file
402
astgen/ASTGeneration.py
Normal file
@ -0,0 +1,402 @@
|
|||||||
|
from parser.MPVisitor import MPVisitor
|
||||||
|
from parser.MPParser import MPParser
|
||||||
|
from functools import reduce
|
||||||
|
|
||||||
|
# * is not a good use case
|
||||||
|
from utils.AST import (
|
||||||
|
IntType,
|
||||||
|
FloatType,
|
||||||
|
BoolType,
|
||||||
|
StringType,
|
||||||
|
ArrayType,
|
||||||
|
# VoidType,
|
||||||
|
Program,
|
||||||
|
# Decl,
|
||||||
|
VarDecl,
|
||||||
|
FuncDecl,
|
||||||
|
# Stmt,
|
||||||
|
Assign,
|
||||||
|
If,
|
||||||
|
While,
|
||||||
|
For,
|
||||||
|
Break,
|
||||||
|
Continue,
|
||||||
|
Return,
|
||||||
|
With,
|
||||||
|
CallStmt,
|
||||||
|
# Expr,
|
||||||
|
BinaryOp,
|
||||||
|
UnaryOp,
|
||||||
|
CallExpr,
|
||||||
|
# LHS,
|
||||||
|
Id,
|
||||||
|
ArrayCell,
|
||||||
|
# Literal,
|
||||||
|
IntLiteral,
|
||||||
|
FloatLiteral,
|
||||||
|
StringLiteral,
|
||||||
|
BooleanLiteral
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def flatten(listOflist):
|
||||||
|
return reduce(lambda x, item: x + item, listOflist, [])
|
||||||
|
|
||||||
|
|
||||||
|
class ASTGeneration(MPVisitor):
|
||||||
|
def visitProgram(self, ctx: MPParser.ProgramContext):
|
||||||
|
"""
|
||||||
|
return Program(list of Decl)
|
||||||
|
where Decl:
|
||||||
|
+ VarDecl ==> var_decl
|
||||||
|
+ FuncDecl ==> func_decl
|
||||||
|
+ ProcDecl ==> proc_decl
|
||||||
|
"""
|
||||||
|
return Program(self.visit(ctx.manydecl()))
|
||||||
|
|
||||||
|
def visitManydecl(self, ctx: MPParser.ManydeclContext):
|
||||||
|
"""
|
||||||
|
return list of decl expanded
|
||||||
|
"""
|
||||||
|
decl = self.visit(ctx.decl())
|
||||||
|
if ctx.manydecl():
|
||||||
|
return decl + self.visit(ctx.manydecl())
|
||||||
|
else:
|
||||||
|
return decl
|
||||||
|
|
||||||
|
def visitDecl(self, ctx: MPParser.DeclContext):
|
||||||
|
"""
|
||||||
|
return either
|
||||||
|
+ var_decl
|
||||||
|
+ func_decl
|
||||||
|
+ proc_decl
|
||||||
|
"""
|
||||||
|
decl = self.visit(ctx.getChild(0))
|
||||||
|
if ctx.var_decl():
|
||||||
|
return decl
|
||||||
|
return [decl]
|
||||||
|
|
||||||
|
def visitVar_decl(self, ctx: MPParser.Var_declContext):
|
||||||
|
"""
|
||||||
|
return varlist
|
||||||
|
"""
|
||||||
|
return self.visit(ctx.varlist())
|
||||||
|
|
||||||
|
def visitVarlist(self, ctx: MPParser.VarlistContext):
|
||||||
|
"""
|
||||||
|
return list of VarDecl(iden, mptype)
|
||||||
|
"""
|
||||||
|
var = self.visit(ctx.var())
|
||||||
|
if ctx.varlist():
|
||||||
|
return var + self.visit(ctx.varlist())
|
||||||
|
else:
|
||||||
|
return var
|
||||||
|
|
||||||
|
def visitVar(self, ctx: MPParser.VarContext):
|
||||||
|
"""
|
||||||
|
return list of VarDecl(iden, mptype)
|
||||||
|
"""
|
||||||
|
mptype = self.visit(ctx.mptype())
|
||||||
|
idenlist = self.visit(ctx.idenlist())
|
||||||
|
|
||||||
|
# apply VarDecl(x, mptype) to idenlist where x is item in idenlist
|
||||||
|
def compose(f, arg):
|
||||||
|
def h(x):
|
||||||
|
return f(x, arg)
|
||||||
|
return h
|
||||||
|
hoo = compose(lambda x, y: VarDecl(x, y), mptype)
|
||||||
|
return list(map(hoo, idenlist))
|
||||||
|
|
||||||
|
def visitIdenlist(self, ctx: MPParser.IdenlistContext):
|
||||||
|
"""
|
||||||
|
return list of iden
|
||||||
|
"""
|
||||||
|
ident = Id(ctx.IDENT().getText())
|
||||||
|
if ctx.idenlist():
|
||||||
|
return [ident] + self.visit(ctx.idenlist())
|
||||||
|
else:
|
||||||
|
return [ident]
|
||||||
|
|
||||||
|
def visitMptype(self, ctx: MPParser.MptypeContext):
|
||||||
|
return self.visit(ctx.getChild(0))
|
||||||
|
|
||||||
|
def visitPrimitive_type(self, ctx: MPParser.Primitive_typeContext):
|
||||||
|
if ctx.INTEGER():
|
||||||
|
return IntType()
|
||||||
|
elif ctx.BOOLEAN():
|
||||||
|
return BoolType()
|
||||||
|
elif ctx.REAL():
|
||||||
|
return FloatType()
|
||||||
|
elif ctx.STRING():
|
||||||
|
return StringType()
|
||||||
|
|
||||||
|
def visitCompound_type(self, ctx: MPParser.Compound_typeContext):
|
||||||
|
"""
|
||||||
|
return ArrayType(low, high, type)
|
||||||
|
"""
|
||||||
|
low, high = self.visit(ctx.array_value())
|
||||||
|
pri_type = self.visit(ctx.primitive_type())
|
||||||
|
return ArrayType(low, high, pri_type)
|
||||||
|
|
||||||
|
def visitArray_value(self, ctx: MPParser.Array_valueContext):
|
||||||
|
"""
|
||||||
|
return low, high
|
||||||
|
"""
|
||||||
|
low = int(ctx.NUM_INT(0).getText())
|
||||||
|
high = int(ctx.NUM_INT(1).getText())
|
||||||
|
sub = len(ctx.MINUS())
|
||||||
|
if sub == 0:
|
||||||
|
pass
|
||||||
|
elif sub == 2:
|
||||||
|
low = -low
|
||||||
|
high = -high
|
||||||
|
elif ctx.getChild(1).getText() == '-':
|
||||||
|
low = -low
|
||||||
|
else:
|
||||||
|
high = -high
|
||||||
|
return low, high
|
||||||
|
|
||||||
|
def visitFunc_decl(self, ctx: MPParser.Func_declContext):
|
||||||
|
ident = Id(ctx.IDENT().getText())
|
||||||
|
param_list = self.visit(ctx.param_list()) if ctx.param_list() else []
|
||||||
|
mptype = self.visit(ctx.mptype())
|
||||||
|
var_decl = flatten(list(map(self.visit, ctx.var_decl())))
|
||||||
|
compound_statement = self.visit(ctx.compound_statement())
|
||||||
|
return FuncDecl(
|
||||||
|
ident,
|
||||||
|
param_list,
|
||||||
|
var_decl,
|
||||||
|
compound_statement,
|
||||||
|
mptype
|
||||||
|
)
|
||||||
|
|
||||||
|
def visitParam_list(self, ctx: MPParser.Param_listContext):
|
||||||
|
"""
|
||||||
|
return list of VarDecl(iden, mptype)
|
||||||
|
"""
|
||||||
|
var = self.visit(ctx.var())
|
||||||
|
# var is a list of VarDecl
|
||||||
|
if ctx.param_list():
|
||||||
|
# concat
|
||||||
|
return var + self.visit(ctx.param_list())
|
||||||
|
else:
|
||||||
|
# plain list return
|
||||||
|
return var
|
||||||
|
return
|
||||||
|
|
||||||
|
def visitProc_decl(self, ctx: MPParser.Proc_declContext):
|
||||||
|
ident = Id(ctx.IDENT().getText())
|
||||||
|
param_list = self.visit(ctx.param_list()) if ctx.param_list() else []
|
||||||
|
var_decl = flatten(list(map(self.visit, ctx.var_decl())))
|
||||||
|
compound_statement = self.visit(ctx.compound_statement())
|
||||||
|
return FuncDecl(
|
||||||
|
ident,
|
||||||
|
param_list,
|
||||||
|
var_decl,
|
||||||
|
compound_statement
|
||||||
|
)
|
||||||
|
|
||||||
|
def visitExpression(self, ctx: MPParser.ExpressionContext):
|
||||||
|
if ctx.getChildCount() == 1:
|
||||||
|
return self.visit(ctx.expression_lv1())
|
||||||
|
if ctx.AND():
|
||||||
|
op = "andthen"
|
||||||
|
else:
|
||||||
|
op = "orelse"
|
||||||
|
return BinaryOp(
|
||||||
|
op,
|
||||||
|
self.visit(ctx.expression()),
|
||||||
|
self.visit(ctx.expression_lv1())
|
||||||
|
)
|
||||||
|
|
||||||
|
def visitExpression_lv1(self, ctx: MPParser.Expression_lv1Context):
|
||||||
|
if ctx.getChildCount() == 1:
|
||||||
|
return self.visit(ctx.expression_lv2(0))
|
||||||
|
return BinaryOp(
|
||||||
|
ctx.getChild(1).getText(),
|
||||||
|
self.visit(ctx.expression_lv2(0)),
|
||||||
|
self.visit(ctx.expression_lv2(1))
|
||||||
|
)
|
||||||
|
|
||||||
|
def visitExpression_lv2(self, ctx: MPParser.Expression_lv2Context):
|
||||||
|
if ctx.getChildCount() == 1:
|
||||||
|
return self.visit(ctx.expression_lv3())
|
||||||
|
return BinaryOp(
|
||||||
|
ctx.getChild(1).getText(),
|
||||||
|
self.visit(ctx.expression_lv2()),
|
||||||
|
self.visit(ctx.expression_lv3())
|
||||||
|
)
|
||||||
|
|
||||||
|
def visitExpression_lv3(self, ctx: MPParser.Expression_lv3Context):
|
||||||
|
if ctx.getChildCount() == 1:
|
||||||
|
return self.visit(ctx.expression_lv4())
|
||||||
|
return BinaryOp(
|
||||||
|
ctx.getChild(1).getText(),
|
||||||
|
self.visit(ctx.expression_lv3()),
|
||||||
|
self.visit(ctx.expression_lv4())
|
||||||
|
)
|
||||||
|
|
||||||
|
def visitExpression_lv4(self, ctx: MPParser.Expression_lv4Context):
|
||||||
|
if ctx.getChildCount() == 1:
|
||||||
|
return self.visit(ctx.index_expression())
|
||||||
|
return UnaryOp(
|
||||||
|
ctx.getChild(0).getText(),
|
||||||
|
self.visit(ctx.expression_lv4())
|
||||||
|
)
|
||||||
|
|
||||||
|
def visitIndex_expression(self, ctx: MPParser.Index_expressionContext):
|
||||||
|
if ctx.getChildCount() == 1:
|
||||||
|
return self.visit(ctx.factor())
|
||||||
|
return ArrayCell(
|
||||||
|
self.visit(ctx.index_expression()),
|
||||||
|
self.visit(ctx.expression())
|
||||||
|
)
|
||||||
|
|
||||||
|
def visitInvocation_expression(
|
||||||
|
self, ctx: MPParser.Invocation_expressionContext):
|
||||||
|
if ctx.call_param():
|
||||||
|
return self.visit(ctx.call_param())
|
||||||
|
return []
|
||||||
|
|
||||||
|
def visitFactor(self, ctx: MPParser.FactorContext):
|
||||||
|
if ctx.expression():
|
||||||
|
return self.visit(ctx.expression())
|
||||||
|
elif ctx.invocation_expression():
|
||||||
|
return CallExpr(Id(ctx.IDENT().getText()),
|
||||||
|
self.visit(ctx.invocation_expression()))
|
||||||
|
elif ctx.literal():
|
||||||
|
return self.visit(ctx.literal())
|
||||||
|
elif ctx.IDENT():
|
||||||
|
return Id(ctx.IDENT().getText())
|
||||||
|
elif ctx.STRING_LITERAL():
|
||||||
|
return StringLiteral(ctx.STRING_LITERAL().getText())
|
||||||
|
return
|
||||||
|
|
||||||
|
def visitStatement(self, ctx: MPParser.StatementContext):
|
||||||
|
return self.visit(ctx.getChild(0))
|
||||||
|
|
||||||
|
def visitStructured_statement(
|
||||||
|
self, ctx: MPParser.Structured_statementContext):
|
||||||
|
if ctx.compound_statement():
|
||||||
|
return self.visit(ctx.getChild(0))
|
||||||
|
else:
|
||||||
|
return [self.visit(ctx.getChild(0))]
|
||||||
|
|
||||||
|
def visitNormal_statement(self, ctx: MPParser.Normal_statementContext):
|
||||||
|
if ctx.assignment_statement():
|
||||||
|
return self.visit(ctx.getChild(0))
|
||||||
|
else:
|
||||||
|
return [self.visit(ctx.getChild(0))]
|
||||||
|
|
||||||
|
def visitAssignment_statement(
|
||||||
|
self, ctx: MPParser.Assignment_statementContext):
|
||||||
|
"""
|
||||||
|
return list of Assign(lhs, exp)
|
||||||
|
"""
|
||||||
|
expression = self.visit(ctx.expression())
|
||||||
|
assignment_lhs_list = self.visit(ctx.assignment_lhs_list())
|
||||||
|
|
||||||
|
rhs_list = assignment_lhs_list[1:] + [expression]
|
||||||
|
|
||||||
|
# def compose(arg):
|
||||||
|
# def h(x):
|
||||||
|
# return Assign(x, arg)
|
||||||
|
# return h
|
||||||
|
# hoo = list(map(lambda x: compose(x), rhs_list))
|
||||||
|
return [Assign(lhs, rhs)
|
||||||
|
for lhs, rhs in zip(assignment_lhs_list, rhs_list)][::-1]
|
||||||
|
|
||||||
|
def visitAssignment_lhs_list(
|
||||||
|
self, ctx: MPParser.Assignment_lhs_listContext):
|
||||||
|
"""
|
||||||
|
return list of lhs
|
||||||
|
"""
|
||||||
|
lhs = self.visit(ctx.lhs())
|
||||||
|
if ctx.assignment_lhs_list():
|
||||||
|
return [lhs] + self.visit(ctx.assignment_lhs_list())
|
||||||
|
else:
|
||||||
|
return [lhs]
|
||||||
|
|
||||||
|
def visitLhs(self, ctx: MPParser.LhsContext):
|
||||||
|
"""
|
||||||
|
return IDENT or index_pression
|
||||||
|
"""
|
||||||
|
if ctx.IDENT():
|
||||||
|
return Id(ctx.IDENT().getText())
|
||||||
|
else:
|
||||||
|
return self.visit(ctx.index_expression())
|
||||||
|
|
||||||
|
def visitIf_statement(self, ctx: MPParser.If_statementContext):
|
||||||
|
expression = self.visit(ctx.expression())
|
||||||
|
if ctx.ELSE():
|
||||||
|
then_statement = self.visit(ctx.statement(0))
|
||||||
|
else_statement = self.visit(ctx.statement(1))
|
||||||
|
return If(expression, then_statement, else_statement)
|
||||||
|
else:
|
||||||
|
then_statement = self.visit(ctx.statement(0))
|
||||||
|
return If(expression, then_statement)
|
||||||
|
|
||||||
|
def visitWhile_statement(self, ctx: MPParser.While_statementContext):
|
||||||
|
return While(self.visit(ctx.expression()), self.visit(ctx.statement()))
|
||||||
|
|
||||||
|
def visitFor_statement(self, ctx: MPParser.For_statementContext):
|
||||||
|
up = True if ctx.TO() else False
|
||||||
|
return For(
|
||||||
|
Id(ctx.IDENT().getText()),
|
||||||
|
self.visit(ctx.expression(0)),
|
||||||
|
self.visit(ctx.expression(1)),
|
||||||
|
up,
|
||||||
|
self.visit(ctx.statement()))
|
||||||
|
|
||||||
|
def visitBreak_statement(self, ctx: MPParser.Break_statementContext):
|
||||||
|
return Break()
|
||||||
|
|
||||||
|
def visitContinue_statement(self, ctx: MPParser.Continue_statementContext):
|
||||||
|
return Continue()
|
||||||
|
|
||||||
|
def visitReturn_statement(self, ctx: MPParser.Return_statementContext):
|
||||||
|
if ctx.expression():
|
||||||
|
return Return(self.visit(ctx.expression()))
|
||||||
|
else:
|
||||||
|
return Return()
|
||||||
|
|
||||||
|
def visitCompound_statement(self, ctx: MPParser.Compound_statementContext):
|
||||||
|
if ctx.statement():
|
||||||
|
return flatten(list(map(self.visit, ctx.statement())))
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
|
||||||
|
def visitWith_statement(self, ctx: MPParser.With_statementContext):
|
||||||
|
return With(self.visit(ctx.varlist()), self.visit(ctx.statement()))
|
||||||
|
|
||||||
|
def visitCall_statement(self, ctx: MPParser.Call_statementContext):
|
||||||
|
param = self.visit(ctx.call_param()) if ctx.call_param() else []
|
||||||
|
return CallStmt(Id(ctx.IDENT().getText()), param)
|
||||||
|
|
||||||
|
def visitCall_param(self, ctx: MPParser.Call_paramContext):
|
||||||
|
expression = self.visit(ctx.expression())
|
||||||
|
if ctx.call_param():
|
||||||
|
return [expression] + self.visit(ctx.call_param())
|
||||||
|
else:
|
||||||
|
return [expression]
|
||||||
|
|
||||||
|
def visitEmpty(self, ctx: MPParser.EmptyContext):
|
||||||
|
return
|
||||||
|
|
||||||
|
def visitLiteral(self, ctx: MPParser.LiteralContext):
|
||||||
|
if ctx.number():
|
||||||
|
return self.visit(ctx.number())
|
||||||
|
elif ctx.BOOL_LIT():
|
||||||
|
if ctx.BOOL_LIT().getText().lower() == 'true':
|
||||||
|
return BooleanLiteral(True)
|
||||||
|
else:
|
||||||
|
return BooleanLiteral(False)
|
||||||
|
elif ctx.STRING_LITERAL():
|
||||||
|
return StringLiteral(ctx.STRING_LITERAL().getText())
|
||||||
|
return
|
||||||
|
|
||||||
|
def visitNumber(self, ctx: MPParser.NumberContext):
|
||||||
|
if ctx.NUM_INT():
|
||||||
|
return IntLiteral(int(ctx.NUM_INT().getText()))
|
||||||
|
elif ctx.NUM_REAL():
|
||||||
|
return FloatLiteral(float(ctx.NUM_REAL().getText()))
|
0
astgen/__init__.py
Normal file
0
astgen/__init__.py
Normal file
778
checker/StaticCheck.py
Normal file
778
checker/StaticCheck.py
Normal file
@ -0,0 +1,778 @@
|
|||||||
|
from utils.Visitor import BaseVisitor
|
||||||
|
from utils.Utils import Utils
|
||||||
|
from checker.StaticError import (
|
||||||
|
# Kind,
|
||||||
|
Function,
|
||||||
|
Procedure,
|
||||||
|
Variable,
|
||||||
|
Parameter,
|
||||||
|
Identifier,
|
||||||
|
# StaticError,
|
||||||
|
Undeclared,
|
||||||
|
Redeclared,
|
||||||
|
TypeMismatchInExpression,
|
||||||
|
TypeMismatchInStatement,
|
||||||
|
FunctionNotReturn,
|
||||||
|
BreakNotInLoop,
|
||||||
|
ContinueNotInLoop,
|
||||||
|
NoEntryPoint,
|
||||||
|
UnreachableStatement,
|
||||||
|
Unreachable
|
||||||
|
)
|
||||||
|
from utils.AST import (
|
||||||
|
IntType,
|
||||||
|
FloatType,
|
||||||
|
BoolType,
|
||||||
|
StringType,
|
||||||
|
ArrayType,
|
||||||
|
VoidType,
|
||||||
|
# Program,
|
||||||
|
# Decl,
|
||||||
|
# VarDecl,
|
||||||
|
FuncDecl,
|
||||||
|
# Stmt,
|
||||||
|
# Assign,
|
||||||
|
# If,
|
||||||
|
# While,
|
||||||
|
# For,
|
||||||
|
# Break,
|
||||||
|
# Continue,
|
||||||
|
# Return,
|
||||||
|
# With,
|
||||||
|
# CallStmt,
|
||||||
|
# Expr,
|
||||||
|
# BinaryOp,
|
||||||
|
# UnaryOp,
|
||||||
|
CallExpr,
|
||||||
|
# LHS,
|
||||||
|
# Id,
|
||||||
|
# ArrayCell,
|
||||||
|
# Literal,
|
||||||
|
# IntLiteral,
|
||||||
|
# FloatLiteral,
|
||||||
|
# StringLiteral,
|
||||||
|
# BooleanLiteral
|
||||||
|
)
|
||||||
|
from functools import reduce
|
||||||
|
|
||||||
|
|
||||||
|
class MType:
|
||||||
|
def __init__(self, partype, rettype):
|
||||||
|
self.partype = partype
|
||||||
|
self.rettype = rettype
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'MType([{}],{})'.format(
|
||||||
|
','.join([str(x) for x in self.partype]),
|
||||||
|
str(self.rettype)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Symbol:
|
||||||
|
def __init__(self, name, mtype, value=0):
|
||||||
|
self.name = name
|
||||||
|
self.mtype = mtype
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Symbol({},{})'.format(
|
||||||
|
self.name,
|
||||||
|
str(self.mtype)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# DEBUG = True
|
||||||
|
DEBUG = False
|
||||||
|
|
||||||
|
|
||||||
|
def printEnv(env, stop=False):
|
||||||
|
if not DEBUG:
|
||||||
|
return
|
||||||
|
if stop:
|
||||||
|
try:
|
||||||
|
input(','.join([str(e) for e in env]))
|
||||||
|
except EOFError:
|
||||||
|
print(','.join([str(e) for e in env]))
|
||||||
|
else:
|
||||||
|
print(','.join([str(e) for e in env]))
|
||||||
|
|
||||||
|
|
||||||
|
def printDebug(desc, **kwargs):
|
||||||
|
if not DEBUG:
|
||||||
|
return
|
||||||
|
|
||||||
|
print(desc)
|
||||||
|
|
||||||
|
if 'env' in kwargs:
|
||||||
|
if 'stop' in kwargs:
|
||||||
|
printEnv(kwargs['env'], kwargs['stop'])
|
||||||
|
else:
|
||||||
|
printEnv(kwargs['env'])
|
||||||
|
|
||||||
|
|
||||||
|
class StaticChecker(BaseVisitor, Utils):
|
||||||
|
|
||||||
|
global_envi = [
|
||||||
|
# from specification, section 7: Built-in Functions/Procedures
|
||||||
|
Symbol("getInt", MType([], IntType())),
|
||||||
|
Symbol("putInt", MType([IntType()], VoidType())),
|
||||||
|
Symbol("putIntLn", MType([IntType()], VoidType())),
|
||||||
|
Symbol("getFloat", MType([], FloatType())),
|
||||||
|
Symbol("putFloat", MType([FloatType()], VoidType())),
|
||||||
|
Symbol("putFloatLn", MType([FloatType()], VoidType())),
|
||||||
|
Symbol("putBool", MType([BoolType()], VoidType())),
|
||||||
|
Symbol("putBoolLn", MType([BoolType()], VoidType())),
|
||||||
|
Symbol("putString", MType([StringType()], VoidType())),
|
||||||
|
Symbol("putStringLn", MType([StringType()], VoidType())),
|
||||||
|
Symbol("putLn", MType([], VoidType()))
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, ast):
|
||||||
|
self.ast = ast
|
||||||
|
|
||||||
|
def check(self):
|
||||||
|
return self.visit(self.ast, StaticChecker.global_envi)
|
||||||
|
|
||||||
|
def checkRedeclared(self, symbol, kind, env):
|
||||||
|
res = self.lookup(symbol.name.lower(), env, lambda e: e.name.lower())
|
||||||
|
if res is not None:
|
||||||
|
raise Redeclared(kind, symbol.name)
|
||||||
|
|
||||||
|
def mergeGlobal2Local(self, local_scope, global_scope):
|
||||||
|
for s in global_scope:
|
||||||
|
res = self.lookup(s.name, local_scope, lambda e: e.name.lower())
|
||||||
|
if res is None:
|
||||||
|
local_scope.append(s)
|
||||||
|
|
||||||
|
def checkTypeCompatibility(self, lhs, rhs, error):
|
||||||
|
# array check
|
||||||
|
if isinstance(lhs, ArrayType):
|
||||||
|
if not isinstance(rhs, ArrayType):
|
||||||
|
raise error
|
||||||
|
if lhs.lower != rhs.lower or \
|
||||||
|
lhs.upper != rhs.upper:
|
||||||
|
raise error
|
||||||
|
# self.checkTypeCompatibility(lhs.eleType, rhs.eleType, error)
|
||||||
|
if not isinstance(lhs.eleType, type(rhs.eleType)):
|
||||||
|
raise error
|
||||||
|
|
||||||
|
# float/int coersion
|
||||||
|
elif isinstance(lhs, FloatType):
|
||||||
|
if not isinstance(rhs, (IntType, FloatType)):
|
||||||
|
raise error
|
||||||
|
|
||||||
|
# else
|
||||||
|
elif not isinstance(lhs, type(rhs)):
|
||||||
|
raise error
|
||||||
|
|
||||||
|
def callBody(self, ast, env):
|
||||||
|
'''
|
||||||
|
ast: CallStmt | CallExpr
|
||||||
|
env: List[Symbol]
|
||||||
|
raise TypeMismatchInStatement | TypeMismatchInExpression
|
||||||
|
=> Type: MType
|
||||||
|
; Used by CallStmt and CallExpr
|
||||||
|
; Both have exact structure difference only on
|
||||||
|
; Raising Error and Kind Expectation
|
||||||
|
'''
|
||||||
|
callParam = [self.visit(x, env) for x in ast.param]
|
||||||
|
mtype = self.visit( # visits Id
|
||||||
|
ast.method,
|
||||||
|
{
|
||||||
|
'env': env,
|
||||||
|
'kind': Function() if isinstance(ast, CallExpr) \
|
||||||
|
else Procedure(),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
rightParam = mtype.partype
|
||||||
|
|
||||||
|
# lazy init of Error
|
||||||
|
error = TypeMismatchInExpression if isinstance(ast, CallExpr) \
|
||||||
|
else TypeMismatchInStatement
|
||||||
|
|
||||||
|
if len(rightParam) != len(callParam):
|
||||||
|
raise error(ast)
|
||||||
|
|
||||||
|
# LHS’s are formal parameters and RHS’s are arguments
|
||||||
|
for pair in zip(rightParam, callParam):
|
||||||
|
lhs = pair[0]
|
||||||
|
rhs = pair[1]
|
||||||
|
|
||||||
|
self.checkTypeCompatibility(lhs, rhs, error(ast))
|
||||||
|
|
||||||
|
return mtype.rettype
|
||||||
|
|
||||||
|
def loopBody(self, stmts, param):
|
||||||
|
'''
|
||||||
|
stmt: List[Statement]
|
||||||
|
param: {
|
||||||
|
'env': List[Symbol],
|
||||||
|
'inloop': Bool,
|
||||||
|
'rettype': Type
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
env = param['env']
|
||||||
|
rettype = param['rettype']
|
||||||
|
|
||||||
|
outFlag = False
|
||||||
|
for stmt in stmts:
|
||||||
|
if outFlag:
|
||||||
|
raise UnreachableStatement(stmt)
|
||||||
|
if self.visit(
|
||||||
|
stmt, {
|
||||||
|
'env': env, 'inloop': True, 'rettype': rettype
|
||||||
|
}
|
||||||
|
):
|
||||||
|
outFlag = True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def processStatement(self, stmts, param):
|
||||||
|
returnFlag = False
|
||||||
|
for stmt in stmts:
|
||||||
|
if returnFlag:
|
||||||
|
raise UnreachableStatement(stmt)
|
||||||
|
if self.visit(stmt, param):
|
||||||
|
returnFlag = True
|
||||||
|
return returnFlag
|
||||||
|
|
||||||
|
def visitProgram(self, ast, env):
|
||||||
|
printDebug("======SCAN PROGRAM======")
|
||||||
|
global_scope = reduce(
|
||||||
|
lambda returnList, decl:
|
||||||
|
[self.visit(
|
||||||
|
decl,
|
||||||
|
{'env': returnList, 'scan': False}
|
||||||
|
)] + returnList,
|
||||||
|
ast.decl,
|
||||||
|
env[:]
|
||||||
|
)
|
||||||
|
printDebug("======GLOBAL======", env=global_scope)
|
||||||
|
|
||||||
|
if not any(map(
|
||||||
|
lambda symbol: isinstance(
|
||||||
|
symbol.mtype,
|
||||||
|
MType) and symbol.name.lower() == 'main' and isinstance(
|
||||||
|
symbol.mtype.rettype,
|
||||||
|
VoidType) and len(symbol.mtype.partype) == 0,
|
||||||
|
global_scope)):
|
||||||
|
raise NoEntryPoint()
|
||||||
|
|
||||||
|
funcs = filter(lambda x: isinstance(x, FuncDecl), ast.decl)
|
||||||
|
for func in funcs:
|
||||||
|
self.visit(func, {'env': global_scope, 'scan': True})
|
||||||
|
|
||||||
|
for symbol in global_scope:
|
||||||
|
if not isinstance(symbol.mtype, MType):
|
||||||
|
continue
|
||||||
|
if symbol.name.lower() == 'main' and \
|
||||||
|
isinstance(symbol.mtype.rettype, VoidType):
|
||||||
|
continue
|
||||||
|
if symbol.value == 0:
|
||||||
|
if symbol in env:
|
||||||
|
continue
|
||||||
|
raise Unreachable(
|
||||||
|
Procedure() if isinstance(symbol.mtype.rettype, VoidType)
|
||||||
|
else Function(),
|
||||||
|
symbol.name)
|
||||||
|
|
||||||
|
return global_scope
|
||||||
|
|
||||||
|
def visitFuncDecl(self, ast, param):
|
||||||
|
'''
|
||||||
|
ast: FuncDecl
|
||||||
|
param: {
|
||||||
|
env: List[Symbol], # Global Reference Environment
|
||||||
|
scan: Bool
|
||||||
|
}
|
||||||
|
raise Redeclared(Parameter)
|
||||||
|
raise Redeclared(Variable)
|
||||||
|
raise UnreachableStatement
|
||||||
|
raise FunctionNotReturn
|
||||||
|
=> Symbol if not scan else None
|
||||||
|
'''
|
||||||
|
env = param['env']
|
||||||
|
scan = param['scan']
|
||||||
|
if not scan:
|
||||||
|
printDebug("FUNCDECL", env=env, stop=False)
|
||||||
|
s = Symbol(
|
||||||
|
ast.name.name,
|
||||||
|
MType(
|
||||||
|
[x.varType for x in ast.param],
|
||||||
|
ast.returnType
|
||||||
|
))
|
||||||
|
|
||||||
|
kind = Procedure() if isinstance(ast.returnType, VoidType) \
|
||||||
|
else Function()
|
||||||
|
self.checkRedeclared(s, kind, env)
|
||||||
|
return s
|
||||||
|
else:
|
||||||
|
printDebug("========SCAN FUNC========")
|
||||||
|
printDebug(str(ast))
|
||||||
|
|
||||||
|
try:
|
||||||
|
# visits VarDecl -- throws Redeclared(Variable)
|
||||||
|
parameter = reduce(
|
||||||
|
lambda scope, vardecl:
|
||||||
|
[self.visit(vardecl, {'env': scope})] + scope,
|
||||||
|
ast.param,
|
||||||
|
# env[:] # copy
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
except Redeclared as e:
|
||||||
|
raise Redeclared(Parameter(), e.n)
|
||||||
|
printDebug("PARAM", env=parameter)
|
||||||
|
|
||||||
|
# visits VarDecl -- throws Redeclared(Variable)
|
||||||
|
local_scope = reduce(
|
||||||
|
lambda scope, vardecl:
|
||||||
|
[self.visit(vardecl, {'env': scope})] + scope,
|
||||||
|
ast.local,
|
||||||
|
parameter # for safety reason, copy
|
||||||
|
)
|
||||||
|
printDebug("LOCAL_VAR", env=local_scope)
|
||||||
|
# self.mergeGlobal2Local(local_scope, env)
|
||||||
|
local_scope += env
|
||||||
|
printDebug("LOCAL_ENV", env=local_scope, stop=False)
|
||||||
|
|
||||||
|
# check in body
|
||||||
|
if not self.processStatement(
|
||||||
|
ast.body,
|
||||||
|
{
|
||||||
|
'env': local_scope,
|
||||||
|
'inloop': False,
|
||||||
|
'rettype': ast.returnType
|
||||||
|
}) and not isinstance(ast.returnType, VoidType):
|
||||||
|
raise FunctionNotReturn(ast.name.name)
|
||||||
|
|
||||||
|
def visitVarDecl(self, ast, param):
|
||||||
|
'''
|
||||||
|
ast: VarDecl
|
||||||
|
param: {
|
||||||
|
env: List[Symbol]
|
||||||
|
~~scan: Bool~~ # ignore
|
||||||
|
}
|
||||||
|
=> Symbol
|
||||||
|
'''
|
||||||
|
# print(param, file=sys.stderr)
|
||||||
|
env = param['env']
|
||||||
|
printDebug("VARDECL", env=env, stop=False)
|
||||||
|
|
||||||
|
s = Symbol(
|
||||||
|
ast.variable.name,
|
||||||
|
ast.varType
|
||||||
|
)
|
||||||
|
|
||||||
|
self.checkRedeclared(s, Variable(), env)
|
||||||
|
|
||||||
|
return s
|
||||||
|
|
||||||
|
def visitIntType(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitFloatType(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitBoolType(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitStringType(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitVoidType(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitArrayType(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitBinaryOp(self, ast, param):
|
||||||
|
'''
|
||||||
|
ast: BinaryOp
|
||||||
|
param: list[Symbol]
|
||||||
|
raise TypeMismatchInExpression
|
||||||
|
(/) --> Float/Int:Float/Int => Float
|
||||||
|
(+,-,*) --> Float:Float/Int => Float
|
||||||
|
--> Float/Int:Float => Float
|
||||||
|
--> Int:Int => Int
|
||||||
|
(div,mod) --> Int:Int => Int
|
||||||
|
(<,<=,=,>=,>,<>) --> Float:Float/Int => Bool
|
||||||
|
--> Float/Int:Float => Bool
|
||||||
|
--> Int:Int => Bool
|
||||||
|
(and,or,andthen,orelse) --> Bool:Bool => Bool
|
||||||
|
=> Type
|
||||||
|
'''
|
||||||
|
op = ast.op.lower()
|
||||||
|
# visits (Id, BinaryOp, UnaryOp, CallExpr, ArrayCell)
|
||||||
|
left_type = self.visit(ast.left, param)
|
||||||
|
right_type = self.visit(ast.right, param)
|
||||||
|
|
||||||
|
def deferType(acceptableTypes, returnType=None):
|
||||||
|
if not isinstance(left_type, acceptableTypes):
|
||||||
|
raise TypeMismatchInExpression(ast)
|
||||||
|
if not isinstance(right_type, acceptableTypes):
|
||||||
|
raise TypeMismatchInExpression(ast)
|
||||||
|
|
||||||
|
if returnType is not None:
|
||||||
|
return returnType
|
||||||
|
if isinstance(left_type, FloatType) or \
|
||||||
|
isinstance(right_type, FloatType):
|
||||||
|
return FloatType()
|
||||||
|
if isinstance(left_type, type(right_type)):
|
||||||
|
return left_type
|
||||||
|
|
||||||
|
raise TypeMismatchInExpression(ast)
|
||||||
|
|
||||||
|
if op in ('and', 'or', 'andthen', 'orelse'):
|
||||||
|
return deferType((BoolType), BoolType())
|
||||||
|
|
||||||
|
if op in ('div', 'mod'):
|
||||||
|
return deferType((IntType), IntType())
|
||||||
|
|
||||||
|
if op in ('+', '-', '*'):
|
||||||
|
return deferType((IntType, FloatType))
|
||||||
|
|
||||||
|
if op in ('/'):
|
||||||
|
return deferType((IntType, FloatType), FloatType())
|
||||||
|
|
||||||
|
if op in ('<', '<=', '=', '>=', '>', '<>'):
|
||||||
|
return deferType((IntType, FloatType), BoolType())
|
||||||
|
|
||||||
|
def visitUnaryOp(self, ast, param):
|
||||||
|
'''
|
||||||
|
ast: UnaryOp
|
||||||
|
param: List[Symbol]
|
||||||
|
raise TypeMismatchInExpression
|
||||||
|
not Bool => Bool
|
||||||
|
- Int => Int
|
||||||
|
- Float => Float
|
||||||
|
=> Type
|
||||||
|
'''
|
||||||
|
op = ast.op.lower()
|
||||||
|
expr = self.visit(ast.body, param)
|
||||||
|
|
||||||
|
if op in ('not'):
|
||||||
|
if not isinstance(expr, BoolType):
|
||||||
|
raise TypeMismatchInExpression(ast)
|
||||||
|
return BoolType()
|
||||||
|
|
||||||
|
if op in ('-'):
|
||||||
|
if not isinstance(expr, (IntType, FloatType)):
|
||||||
|
raise TypeMismatchInExpression(ast)
|
||||||
|
return expr
|
||||||
|
|
||||||
|
def visitCallExpr(self, ast, env):
|
||||||
|
'''
|
||||||
|
ast: CallExpr ~ CallStmt
|
||||||
|
env: list[Symbol]
|
||||||
|
raise Undeclared(Function)
|
||||||
|
raise TypeMismatchInExpression
|
||||||
|
wrong param size
|
||||||
|
wrong param type
|
||||||
|
Array[n..m] of X --> Array[n..m] of X
|
||||||
|
Float --> Float/Int
|
||||||
|
X --> X
|
||||||
|
=> Type
|
||||||
|
'''
|
||||||
|
return self.callBody(ast, env)
|
||||||
|
|
||||||
|
def visitId(self, ast, param):
|
||||||
|
'''
|
||||||
|
ast: Id
|
||||||
|
param: List[Symbol] or {
|
||||||
|
'env': List[Symbol]
|
||||||
|
'kind': kind expectation
|
||||||
|
}
|
||||||
|
raise Undeclared
|
||||||
|
=> Type: Symbol.mtype
|
||||||
|
'''
|
||||||
|
env = param['env'] if not isinstance(param, list) else param
|
||||||
|
kind = param['kind'] if not isinstance(param, list) else Identifier()
|
||||||
|
|
||||||
|
# type(res) == Symbol
|
||||||
|
# printDebug("ID", env=env, stop=False)
|
||||||
|
res = self.lookup(ast.name.lower(), env, lambda e: e.name.lower())
|
||||||
|
|
||||||
|
if res is None:
|
||||||
|
raise Undeclared(kind, ast.name)
|
||||||
|
|
||||||
|
if isinstance(kind, Identifier):
|
||||||
|
if isinstance(res.mtype, MType):
|
||||||
|
raise Undeclared(kind, ast.name)
|
||||||
|
return res.mtype
|
||||||
|
|
||||||
|
# param is dict
|
||||||
|
if isinstance(kind, Function) or isinstance(kind, Procedure):
|
||||||
|
# check if mtype -- aka function
|
||||||
|
if not isinstance(res.mtype, MType):
|
||||||
|
raise Undeclared(kind, ast.name)
|
||||||
|
|
||||||
|
if isinstance(kind, Function):
|
||||||
|
if isinstance(res.mtype.rettype, VoidType):
|
||||||
|
raise Undeclared(kind, ast.name)
|
||||||
|
res.value += 1
|
||||||
|
|
||||||
|
elif isinstance(kind, Procedure):
|
||||||
|
if not isinstance(res.mtype.rettype, VoidType):
|
||||||
|
raise Undeclared(kind, ast.name)
|
||||||
|
res.value += 1
|
||||||
|
return res.mtype
|
||||||
|
|
||||||
|
def visitArrayCell(self, ast, param):
|
||||||
|
'''
|
||||||
|
ast: ArrayCell
|
||||||
|
param: List[Symbol]
|
||||||
|
raise TypeMismatchInExpression
|
||||||
|
arr[idx] --> ArrayType[IntType] => ArrayType.eleType
|
||||||
|
=> Type
|
||||||
|
'''
|
||||||
|
arr = self.visit(ast.arr, param)
|
||||||
|
idx = self.visit(ast.idx, param)
|
||||||
|
|
||||||
|
if not isinstance(idx, IntType) or \
|
||||||
|
not isinstance(arr, ArrayType):
|
||||||
|
raise TypeMismatchInExpression(ast)
|
||||||
|
|
||||||
|
return arr.eleType
|
||||||
|
|
||||||
|
'''
|
||||||
|
Statements are passed with a dict() with simple params:
|
||||||
|
env: List[Symbol] # local referencing environment
|
||||||
|
inloop: Bool # in loop flag
|
||||||
|
rettype: Type # return type of function/procedure
|
||||||
|
Simple statements deal only with 'env',
|
||||||
|
Continue/Break statements use 'inloop' to check for non in loop call
|
||||||
|
Return statements use 'rettype' to check for type compatibility when return
|
||||||
|
|
||||||
|
Function/Procedure statements pass all these params,
|
||||||
|
For/While statements pass inloop as True when processing loop statements
|
||||||
|
while preserving 'rettype
|
||||||
|
If statements pass param to then/else statements
|
||||||
|
With statements ...
|
||||||
|
|
||||||
|
All other statements uses param as read only
|
||||||
|
|
||||||
|
Return of statements are the status of the function/procedure whether
|
||||||
|
it has returned or not
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
procedure main();
|
||||||
|
begin
|
||||||
|
if (n and mask) then
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
the corresponding AST Tree will be:
|
||||||
|
Program([
|
||||||
|
FuncDecl(Id(main),[],VoidType(),[],[
|
||||||
|
If(BinaryOp(and,Id(n),Id(mask)),[
|
||||||
|
Return(Some(IntLiteral(1)))
|
||||||
|
],[
|
||||||
|
Return(Some(IntLiteral(0)))
|
||||||
|
])
|
||||||
|
])
|
||||||
|
])
|
||||||
|
|
||||||
|
The If in AST will return True as both of the branch returns.
|
||||||
|
There is no else if statement, but this algorithm works as
|
||||||
|
expect that in if statement, all branch returns means the function is ended
|
||||||
|
|
||||||
|
The same logic can also be applied to for/while/with statements
|
||||||
|
'''
|
||||||
|
|
||||||
|
def visitAssign(self, ast, param):
|
||||||
|
'''
|
||||||
|
ast: Assign
|
||||||
|
param: {
|
||||||
|
'env': List[Symbol]
|
||||||
|
'inloop': Bool
|
||||||
|
}
|
||||||
|
raise TypeMismatchInStatement
|
||||||
|
Float := Float/Int
|
||||||
|
Int := Int
|
||||||
|
Bool := Bool
|
||||||
|
// no String, Array
|
||||||
|
=> Returned?
|
||||||
|
'''
|
||||||
|
env = param['env']
|
||||||
|
left_type = self.visit(ast.lhs, env)
|
||||||
|
right_type = self.visit(ast.exp, env)
|
||||||
|
|
||||||
|
if isinstance(left_type, (StringType, ArrayType)):
|
||||||
|
raise TypeMismatchInStatement(ast)
|
||||||
|
|
||||||
|
self.checkTypeCompatibility(
|
||||||
|
left_type, right_type, TypeMismatchInStatement(ast))
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def visitWith(self, ast, param):
|
||||||
|
'''
|
||||||
|
ast: With
|
||||||
|
param: {
|
||||||
|
'env': List[Symbol],
|
||||||
|
'inloop': Bool,
|
||||||
|
'rettype': Type
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
env = param['env']
|
||||||
|
|
||||||
|
with_scope = reduce(
|
||||||
|
lambda with_scope, decl:
|
||||||
|
[self.visit(decl, {'env': with_scope})] + with_scope,
|
||||||
|
ast.decl,
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
with_scope += env
|
||||||
|
|
||||||
|
return self.processStatement(
|
||||||
|
ast.stmt,
|
||||||
|
{
|
||||||
|
'env': with_scope,
|
||||||
|
'inloop': param['inloop'],
|
||||||
|
'rettype': param['rettype']
|
||||||
|
})
|
||||||
|
|
||||||
|
def visitIf(self, ast, param):
|
||||||
|
'''
|
||||||
|
ast: If
|
||||||
|
param: {
|
||||||
|
'env': List[Symbol]
|
||||||
|
'inloop': Bool
|
||||||
|
'rettype': Type
|
||||||
|
}
|
||||||
|
=> Returned?
|
||||||
|
'''
|
||||||
|
expr = self.visit(ast.expr, param['env'])
|
||||||
|
if not isinstance(expr, BoolType):
|
||||||
|
raise TypeMismatchInStatement(ast)
|
||||||
|
|
||||||
|
thenReturnFlag = False
|
||||||
|
for stmt in ast.thenStmt:
|
||||||
|
if thenReturnFlag:
|
||||||
|
raise UnreachableStatement(ast)
|
||||||
|
if self.visit(stmt, param):
|
||||||
|
thenReturnFlag = True
|
||||||
|
|
||||||
|
elseReturnFlag = False
|
||||||
|
for stmt in ast.elseStmt:
|
||||||
|
if elseReturnFlag:
|
||||||
|
raise UnreachableStatement(ast)
|
||||||
|
if self.visit(stmt, param):
|
||||||
|
elseReturnFlag = True
|
||||||
|
|
||||||
|
return thenReturnFlag and elseReturnFlag
|
||||||
|
|
||||||
|
def visitFor(self, ast, param):
|
||||||
|
'''
|
||||||
|
ast: For
|
||||||
|
param: {
|
||||||
|
'env': List[Symbol],
|
||||||
|
'rettype': Type
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
env = param['env']
|
||||||
|
idType = self.visit(ast.id, env)
|
||||||
|
expr1 = self.visit(ast.expr1, env)
|
||||||
|
expr2 = self.visit(ast.expr2, env)
|
||||||
|
|
||||||
|
if not isinstance(idType, IntType) or \
|
||||||
|
not isinstance(expr1, IntType) or \
|
||||||
|
not isinstance(expr2, IntType):
|
||||||
|
raise TypeMismatchInStatement(ast)
|
||||||
|
|
||||||
|
return self.loopBody(ast.loop, param)
|
||||||
|
|
||||||
|
def visitContinue(self, ast, param):
|
||||||
|
'''
|
||||||
|
ast: Continue
|
||||||
|
param: {
|
||||||
|
'inloop': Bool
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
if not param['inloop']:
|
||||||
|
raise ContinueNotInLoop()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def visitBreak(self, ast, param):
|
||||||
|
'''
|
||||||
|
ast: Break
|
||||||
|
param: {
|
||||||
|
'inloop': Bool
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
if not param['inloop']:
|
||||||
|
raise BreakNotInLoop()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def visitReturn(self, ast, param):
|
||||||
|
'''
|
||||||
|
ast: Return
|
||||||
|
param: {
|
||||||
|
'env': List[Symbol]
|
||||||
|
'rettype': Type
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
rettype = param['rettype']
|
||||||
|
env = param['env']
|
||||||
|
if isinstance(rettype, VoidType):
|
||||||
|
if ast.expr is not None:
|
||||||
|
raise TypeMismatchInStatement(ast)
|
||||||
|
else:
|
||||||
|
if ast.expr is None:
|
||||||
|
raise TypeMismatchInStatement(ast)
|
||||||
|
self.checkTypeCompatibility(
|
||||||
|
rettype, self.visit(ast.expr, env),
|
||||||
|
TypeMismatchInStatement(ast)
|
||||||
|
)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def visitWhile(self, ast, param):
|
||||||
|
'''
|
||||||
|
ast: While
|
||||||
|
param: {
|
||||||
|
'env': List[Symbol],
|
||||||
|
'inloop': Bool,
|
||||||
|
'rettype': Type
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
env = param['env']
|
||||||
|
|
||||||
|
exp = self.visit(ast.exp, env)
|
||||||
|
if not isinstance(exp, BoolType):
|
||||||
|
raise TypeMismatchInStatement(ast)
|
||||||
|
|
||||||
|
return self.loopBody(ast.sl, param)
|
||||||
|
|
||||||
|
def visitCallStmt(self, ast, param):
|
||||||
|
'''
|
||||||
|
ast: CallStmt
|
||||||
|
param: {
|
||||||
|
'env': list[Symbol]
|
||||||
|
}
|
||||||
|
raise Undeclared(Procedure)
|
||||||
|
raise TypeMismatchInStatement
|
||||||
|
wrong param size
|
||||||
|
wrong param type
|
||||||
|
Array[n..m] of X --> Array[n..m] of X
|
||||||
|
Float --> Float/Int
|
||||||
|
X --> X
|
||||||
|
=> Returned?
|
||||||
|
'''
|
||||||
|
self.callBody(ast, param['env']) # skips return
|
||||||
|
return False
|
||||||
|
|
||||||
|
def visitIntLiteral(self, asttree, param):
|
||||||
|
return IntType()
|
||||||
|
|
||||||
|
def visitFloatLiteral(self, asttree, param):
|
||||||
|
return FloatType()
|
||||||
|
|
||||||
|
def visitBooleanLiteral(self, asttree, param):
|
||||||
|
return BoolType()
|
||||||
|
|
||||||
|
def visitStringLiteral(self, asttree, param):
|
||||||
|
return StringType()
|
125
checker/StaticError.py
Normal file
125
checker/StaticError.py
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
from abc import ABC
|
||||||
|
|
||||||
|
|
||||||
|
class Kind(ABC):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Function(Kind):
|
||||||
|
def __str__(self):
|
||||||
|
return "Function"
|
||||||
|
|
||||||
|
|
||||||
|
class Procedure(Kind):
|
||||||
|
def __str__(self):
|
||||||
|
return "Procedure"
|
||||||
|
|
||||||
|
|
||||||
|
class Parameter(Kind):
|
||||||
|
def __str__(self):
|
||||||
|
return "Parameter"
|
||||||
|
|
||||||
|
|
||||||
|
class Variable(Kind):
|
||||||
|
def __str__(self):
|
||||||
|
return "Variable"
|
||||||
|
|
||||||
|
|
||||||
|
class Identifier(Kind):
|
||||||
|
def __str__(self):
|
||||||
|
return "Identifier"
|
||||||
|
|
||||||
|
|
||||||
|
class StaticError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Undeclared(StaticError):
|
||||||
|
"""k: Kind
|
||||||
|
n: string: name of identifier """
|
||||||
|
|
||||||
|
def __init__(self, k, n):
|
||||||
|
self.k = k
|
||||||
|
self.n = n
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "Undeclared " + str(self.k) + ": " + self.n
|
||||||
|
|
||||||
|
|
||||||
|
class Redeclared(StaticError):
|
||||||
|
"""k: Kind
|
||||||
|
n: string: name of identifier """
|
||||||
|
|
||||||
|
def __init__(self, k, n):
|
||||||
|
self.k = k
|
||||||
|
self.n = n
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "Redeclared " + str(self.k) + ": " + self.n
|
||||||
|
|
||||||
|
|
||||||
|
class TypeMismatchInExpression(StaticError):
|
||||||
|
"""exp: AST.Expr"""
|
||||||
|
|
||||||
|
def __init__(self, exp):
|
||||||
|
self.exp = exp
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "Type Mismatch In Expression: " + str(self.exp)
|
||||||
|
|
||||||
|
|
||||||
|
class TypeMismatchInStatement(StaticError):
|
||||||
|
"""stmt:AST.Stmt"""
|
||||||
|
|
||||||
|
def __init__(self, stmt):
|
||||||
|
self.stmt = stmt
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "Type Mismatch In Statement: " + str(self.stmt)
|
||||||
|
|
||||||
|
|
||||||
|
class FunctionNotReturn(StaticError):
|
||||||
|
"""m is a string that is the name of the function"""
|
||||||
|
|
||||||
|
def __init__(self, m):
|
||||||
|
self.m = m
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
# return "Function " + self.m + "Not Return "
|
||||||
|
return "Function " + self.m + " Not Return"
|
||||||
|
|
||||||
|
|
||||||
|
class BreakNotInLoop(StaticError):
|
||||||
|
def __str__(self):
|
||||||
|
return "Break Not In Loop"
|
||||||
|
|
||||||
|
|
||||||
|
class ContinueNotInLoop(StaticError):
|
||||||
|
def __str__(self):
|
||||||
|
return "Continue Not In Loop"
|
||||||
|
|
||||||
|
|
||||||
|
class NoEntryPoint(StaticError):
|
||||||
|
def __str__(self):
|
||||||
|
return "No entry point"
|
||||||
|
|
||||||
|
|
||||||
|
class UnreachableStatement(StaticError):
|
||||||
|
"""stmt is AST.Stmt"""
|
||||||
|
|
||||||
|
def __init__(self, stmt):
|
||||||
|
self.stmt = stmt
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "Unreachable statement: " + str(self.stmt)
|
||||||
|
|
||||||
|
|
||||||
|
class Unreachable(StaticError):
|
||||||
|
"""m is a string that is the name of the unreachable function/procedure"""
|
||||||
|
|
||||||
|
def __init__(self, k, m):
|
||||||
|
self.k = k
|
||||||
|
self.m = m
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "Unreachable " + str(self.k) + ": " + self.m
|
0
checker/__init__.py
Normal file
0
checker/__init__.py
Normal file
16
codegen/CodeGenError.py
Normal file
16
codegen/CodeGenError.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
class IllegalOperandException(Exception):
|
||||||
|
def __init__(self, msg):
|
||||||
|
# msg:string
|
||||||
|
self.s = msg
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "Illegal Operand: " + self.s + "\n"
|
||||||
|
|
||||||
|
|
||||||
|
class IllegalRuntimeException(Exception):
|
||||||
|
def __init__(self, msg):
|
||||||
|
# msg:string
|
||||||
|
self.s = msg
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "Illegal Runtime: " + self.s + "\n"
|
940
codegen/CodeGenerator.py
Normal file
940
codegen/CodeGenerator.py
Normal file
@ -0,0 +1,940 @@
|
|||||||
|
from utils.Utils import Utils
|
||||||
|
from utils.Visitor import BaseVisitor
|
||||||
|
from checker.StaticCheck import MType, Symbol
|
||||||
|
from utils.AST import (
|
||||||
|
# Type,
|
||||||
|
IntType,
|
||||||
|
FloatType,
|
||||||
|
BoolType,
|
||||||
|
StringType,
|
||||||
|
# ArrayType,
|
||||||
|
VoidType,
|
||||||
|
# Program,
|
||||||
|
# Decl,
|
||||||
|
# VarDecl,
|
||||||
|
FuncDecl,
|
||||||
|
# Stmt,
|
||||||
|
Assign,
|
||||||
|
# If,
|
||||||
|
While,
|
||||||
|
# For,
|
||||||
|
# Break,
|
||||||
|
# Continue,
|
||||||
|
# Return,
|
||||||
|
# With,
|
||||||
|
# CallStmt,
|
||||||
|
# Expr,
|
||||||
|
BinaryOp,
|
||||||
|
# UnaryOp,
|
||||||
|
# CallExpr,
|
||||||
|
# LHS,
|
||||||
|
Id,
|
||||||
|
# ArrayCell,
|
||||||
|
# Literal,
|
||||||
|
IntLiteral,
|
||||||
|
# FloatLiteral,
|
||||||
|
# StringLiteral,
|
||||||
|
# BooleanLiteral,
|
||||||
|
ArrayPointerType,
|
||||||
|
ClassType
|
||||||
|
)
|
||||||
|
from codegen.Emitter import Emitter
|
||||||
|
from codegen.Frame import Frame
|
||||||
|
from abc import ABC # , abstractmethod
|
||||||
|
# from functools import reduce
|
||||||
|
|
||||||
|
|
||||||
|
class CodeGenerator(Utils):
|
||||||
|
def __init__(self):
|
||||||
|
self.libName = "io"
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
return [
|
||||||
|
# from specification, section 7: Built-in Functions/Procedures
|
||||||
|
Symbol(
|
||||||
|
"getInt",
|
||||||
|
MType([], IntType()),
|
||||||
|
CName(self.libName)
|
||||||
|
),
|
||||||
|
Symbol(
|
||||||
|
"putInt",
|
||||||
|
MType([IntType()], VoidType()),
|
||||||
|
CName(self.libName)
|
||||||
|
),
|
||||||
|
Symbol(
|
||||||
|
"putIntLn",
|
||||||
|
MType([IntType()], VoidType()),
|
||||||
|
CName(self.libName)
|
||||||
|
),
|
||||||
|
Symbol(
|
||||||
|
"getFloat",
|
||||||
|
MType([], FloatType()),
|
||||||
|
CName(self.libName)
|
||||||
|
),
|
||||||
|
Symbol(
|
||||||
|
"putFloat",
|
||||||
|
MType([FloatType()], VoidType()),
|
||||||
|
CName(self.libName)
|
||||||
|
),
|
||||||
|
Symbol(
|
||||||
|
"putFloatLn",
|
||||||
|
MType([FloatType()], VoidType()),
|
||||||
|
CName(self.libName)
|
||||||
|
),
|
||||||
|
Symbol(
|
||||||
|
"putBool",
|
||||||
|
MType([BoolType()], VoidType()),
|
||||||
|
CName(self.libName)
|
||||||
|
),
|
||||||
|
Symbol(
|
||||||
|
"putBoolLn",
|
||||||
|
MType([BoolType()], VoidType()),
|
||||||
|
CName(self.libName)
|
||||||
|
),
|
||||||
|
Symbol(
|
||||||
|
"putString",
|
||||||
|
MType([StringType()], VoidType()),
|
||||||
|
CName(self.libName)
|
||||||
|
),
|
||||||
|
Symbol(
|
||||||
|
"putStringLn",
|
||||||
|
MType([StringType()], VoidType()),
|
||||||
|
CName(self.libName)
|
||||||
|
),
|
||||||
|
Symbol(
|
||||||
|
"putLn",
|
||||||
|
MType([], VoidType()),
|
||||||
|
CName(self.libName)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
def gen(self, ast, dir_, name):
|
||||||
|
# ast: AST
|
||||||
|
# dir_: String
|
||||||
|
|
||||||
|
gl = self.init()
|
||||||
|
gc = CodeGenVisitor(ast, gl, dir_, name)
|
||||||
|
gc.visit(ast, None) # visits Program
|
||||||
|
|
||||||
|
|
||||||
|
class SubBody():
|
||||||
|
def __init__(self, frame, sym):
|
||||||
|
# frame: Frame
|
||||||
|
# sym: List[Symbol]
|
||||||
|
|
||||||
|
self.frame = frame
|
||||||
|
self.sym = sym
|
||||||
|
self.gen = False
|
||||||
|
self.isFor = False
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "SubBody({},{})".format(
|
||||||
|
str(self.frame),
|
||||||
|
','.join([str(x) for x in self.sym])
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Access():
|
||||||
|
def __init__(self, frame, sym, **kwargs):
|
||||||
|
# frame: Frame
|
||||||
|
# sym: List[Symbol]
|
||||||
|
# isLeft: Boolean
|
||||||
|
# isFirst: Boolean
|
||||||
|
|
||||||
|
self.frame = frame
|
||||||
|
self.sym = sym
|
||||||
|
self.isLeft = kwargs.get('isLeft', False)
|
||||||
|
self.isFirst = kwargs.get('isFirst', False)
|
||||||
|
|
||||||
|
|
||||||
|
class Val(ABC):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Index(Val):
|
||||||
|
def __init__(self, value):
|
||||||
|
# value: Int
|
||||||
|
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
|
||||||
|
class CName(Val):
|
||||||
|
def __init__(self, value):
|
||||||
|
# value: String
|
||||||
|
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
|
||||||
|
class CodeGenVisitor(BaseVisitor, Utils):
|
||||||
|
def __init__(self, astTree, env, dir_, name):
|
||||||
|
'''
|
||||||
|
astTree: AST
|
||||||
|
env: List[Symbol]
|
||||||
|
dir_: File
|
||||||
|
'''
|
||||||
|
|
||||||
|
self.astTree = astTree
|
||||||
|
self.env = env[:] # safety reason
|
||||||
|
self.className = name
|
||||||
|
self.path = dir_
|
||||||
|
self.emit = Emitter(
|
||||||
|
self.path + "/" + self.className + ".j")
|
||||||
|
|
||||||
|
# import sys
|
||||||
|
# print(astTree, file=sys.stderr)
|
||||||
|
|
||||||
|
def genMETHOD(self, consdecl, o, frame):
|
||||||
|
'''
|
||||||
|
consdecl: FuncDecl
|
||||||
|
o: SubBody,
|
||||||
|
frame: Frame
|
||||||
|
|
||||||
|
Submethod to generate code for body,
|
||||||
|
most of this is given by teacher himself
|
||||||
|
with slight modifications,
|
||||||
|
add local variable code generation
|
||||||
|
'''
|
||||||
|
|
||||||
|
isInit = consdecl.returnType is None
|
||||||
|
isMain = consdecl.name.name == "main" and \
|
||||||
|
len(consdecl.param) == 0 and \
|
||||||
|
isinstance(consdecl.returnType, VoidType)
|
||||||
|
|
||||||
|
if isInit:
|
||||||
|
returnType = VoidType()
|
||||||
|
methodName = '<init>'
|
||||||
|
else:
|
||||||
|
returnType = consdecl.returnType
|
||||||
|
methodName = consdecl.name.name
|
||||||
|
|
||||||
|
if isMain:
|
||||||
|
intype = [ArrayPointerType(StringType())]
|
||||||
|
else:
|
||||||
|
intype = [v.varType for v in consdecl.param]
|
||||||
|
|
||||||
|
mtype = MType(intype, returnType)
|
||||||
|
|
||||||
|
self.emit.printout(
|
||||||
|
self.emit.emitMETHOD(
|
||||||
|
methodName,
|
||||||
|
mtype,
|
||||||
|
not isInit,
|
||||||
|
frame
|
||||||
|
))
|
||||||
|
|
||||||
|
frame.enterScope(True)
|
||||||
|
|
||||||
|
glenv = o
|
||||||
|
|
||||||
|
# Generate code for parameter declarations
|
||||||
|
if isInit:
|
||||||
|
self.emit.printout(
|
||||||
|
self.emit.emitVAR(
|
||||||
|
frame.getNewIndex(),
|
||||||
|
"this",
|
||||||
|
ClassType(self.className),
|
||||||
|
frame.getStartLabel(),
|
||||||
|
frame.getEndLabel(),
|
||||||
|
frame
|
||||||
|
))
|
||||||
|
if isMain:
|
||||||
|
self.emit.printout(
|
||||||
|
self.emit.emitVAR(
|
||||||
|
frame.getNewIndex(),
|
||||||
|
"args",
|
||||||
|
ArrayPointerType(StringType()),
|
||||||
|
frame.getStartLabel(),
|
||||||
|
frame.getEndLabel(),
|
||||||
|
frame
|
||||||
|
))
|
||||||
|
|
||||||
|
# set up local variables
|
||||||
|
if glenv is None:
|
||||||
|
glenv = []
|
||||||
|
local = []
|
||||||
|
for p in consdecl.param:
|
||||||
|
s = self.visit(
|
||||||
|
p,
|
||||||
|
SubBody(frame, local + glenv)
|
||||||
|
)
|
||||||
|
local = [s] + local
|
||||||
|
for l in consdecl.local:
|
||||||
|
s = self.visit(
|
||||||
|
l,
|
||||||
|
SubBody(frame, local + glenv)
|
||||||
|
)
|
||||||
|
local = [s] + local
|
||||||
|
glenv = local + glenv
|
||||||
|
|
||||||
|
body = consdecl.body
|
||||||
|
self.emit.printout(
|
||||||
|
self.emit.emitLABEL(
|
||||||
|
frame.getStartLabel(),
|
||||||
|
frame
|
||||||
|
))
|
||||||
|
|
||||||
|
# Generate code for statements
|
||||||
|
if isInit:
|
||||||
|
self.emit.printout(
|
||||||
|
self.emit.emitREADVAR(
|
||||||
|
"this",
|
||||||
|
ClassType(self.className),
|
||||||
|
0,
|
||||||
|
frame
|
||||||
|
))
|
||||||
|
self.emit.printout(
|
||||||
|
self.emit.emitINVOKESPECIAL(frame)
|
||||||
|
)
|
||||||
|
|
||||||
|
# visit statement
|
||||||
|
list(map(lambda x:
|
||||||
|
self.visit(
|
||||||
|
x,
|
||||||
|
SubBody(frame, glenv)),
|
||||||
|
body
|
||||||
|
))
|
||||||
|
|
||||||
|
self.emit.printout(
|
||||||
|
self.emit.emitLABEL(
|
||||||
|
frame.getEndLabel(),
|
||||||
|
frame
|
||||||
|
))
|
||||||
|
'''
|
||||||
|
prevents:
|
||||||
|
LabelX:
|
||||||
|
LabelY:
|
||||||
|
end
|
||||||
|
'''
|
||||||
|
self.emit.printout(
|
||||||
|
self.emit.emitRETURN(
|
||||||
|
VoidType(),
|
||||||
|
frame
|
||||||
|
))
|
||||||
|
self.emit.printout(
|
||||||
|
self.emit.emitENDMETHOD(frame)
|
||||||
|
)
|
||||||
|
frame.exitScope()
|
||||||
|
|
||||||
|
def callBody(self, ast, ctxt):
|
||||||
|
'''
|
||||||
|
ast: CallExpr | CallStmt
|
||||||
|
ctxt: SubBody if CallStmt
|
||||||
|
Access if CallExpr
|
||||||
|
=> name, type if CallExpr
|
||||||
|
|
||||||
|
CallExpr and CallStmt has similar routine,
|
||||||
|
Except that CallExpr returns (name, type)
|
||||||
|
of the function being called
|
||||||
|
'''
|
||||||
|
frame = ctxt.frame
|
||||||
|
sym = ctxt.sym
|
||||||
|
|
||||||
|
symbol, ctype = self.visit( # visits Id
|
||||||
|
ast.method,
|
||||||
|
Access(frame, sym, isFirst=True)
|
||||||
|
)
|
||||||
|
cname = symbol.value
|
||||||
|
params = ctype.partype
|
||||||
|
|
||||||
|
in_ = ("", list())
|
||||||
|
for i, arg in enumerate(ast.param):
|
||||||
|
str1, typ1 = self.visit(
|
||||||
|
arg,
|
||||||
|
Access(frame, sym, isFirst=True)
|
||||||
|
)
|
||||||
|
if isinstance(typ1, Symbol):
|
||||||
|
typ1 = typ1.mtype.rettype
|
||||||
|
|
||||||
|
if not isinstance(typ1, type(params[i])):
|
||||||
|
# foo(float) ==> foo(int)
|
||||||
|
# others: Checker catches
|
||||||
|
str1 += self.emit.emitI2F(frame)
|
||||||
|
|
||||||
|
in_ = (in_[0] + str1, in_[1] + [typ1])
|
||||||
|
|
||||||
|
# funcname = cname.value + '/' + ast.method.name
|
||||||
|
funcname = cname.value + '/' + symbol.name
|
||||||
|
code = ''
|
||||||
|
code += in_[0]
|
||||||
|
code += self.emit.emitINVOKESTATIC(
|
||||||
|
funcname,
|
||||||
|
ctype,
|
||||||
|
frame
|
||||||
|
)
|
||||||
|
return code, symbol
|
||||||
|
|
||||||
|
def visitProgram(self, ast, c):
|
||||||
|
'''
|
||||||
|
ast: Program
|
||||||
|
c: Unknown
|
||||||
|
=> c
|
||||||
|
'''
|
||||||
|
|
||||||
|
self.emit.printout(
|
||||||
|
self.emit.emitPROLOG(
|
||||||
|
self.className,
|
||||||
|
"java.lang.Object"
|
||||||
|
))
|
||||||
|
e = SubBody(None, self.env)
|
||||||
|
|
||||||
|
# generate global declare list
|
||||||
|
for x in ast.decl:
|
||||||
|
# returns Symbol on no Gen
|
||||||
|
self.env += [self.visit(x, e)]
|
||||||
|
|
||||||
|
e.gen = True
|
||||||
|
for x in ast.decl:
|
||||||
|
# recall that e = SubBody(None, self.env)
|
||||||
|
# and e.sym = self.env as reference
|
||||||
|
self.visit(x, e)
|
||||||
|
|
||||||
|
# generate default constructor
|
||||||
|
self.genMETHOD(
|
||||||
|
FuncDecl(
|
||||||
|
Id("<init>"),
|
||||||
|
list(),
|
||||||
|
list(),
|
||||||
|
list(),
|
||||||
|
None
|
||||||
|
),
|
||||||
|
c,
|
||||||
|
Frame("<init>", VoidType)
|
||||||
|
)
|
||||||
|
self.emit.emitEPILOG()
|
||||||
|
return c
|
||||||
|
|
||||||
|
def visitFuncDecl(self, ast, subbody):
|
||||||
|
'''
|
||||||
|
ast: FuncDecl
|
||||||
|
subbody: SubBody
|
||||||
|
=> None if generate code
|
||||||
|
=> else Symbol
|
||||||
|
'''
|
||||||
|
|
||||||
|
if subbody.gen:
|
||||||
|
# on gen
|
||||||
|
frame = Frame(ast.name, ast.returnType)
|
||||||
|
self.genMETHOD(
|
||||||
|
ast,
|
||||||
|
subbody.sym,
|
||||||
|
frame
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# on first scan to get global Symbol
|
||||||
|
params = [v.varType for v in ast.param]
|
||||||
|
return Symbol(
|
||||||
|
ast.name.name,
|
||||||
|
MType(params, ast.returnType),
|
||||||
|
CName(self.className)
|
||||||
|
)
|
||||||
|
|
||||||
|
def visitVarDecl(self, ast, subbody):
|
||||||
|
'''
|
||||||
|
ast: VarDecl
|
||||||
|
subbody: SubBody
|
||||||
|
=> Symbol(,,CName) for global VarDecl
|
||||||
|
=> Symbol(,,Index) for local VarDecl
|
||||||
|
'''
|
||||||
|
if subbody.gen:
|
||||||
|
return
|
||||||
|
if subbody.frame is None:
|
||||||
|
# generate code for global var decl
|
||||||
|
# returns Symbol with CName
|
||||||
|
code = self.emit.emitATTRIBUTE(
|
||||||
|
ast.variable.name,
|
||||||
|
ast.varType,
|
||||||
|
False,
|
||||||
|
''
|
||||||
|
)
|
||||||
|
self.emit.printout(code)
|
||||||
|
return Symbol(
|
||||||
|
ast.variable.name,
|
||||||
|
ast.varType,
|
||||||
|
CName(self.className)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# generate code for local var decl
|
||||||
|
# returns Symbol with Index
|
||||||
|
frame = subbody.frame
|
||||||
|
idx = frame.getNewIndex()
|
||||||
|
code = self.emit.emitVAR(
|
||||||
|
idx,
|
||||||
|
ast.variable.name,
|
||||||
|
ast.varType,
|
||||||
|
frame.getStartLabel(),
|
||||||
|
frame.getEndLabel(),
|
||||||
|
frame
|
||||||
|
)
|
||||||
|
self.emit.printout(code)
|
||||||
|
return Symbol(
|
||||||
|
ast.variable.name,
|
||||||
|
ast.varType,
|
||||||
|
Index(idx)
|
||||||
|
)
|
||||||
|
|
||||||
|
def visitBinaryOp(self, ast, param):
|
||||||
|
'''
|
||||||
|
ast: BinaryOp
|
||||||
|
param: Access
|
||||||
|
=> code, type
|
||||||
|
|
||||||
|
Rules:
|
||||||
|
(/) --> Float/Int:Float/Int => Float
|
||||||
|
(+,-,*) --> Float:Float/Int => Float
|
||||||
|
--> Float/Int:Float => Float
|
||||||
|
--> Int:Int => Int
|
||||||
|
(div,mod) --> Int:Int => Int
|
||||||
|
(<,<=,=,>=,>,<>) --> Float:Float/Int => Bool
|
||||||
|
--> Float/Int:Float => Bool
|
||||||
|
--> Int:Int => Bool
|
||||||
|
(and,or,andthen,orelse) --> Bool:Bool => Bool
|
||||||
|
'''
|
||||||
|
frame = param.frame
|
||||||
|
sym = param.sym
|
||||||
|
|
||||||
|
lhs, ltype = self.visit(
|
||||||
|
ast.left,
|
||||||
|
Access(frame, sym)
|
||||||
|
)
|
||||||
|
rhs, rtype = self.visit(
|
||||||
|
ast.right,
|
||||||
|
Access(frame, sym)
|
||||||
|
)
|
||||||
|
if isinstance(ltype, MType):
|
||||||
|
ltype = ltype.rettype
|
||||||
|
if isinstance(rtype, MType):
|
||||||
|
rtype = rtype.rettype
|
||||||
|
|
||||||
|
if (isinstance(ltype, type(rtype))):
|
||||||
|
# because idiv returns int not float
|
||||||
|
# while MP / returns float on all cases
|
||||||
|
if ast.op == '/' and\
|
||||||
|
isinstance(ltype, IntType):
|
||||||
|
lhs += self.emit.emitI2F(frame)
|
||||||
|
rhs += self.emit.emitI2F(frame)
|
||||||
|
intype = FloatType()
|
||||||
|
rettype = FloatType()
|
||||||
|
else:
|
||||||
|
intype = ltype
|
||||||
|
rettype = ltype
|
||||||
|
else:
|
||||||
|
# only Float:Int or Int:Float
|
||||||
|
# I2F on Int
|
||||||
|
if isinstance(ltype, IntType):
|
||||||
|
lhs += self.emit.emitI2F(frame)
|
||||||
|
if isinstance(rtype, IntType):
|
||||||
|
rhs += self.emit.emitI2F(frame)
|
||||||
|
intype = FloatType()
|
||||||
|
rettype = FloatType()
|
||||||
|
|
||||||
|
code = ''
|
||||||
|
code += lhs
|
||||||
|
code += rhs
|
||||||
|
# self.emit.printout(lhs) # push left
|
||||||
|
# self.emit.printout(rhs) # push right
|
||||||
|
|
||||||
|
# generate code for each operator
|
||||||
|
if ast.op in ('+', '-'):
|
||||||
|
code += self.emit.emitADDOP(
|
||||||
|
ast.op,
|
||||||
|
intype,
|
||||||
|
frame
|
||||||
|
)
|
||||||
|
elif ast.op in ('*', '/'):
|
||||||
|
code += self.emit.emitMULOP(
|
||||||
|
ast.op,
|
||||||
|
intype,
|
||||||
|
frame
|
||||||
|
)
|
||||||
|
elif ast.op in ('<', '<=', '=', '>=', '>', '<>'):
|
||||||
|
code += self.emit.emitREOP(
|
||||||
|
ast.op,
|
||||||
|
intype,
|
||||||
|
frame
|
||||||
|
)
|
||||||
|
rettype = BoolType()
|
||||||
|
elif ast.op.lower() == 'div':
|
||||||
|
code += self.emit.emitDIV(frame)
|
||||||
|
elif ast.op.lower() == 'mod':
|
||||||
|
code += self.emit.emitMOD(frame)
|
||||||
|
elif ast.op.lower() == 'and':
|
||||||
|
code += self.emit.emitANDOP(frame)
|
||||||
|
elif ast.op.lower() == 'or':
|
||||||
|
code += self.emit.emitOROP(frame)
|
||||||
|
elif ast.op.lower() == 'andthen':
|
||||||
|
code = ''
|
||||||
|
falseLabel = frame.getNewLabel()
|
||||||
|
endLabel = frame.getNewLabel()
|
||||||
|
code += lhs
|
||||||
|
code += self.emit.emitIFEQ(falseLabel, frame)
|
||||||
|
code += rhs
|
||||||
|
code += self.emit.emitIFEQ(falseLabel, frame)
|
||||||
|
code += self.emit.emitPUSHICONST(1, frame)
|
||||||
|
code += self.emit.emitGOTO(endLabel, frame)
|
||||||
|
code += self.emit.emitLABEL(falseLabel, frame)
|
||||||
|
code += self.emit.emitPUSHICONST(0, frame)
|
||||||
|
code += self.emit.emitLABEL(endLabel, frame)
|
||||||
|
rettype = BoolType()
|
||||||
|
elif ast.op.lower() == 'orelse':
|
||||||
|
code = ''
|
||||||
|
trueLabel = frame.getNewLabel()
|
||||||
|
endLabel = frame.getNewLabel()
|
||||||
|
code += lhs
|
||||||
|
# if lhs != 0 True
|
||||||
|
code += self.emit.emitIFNE(trueLabel, frame)
|
||||||
|
code += rhs
|
||||||
|
# if rhs != 0 True
|
||||||
|
code += self.emit.emitIFNE(trueLabel, frame)
|
||||||
|
code += self.emit.emitPUSHICONST(0, frame)
|
||||||
|
code += self.emit.emitGOTO(endLabel, frame)
|
||||||
|
code += self.emit.emitLABEL(trueLabel, frame)
|
||||||
|
code += self.emit.emitPUSHICONST(1, frame)
|
||||||
|
code += self.emit.emitLABEL(endLabel, frame)
|
||||||
|
rettype = BoolType()
|
||||||
|
|
||||||
|
return code, rettype
|
||||||
|
|
||||||
|
def visitUnaryOp(self, ast, param):
|
||||||
|
frame = param.frame
|
||||||
|
sym = param.sym
|
||||||
|
|
||||||
|
bodycode, bodytype = self.visit(
|
||||||
|
ast.body,
|
||||||
|
Access(frame, sym)
|
||||||
|
)
|
||||||
|
|
||||||
|
code = ''
|
||||||
|
code += bodycode
|
||||||
|
if ast.op.lower() == 'not':
|
||||||
|
code += self.emit.emitNOT(bodytype, frame)
|
||||||
|
elif ast.op.lower() == '-':
|
||||||
|
code += self.emit.emitNEGOP(bodytype, frame)
|
||||||
|
|
||||||
|
return code, bodytype
|
||||||
|
|
||||||
|
def visitCallExpr(self, ast, o):
|
||||||
|
'''
|
||||||
|
ast: CallExpr
|
||||||
|
o: Access
|
||||||
|
=> (name, type) of function being called
|
||||||
|
'''
|
||||||
|
return self.callBody(ast, o)
|
||||||
|
|
||||||
|
def visitId(self, ast, param):
|
||||||
|
'''
|
||||||
|
ast: Id
|
||||||
|
param: Access
|
||||||
|
'''
|
||||||
|
res = self.lookup(
|
||||||
|
ast.name,
|
||||||
|
param.sym,
|
||||||
|
lambda env: env.name
|
||||||
|
)
|
||||||
|
|
||||||
|
# not likely, checker catches
|
||||||
|
if res is None:
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
# function call
|
||||||
|
if isinstance(res.mtype, MType):
|
||||||
|
return res, res.mtype
|
||||||
|
|
||||||
|
frame = param.frame
|
||||||
|
# global variable
|
||||||
|
# res: Symbol(,,CName)
|
||||||
|
if isinstance(res.value, CName):
|
||||||
|
varname = res.value.value + '/' + res.name
|
||||||
|
if param.isLeft:
|
||||||
|
code = self.emit.emitPUTSTATIC(
|
||||||
|
varname,
|
||||||
|
res.mtype,
|
||||||
|
frame
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
code = self.emit.emitGETSTATIC(
|
||||||
|
varname,
|
||||||
|
res.mtype,
|
||||||
|
frame
|
||||||
|
)
|
||||||
|
return code, res.mtype
|
||||||
|
|
||||||
|
# Local variable
|
||||||
|
if param.isLeft:
|
||||||
|
code = self.emit.emitWRITEVAR(
|
||||||
|
res.name,
|
||||||
|
res.mtype,
|
||||||
|
res.value.value,
|
||||||
|
frame
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
code = self.emit.emitREADVAR(
|
||||||
|
res.name,
|
||||||
|
res.mtype,
|
||||||
|
res.value.value,
|
||||||
|
frame
|
||||||
|
)
|
||||||
|
return code, res.mtype
|
||||||
|
|
||||||
|
def visitArrayCell(self, ast, param):
|
||||||
|
'''
|
||||||
|
ast: ArrayCell,
|
||||||
|
param: Access
|
||||||
|
'''
|
||||||
|
frame = param.frame
|
||||||
|
sym = param.sym
|
||||||
|
arrcode, arrtype = self.visit(
|
||||||
|
ast.arr,
|
||||||
|
Access(frame, sym)
|
||||||
|
)
|
||||||
|
idxcode, idxtype = self.visit(
|
||||||
|
ast.idx,
|
||||||
|
Access(frame, sym)
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitAssign(self, ast, param):
|
||||||
|
'''
|
||||||
|
ast: Assign
|
||||||
|
param: SubBody
|
||||||
|
'''
|
||||||
|
frame = param.frame
|
||||||
|
sym = param.sym
|
||||||
|
expcode, exptype = self.visit(
|
||||||
|
ast.exp,
|
||||||
|
Access(frame, sym)
|
||||||
|
)
|
||||||
|
lhscode, lhstype = self.visit(
|
||||||
|
ast.lhs,
|
||||||
|
Access(frame, sym, isLeft=True)
|
||||||
|
)
|
||||||
|
|
||||||
|
if isinstance(exptype, Symbol):
|
||||||
|
exptype = exptype.mtype.rettype
|
||||||
|
|
||||||
|
if not isinstance(exptype, type(lhstype)):
|
||||||
|
# float = int
|
||||||
|
# others => checker catches
|
||||||
|
expcode += self.emit.emitI2F(param.frame)
|
||||||
|
|
||||||
|
code = ''
|
||||||
|
code += expcode + lhscode
|
||||||
|
self.emit.printout(code)
|
||||||
|
|
||||||
|
def visitWith(self, ast, param):
|
||||||
|
'''
|
||||||
|
ast: With
|
||||||
|
param: SubBody
|
||||||
|
'''
|
||||||
|
frame = param.frame
|
||||||
|
sym = param.sym
|
||||||
|
|
||||||
|
frame.enterScope(False)
|
||||||
|
startLabel = self.emit.emitLABEL(frame.getStartLabel(), frame)
|
||||||
|
endLabel = self.emit.emitLABEL(frame.getEndLabel(), frame)
|
||||||
|
|
||||||
|
local = sym[:]
|
||||||
|
for var in ast.decl:
|
||||||
|
local = [self.visit(var, SubBody(frame, local))] + local
|
||||||
|
|
||||||
|
self.emit.printout(startLabel)
|
||||||
|
for stmt in ast.stmt:
|
||||||
|
self.visit(stmt, SubBody(frame, local))
|
||||||
|
self.emit.printout(endLabel)
|
||||||
|
frame.exitScope()
|
||||||
|
|
||||||
|
def visitIf(self, ast, param):
|
||||||
|
'''
|
||||||
|
ast: If
|
||||||
|
param: SubBody
|
||||||
|
'''
|
||||||
|
frame = param.frame
|
||||||
|
sym = param.sym
|
||||||
|
haveElse = True if len(ast.elseStmt) > 0 \
|
||||||
|
else False
|
||||||
|
|
||||||
|
code = ''
|
||||||
|
expcode, exptype = self.visit(
|
||||||
|
ast.expr, Access(frame, sym)
|
||||||
|
)
|
||||||
|
code += expcode
|
||||||
|
|
||||||
|
elseLabel = frame.getNewLabel()
|
||||||
|
|
||||||
|
if haveElse:
|
||||||
|
endLabel = frame.getNewLabel()
|
||||||
|
|
||||||
|
code += self.emit.emitIFEQ(elseLabel, frame)
|
||||||
|
|
||||||
|
self.emit.printout(code)
|
||||||
|
code = ''
|
||||||
|
|
||||||
|
# printout then code
|
||||||
|
for stmt in ast.thenStmt:
|
||||||
|
self.visit(stmt, param)
|
||||||
|
|
||||||
|
if haveElse:
|
||||||
|
code += self.emit.emitGOTO(endLabel, frame)
|
||||||
|
code += self.emit.emitLABEL(elseLabel, frame)
|
||||||
|
self.emit.printout(code)
|
||||||
|
code = ''
|
||||||
|
|
||||||
|
if not haveElse:
|
||||||
|
return
|
||||||
|
|
||||||
|
# printout else code
|
||||||
|
for stmt in ast.elseStmt:
|
||||||
|
self.visit(stmt, param)
|
||||||
|
|
||||||
|
code += self.emit.emitLABEL(endLabel, frame)
|
||||||
|
self.emit.printout(code)
|
||||||
|
|
||||||
|
def visitFor(self, ast, param):
|
||||||
|
conditionOp = '<=' if ast.up else '>='
|
||||||
|
continueOp = '+' if ast.up else '-'
|
||||||
|
|
||||||
|
loopCondition = BinaryOp(conditionOp, ast.id, ast.expr2)
|
||||||
|
continueInstruction = Assign(
|
||||||
|
ast.id, BinaryOp(
|
||||||
|
continueOp, ast.id, IntLiteral(1)))
|
||||||
|
loop = ast.loop[:] + [continueInstruction]
|
||||||
|
|
||||||
|
param.isFor = True
|
||||||
|
self.visit(Assign(ast.id, ast.expr1), param)
|
||||||
|
self.visit(While(loopCondition, loop), param)
|
||||||
|
|
||||||
|
def visitContinue(self, ast, param):
|
||||||
|
frame = param.frame
|
||||||
|
continueLabel = frame.getContinueLabel()
|
||||||
|
code = self.emit.emitGOTO(continueLabel, frame)
|
||||||
|
self.emit.printout(code)
|
||||||
|
|
||||||
|
def visitBreak(self, ast, param):
|
||||||
|
frame = param.frame
|
||||||
|
breakLabel = frame.getBreakLabel()
|
||||||
|
code = self.emit.emitGOTO(breakLabel, frame)
|
||||||
|
self.emit.printout("\t; Break\n")
|
||||||
|
self.emit.printout(code)
|
||||||
|
|
||||||
|
def visitReturn(self, ast, param):
|
||||||
|
frame = param.frame
|
||||||
|
sym = param.sym
|
||||||
|
rettype = frame.returnType
|
||||||
|
|
||||||
|
if ast.expr:
|
||||||
|
expcode, exptype = self.visit(
|
||||||
|
ast.expr,
|
||||||
|
Access(frame, sym)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
expcode, exptype = '', VoidType()
|
||||||
|
|
||||||
|
code = ''
|
||||||
|
code += expcode
|
||||||
|
if not isinstance(exptype, type(rettype)):
|
||||||
|
# return int in float function
|
||||||
|
# others -> Checker catches
|
||||||
|
code += self.emit.emitI2F(frame)
|
||||||
|
code += self.emit.emitRETURN(rettype, frame)
|
||||||
|
self.emit.printout(code)
|
||||||
|
|
||||||
|
def visitWhile(self, ast, param):
|
||||||
|
'''
|
||||||
|
ast: While
|
||||||
|
param: SubBody
|
||||||
|
'''
|
||||||
|
frame = param.frame
|
||||||
|
sym = param.sym
|
||||||
|
isFor = param.isFor
|
||||||
|
|
||||||
|
param.isFor = False
|
||||||
|
code = ''
|
||||||
|
|
||||||
|
frame.enterLoop()
|
||||||
|
breakLabel = frame.getBreakLabel()
|
||||||
|
continueLabel = frame.getContinueLabel()
|
||||||
|
|
||||||
|
expcode, exptype = self.visit(
|
||||||
|
ast.exp,
|
||||||
|
Access(frame, sym)
|
||||||
|
)
|
||||||
|
if isFor:
|
||||||
|
continueInstruction = ast.sl[-1]
|
||||||
|
ast.sl = ast.sl[:-1]
|
||||||
|
|
||||||
|
code += expcode
|
||||||
|
code += self.emit.emitIFEQ(breakLabel, frame)
|
||||||
|
|
||||||
|
bodyLabel = frame.getNewLabel()
|
||||||
|
code += '; body\n'
|
||||||
|
code += self.emit.emitLABEL(bodyLabel, frame)
|
||||||
|
|
||||||
|
self.emit.printout(code)
|
||||||
|
code = ''
|
||||||
|
|
||||||
|
for stmt in ast.sl:
|
||||||
|
self.visit(stmt, param)
|
||||||
|
|
||||||
|
code += '; continue\n'
|
||||||
|
code += self.emit.emitLABEL(continueLabel, frame)
|
||||||
|
if isFor:
|
||||||
|
self.emit.printout(code)
|
||||||
|
code = ''
|
||||||
|
self.visit(continueInstruction, param)
|
||||||
|
code += expcode
|
||||||
|
code += self.emit.emitIFNE(bodyLabel, frame)
|
||||||
|
else:
|
||||||
|
code += expcode
|
||||||
|
code += self.emit.emitIFNE(bodyLabel, frame)
|
||||||
|
|
||||||
|
code += '; break\n'
|
||||||
|
code += self.emit.emitLABEL(breakLabel, frame)
|
||||||
|
self.emit.printout(code)
|
||||||
|
frame.exitLoop()
|
||||||
|
|
||||||
|
def visitCallStmt(self, ast, o):
|
||||||
|
'''
|
||||||
|
ast: CallStmt
|
||||||
|
o: SubBody
|
||||||
|
'''
|
||||||
|
code, symbol = self.callBody(ast, o)
|
||||||
|
self.emit.printout(code)
|
||||||
|
|
||||||
|
def visitIntLiteral(self, ast, param):
|
||||||
|
'''
|
||||||
|
ast: IntLiteral
|
||||||
|
param: Access
|
||||||
|
=> code, type
|
||||||
|
'''
|
||||||
|
frame = param.frame
|
||||||
|
return self.emit.emitPUSHICONST(
|
||||||
|
ast.value,
|
||||||
|
frame
|
||||||
|
), IntType()
|
||||||
|
|
||||||
|
def visitFloatLiteral(self, ast, param):
|
||||||
|
'''
|
||||||
|
ast: FloatLiteral
|
||||||
|
param: Access
|
||||||
|
=> code, type
|
||||||
|
'''
|
||||||
|
frame = param.frame
|
||||||
|
return self.emit.emitPUSHFCONST(
|
||||||
|
str(ast.value),
|
||||||
|
frame
|
||||||
|
), FloatType()
|
||||||
|
|
||||||
|
def visitBooleanLiteral(self, ast, param):
|
||||||
|
frame = param.frame
|
||||||
|
return self.emit.emitPUSHICONST(
|
||||||
|
str(ast.value).lower(),
|
||||||
|
frame
|
||||||
|
), BoolType()
|
||||||
|
|
||||||
|
def visitStringLiteral(self, ast, param):
|
||||||
|
frame = param.frame
|
||||||
|
return self.emit.emitPUSHCONST(
|
||||||
|
# emitLDC doesn't add "
|
||||||
|
'"{}"'.format(ast.value),
|
||||||
|
StringType(),
|
||||||
|
frame
|
||||||
|
), StringType()
|
784
codegen/Emitter.py
Normal file
784
codegen/Emitter.py
Normal file
@ -0,0 +1,784 @@
|
|||||||
|
from codegen.CodeGenError import (
|
||||||
|
# Utils,
|
||||||
|
# IllegalEscape,
|
||||||
|
IllegalOperandException,
|
||||||
|
# IllegalRuntimeException
|
||||||
|
)
|
||||||
|
# from Utils import *
|
||||||
|
from checker.StaticCheck import MType # , Symbol
|
||||||
|
# from StaticError import (
|
||||||
|
# # Kind,
|
||||||
|
# Function,
|
||||||
|
# Procedure,
|
||||||
|
# Variable,
|
||||||
|
# Parameter,
|
||||||
|
# Identifier,
|
||||||
|
# # StaticError,
|
||||||
|
# Undeclared,
|
||||||
|
# Redeclared,
|
||||||
|
# TypeMismatchInExpression,
|
||||||
|
# TypeMismatchInStatement,
|
||||||
|
# FunctionNotReturn,
|
||||||
|
# BreakNotInLoop,
|
||||||
|
# ContinueNotInLoop,
|
||||||
|
# NoEntryPoint,
|
||||||
|
# UnreachableStatement,
|
||||||
|
# Unreachable
|
||||||
|
# )
|
||||||
|
from utils.AST import (
|
||||||
|
IntType,
|
||||||
|
FloatType,
|
||||||
|
BoolType,
|
||||||
|
StringType,
|
||||||
|
# ArrayType,
|
||||||
|
VoidType,
|
||||||
|
# Program,
|
||||||
|
# Decl,
|
||||||
|
# VarDecl,
|
||||||
|
# FuncDecl,
|
||||||
|
# Stmt,
|
||||||
|
# Assign,
|
||||||
|
# If,
|
||||||
|
# While,
|
||||||
|
# For,
|
||||||
|
# Break,
|
||||||
|
# Continue,
|
||||||
|
# Return,
|
||||||
|
# With,
|
||||||
|
# CallStmt,
|
||||||
|
# Expr,
|
||||||
|
# BinaryOp,
|
||||||
|
# UnaryOp,
|
||||||
|
# CallExpr,
|
||||||
|
# LHS,
|
||||||
|
# Id,
|
||||||
|
# ArrayCell,
|
||||||
|
# Literal,
|
||||||
|
IntLiteral,
|
||||||
|
# FloatLiteral,
|
||||||
|
# StringLiteral,
|
||||||
|
# BooleanLiteral,
|
||||||
|
ArrayPointerType,
|
||||||
|
ClassType
|
||||||
|
)
|
||||||
|
# from codegen.CodeGenerator import ArrayPointerType, ClassType
|
||||||
|
from codegen.MachineCode import JasminCode
|
||||||
|
|
||||||
|
|
||||||
|
class Emitter():
|
||||||
|
def __init__(self, filename):
|
||||||
|
self.filename = filename
|
||||||
|
self.buff = list()
|
||||||
|
self.jvm = JasminCode()
|
||||||
|
|
||||||
|
def getJVMType(self, inType):
|
||||||
|
'''
|
||||||
|
https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.3.2
|
||||||
|
'''
|
||||||
|
typeIn = type(inType)
|
||||||
|
if typeIn is IntType:
|
||||||
|
return "I"
|
||||||
|
elif typeIn is FloatType:
|
||||||
|
return "F"
|
||||||
|
elif typeIn is BoolType:
|
||||||
|
return "Z"
|
||||||
|
elif typeIn is StringType:
|
||||||
|
return "Ljava/lang/String;"
|
||||||
|
elif typeIn is VoidType:
|
||||||
|
return "V"
|
||||||
|
elif typeIn is ArrayPointerType:
|
||||||
|
return "[" + self.getJVMType(inType.eleType)
|
||||||
|
elif typeIn is MType:
|
||||||
|
return "({}){}".format(
|
||||||
|
"".join(list(map(lambda x: self.getJVMType(x),
|
||||||
|
inType.partype))),
|
||||||
|
self.getJVMType(inType.rettype)
|
||||||
|
)
|
||||||
|
# return "(" + "".join(list(map(lambda x: self.getJVMType(x),
|
||||||
|
# inType.partype))) + ")" + self.getJVMType(inType.rettype)
|
||||||
|
elif typeIn is ClassType:
|
||||||
|
return "L" + inType.cname + ";"
|
||||||
|
|
||||||
|
def getFullType(inType):
|
||||||
|
typeIn = type(inType)
|
||||||
|
if typeIn is IntType:
|
||||||
|
return "int"
|
||||||
|
elif typeIn is StringType:
|
||||||
|
return "java/lang/String"
|
||||||
|
elif typeIn is VoidType:
|
||||||
|
return "void"
|
||||||
|
|
||||||
|
def emitPUSHICONST(self, in_, frame):
|
||||||
|
# in: Int or Sring
|
||||||
|
# frame: Frame
|
||||||
|
|
||||||
|
frame.push()
|
||||||
|
if isinstance(in_, int):
|
||||||
|
i = in_
|
||||||
|
if i >= -1 and i <= 5:
|
||||||
|
return self.jvm.emitICONST(i)
|
||||||
|
elif i >= -128 and i <= 127:
|
||||||
|
return self.jvm.emitBIPUSH(i)
|
||||||
|
elif i >= -32768 and i <= 32767:
|
||||||
|
return self.jvm.emitSIPUSH(i)
|
||||||
|
elif isinstance(in_, str):
|
||||||
|
if in_ == "true":
|
||||||
|
return self.emitPUSHICONST(1, frame)
|
||||||
|
elif in_ == "false":
|
||||||
|
return self.emitPUSHICONST(0, frame)
|
||||||
|
else:
|
||||||
|
return self.emitPUSHICONST(int(in_), frame)
|
||||||
|
|
||||||
|
def emitPUSHFCONST(self, in_, frame):
|
||||||
|
# in_: String
|
||||||
|
# frame: Frame
|
||||||
|
|
||||||
|
f = float(in_)
|
||||||
|
frame.push()
|
||||||
|
rst = "{0:.4f}".format(f)
|
||||||
|
if rst == "0.0" or rst == "1.0" or rst == "2.0":
|
||||||
|
return self.jvm.emitFCONST(rst)
|
||||||
|
else:
|
||||||
|
return self.jvm.emitLDC(in_)
|
||||||
|
|
||||||
|
'''
|
||||||
|
* generate code to push a constant onto the operand stack.
|
||||||
|
* @param in the lexeme of the constant
|
||||||
|
* @param typ the type of the constant
|
||||||
|
'''
|
||||||
|
|
||||||
|
def emitPUSHCONST(self, in_, typ, frame):
|
||||||
|
# in_: String
|
||||||
|
# typ: Type
|
||||||
|
# frame: Frame
|
||||||
|
|
||||||
|
if isinstance(typ, IntType):
|
||||||
|
return self.emitPUSHICONST(in_, frame)
|
||||||
|
elif isinstance(typ, BoolType):
|
||||||
|
return self.emitPUSHICONST(in_, frame)
|
||||||
|
elif isinstance(typ, StringType):
|
||||||
|
frame.push()
|
||||||
|
return self.jvm.emitLDC(in_)
|
||||||
|
else:
|
||||||
|
raise IllegalOperandException(in_)
|
||||||
|
|
||||||
|
###############################################
|
||||||
|
|
||||||
|
def emitALOAD(self, in_, frame):
|
||||||
|
# in_: Type
|
||||||
|
# frame: Frame
|
||||||
|
# ..., arrayref, index, value -> ...
|
||||||
|
|
||||||
|
frame.pop()
|
||||||
|
if isinstance(in_, IntType):
|
||||||
|
return self.jvm.emitIALOAD()
|
||||||
|
elif isinstance(in_, ArrayPointerType) or\
|
||||||
|
isinstance(in_, ClassType) or\
|
||||||
|
isinstance(in_, StringType):
|
||||||
|
return self.jvm.emitAALOAD()
|
||||||
|
else:
|
||||||
|
raise IllegalOperandException(str(in_))
|
||||||
|
|
||||||
|
def emitASTORE(self, in_, frame):
|
||||||
|
# in_: Type
|
||||||
|
# frame: Frame
|
||||||
|
# ..., arrayref, index, value -> ...
|
||||||
|
|
||||||
|
frame.pop()
|
||||||
|
frame.pop()
|
||||||
|
frame.pop()
|
||||||
|
if isinstance(in_, IntType):
|
||||||
|
return self.jvm.emitIASTORE()
|
||||||
|
elif isinstance(in_, ArrayPointerType) or\
|
||||||
|
isinstance(in_, ClassType) or\
|
||||||
|
isinstance(in_, StringType):
|
||||||
|
return self.jvm.emitAASTORE()
|
||||||
|
else:
|
||||||
|
raise IllegalOperandException(str(in_))
|
||||||
|
|
||||||
|
''' generate the var directive for a local variable.
|
||||||
|
* @param in the index of the local variable.
|
||||||
|
* @param varName the name of the local variable.
|
||||||
|
* @param inType the type of the local variable.
|
||||||
|
* @param fromLabel the starting label of the scope
|
||||||
|
* where the variable is active.
|
||||||
|
* @param toLabel the ending label of the scope
|
||||||
|
* where the variable is active.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def emitVAR(self, in_, varName, inType, fromLabel, toLabel, frame):
|
||||||
|
# in_: Int
|
||||||
|
# varName: String
|
||||||
|
# inType: Type
|
||||||
|
# fromLabel: Int
|
||||||
|
# toLabel: Int
|
||||||
|
# frame: Frame
|
||||||
|
|
||||||
|
return self.jvm.emitVAR(
|
||||||
|
in_,
|
||||||
|
varName,
|
||||||
|
self.getJVMType(inType),
|
||||||
|
fromLabel,
|
||||||
|
toLabel)
|
||||||
|
|
||||||
|
def emitREADVAR(self, name, inType, index, frame):
|
||||||
|
# name: String
|
||||||
|
# inType: Type
|
||||||
|
# index: Int
|
||||||
|
# frame: Frame
|
||||||
|
# ... -> ..., value
|
||||||
|
|
||||||
|
frame.push()
|
||||||
|
if isinstance(inType, (IntType, BoolType)):
|
||||||
|
return self.jvm.emitILOAD(index)
|
||||||
|
elif isinstance(inType, FloatType):
|
||||||
|
return self.jvm.emitFLOAD(index)
|
||||||
|
elif isinstance(inType, ArrayPointerType) or\
|
||||||
|
isinstance(inType, ClassType) or\
|
||||||
|
isinstance(inType, StringType):
|
||||||
|
return self.jvm.emitALOAD(index)
|
||||||
|
else:
|
||||||
|
raise IllegalOperandException(name)
|
||||||
|
|
||||||
|
''' generate the second instruction for array cell access
|
||||||
|
*
|
||||||
|
'''
|
||||||
|
|
||||||
|
def emitREADVAR2(self, name, typ, frame):
|
||||||
|
# name: String
|
||||||
|
# typ: Type
|
||||||
|
# frame: Frame
|
||||||
|
# ... -> ..., value
|
||||||
|
|
||||||
|
# frame.push()
|
||||||
|
raise IllegalOperandException(name)
|
||||||
|
|
||||||
|
'''
|
||||||
|
* generate code to pop a value on top of the operand stack
|
||||||
|
* and store it to a block-scoped variable.
|
||||||
|
* @param name the symbol entry of the variable.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def emitWRITEVAR(self, name, inType, index, frame):
|
||||||
|
# name: String
|
||||||
|
# inType: Type
|
||||||
|
# index: Int
|
||||||
|
# frame: Frame
|
||||||
|
# ..., value -> ...
|
||||||
|
|
||||||
|
frame.pop()
|
||||||
|
|
||||||
|
if isinstance(inType, (IntType, BoolType)):
|
||||||
|
return self.jvm.emitISTORE(index)
|
||||||
|
elif isinstance(inType, FloatType):
|
||||||
|
return self.jvm.emitFSTORE(index)
|
||||||
|
elif isinstance(inType, ArrayPointerType) or\
|
||||||
|
isinstance(inType, ClassType) or\
|
||||||
|
isinstance(inType, StringType):
|
||||||
|
return self.jvm.emitASTORE(index)
|
||||||
|
else:
|
||||||
|
raise IllegalOperandException(name)
|
||||||
|
|
||||||
|
''' generate the second instruction for array cell access
|
||||||
|
*
|
||||||
|
'''
|
||||||
|
|
||||||
|
def emitWRITEVAR2(self, name, typ, frame):
|
||||||
|
# name: String
|
||||||
|
# typ: Type
|
||||||
|
# frame: Frame
|
||||||
|
# ..., value -> ...
|
||||||
|
|
||||||
|
# frame.push()
|
||||||
|
raise IllegalOperandException(name)
|
||||||
|
|
||||||
|
''' generate the field (static) directive for a class mutable or
|
||||||
|
* immutable attribute.
|
||||||
|
* @param lexeme the name of the attribute.
|
||||||
|
* @param in the type of the attribute.
|
||||||
|
* @param isFinal true in case of constant; false otherwise
|
||||||
|
'''
|
||||||
|
|
||||||
|
def emitATTRIBUTE(self, lexeme, in_, isFinal, value):
|
||||||
|
# lexeme: String
|
||||||
|
# in_: Type
|
||||||
|
# isFinal: Boolean
|
||||||
|
# value: String
|
||||||
|
|
||||||
|
return self.jvm.emitSTATICFIELD(lexeme, self.getJVMType(in_), False)
|
||||||
|
|
||||||
|
def emitGETSTATIC(self, lexeme, in_, frame):
|
||||||
|
# lexeme: String
|
||||||
|
# in_: Type
|
||||||
|
# frame: Frame
|
||||||
|
|
||||||
|
frame.push()
|
||||||
|
return self.jvm.emitGETSTATIC(lexeme, self.getJVMType(in_))
|
||||||
|
|
||||||
|
def emitPUTSTATIC(self, lexeme, in_, frame):
|
||||||
|
# lexeme: String
|
||||||
|
# in_: Type
|
||||||
|
# frame: Frame
|
||||||
|
|
||||||
|
frame.pop()
|
||||||
|
return self.jvm.emitPUTSTATIC(lexeme, self.getJVMType(in_))
|
||||||
|
|
||||||
|
def emitGETFIELD(self, lexeme, in_, frame):
|
||||||
|
# lexeme: String
|
||||||
|
# in_: Type
|
||||||
|
# frame: Frame
|
||||||
|
|
||||||
|
return self.jvm.emitGETFIELD(lexeme, self.getJVMType(in_))
|
||||||
|
|
||||||
|
def emitPUTFIELD(self, lexeme, in_, frame):
|
||||||
|
# lexeme: String
|
||||||
|
# in_: Type
|
||||||
|
# frame: Frame
|
||||||
|
|
||||||
|
frame.pop()
|
||||||
|
frame.pop()
|
||||||
|
return self.jvm.emitPUTFIELD(lexeme, self.getJVMType(in_))
|
||||||
|
|
||||||
|
''' generate code to invoke a static method
|
||||||
|
* @param lexeme the qualified name of the method
|
||||||
|
* (i.e., class-name/method-name)
|
||||||
|
* @param in the type descriptor of the method.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def emitINVOKESTATIC(self, lexeme, in_, frame):
|
||||||
|
# lexeme: String
|
||||||
|
# in_: Type
|
||||||
|
# frame: Frame
|
||||||
|
|
||||||
|
typ = in_
|
||||||
|
list(map(lambda x: frame.pop(), typ.partype))
|
||||||
|
if not isinstance(typ.rettype, VoidType):
|
||||||
|
frame.push()
|
||||||
|
return self.jvm.emitINVOKESTATIC(lexeme, self.getJVMType(in_))
|
||||||
|
|
||||||
|
''' generate code to invoke a special method
|
||||||
|
* @param lexeme the qualified name of the method
|
||||||
|
* (i.e., class-name/method-name)
|
||||||
|
* @param in the type descriptor of the method.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def emitINVOKESPECIAL(self, frame, lexeme=None, in_=None):
|
||||||
|
# lexeme: String
|
||||||
|
# in_: Type
|
||||||
|
# frame: Frame
|
||||||
|
|
||||||
|
if lexeme is not None and in_ is not None:
|
||||||
|
typ = in_
|
||||||
|
list(map(lambda x: frame.pop(), typ.partype))
|
||||||
|
frame.pop()
|
||||||
|
if not isinstance(typ.rettype, VoidType):
|
||||||
|
frame.push()
|
||||||
|
return self.jvm.emitINVOKESPECIAL(lexeme, self.getJVMType(in_))
|
||||||
|
elif lexeme is None and in_ is None:
|
||||||
|
frame.pop()
|
||||||
|
return self.jvm.emitINVOKESPECIAL()
|
||||||
|
|
||||||
|
''' generate code to invoke a virtual method
|
||||||
|
* @param lexeme the qualified name of the method
|
||||||
|
* (i.e., class-name/method-name)
|
||||||
|
* @param in the type descriptor of the method.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def emitINVOKEVIRTUAL(self, lexeme, in_, frame):
|
||||||
|
# lexeme: String
|
||||||
|
# in_: Type
|
||||||
|
# frame: Frame
|
||||||
|
|
||||||
|
typ = in_
|
||||||
|
list(map(lambda x: frame.pop(), typ.partype))
|
||||||
|
frame.pop()
|
||||||
|
if not isinstance(typ, VoidType):
|
||||||
|
frame.push()
|
||||||
|
return self.jvm.emitINVOKEVIRTUAL(lexeme, self.getJVMType(in_))
|
||||||
|
|
||||||
|
'''
|
||||||
|
* generate ineg, fneg.
|
||||||
|
* @param in the type of the operands.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def emitNEGOP(self, in_, frame):
|
||||||
|
# in_: Type
|
||||||
|
# frame: Frame
|
||||||
|
# ..., value -> ..., result
|
||||||
|
|
||||||
|
if isinstance(in_, IntType):
|
||||||
|
return self.jvm.emitINEG()
|
||||||
|
else:
|
||||||
|
return self.jvm.emitFNEG()
|
||||||
|
|
||||||
|
def emitNOT(self, in_, frame):
|
||||||
|
# in_: Type
|
||||||
|
# frame: Frame
|
||||||
|
|
||||||
|
label1 = frame.getNewLabel()
|
||||||
|
label2 = frame.getNewLabel()
|
||||||
|
result = list()
|
||||||
|
result.append(self.emitIFTRUE(label1, frame))
|
||||||
|
result.append(self.emitPUSHCONST("true", in_, frame))
|
||||||
|
result.append(self.emitGOTO(label2, frame))
|
||||||
|
result.append(self.emitLABEL(label1, frame))
|
||||||
|
result.append(self.emitPUSHCONST("false", in_, frame))
|
||||||
|
result.append(self.emitLABEL(label2, frame))
|
||||||
|
return ''.join(result)
|
||||||
|
|
||||||
|
'''
|
||||||
|
* generate iadd, isub, fadd or fsub.
|
||||||
|
* @param lexeme the lexeme of the operator.
|
||||||
|
* @param in the type of the operands.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def emitADDOP(self, lexeme, in_, frame):
|
||||||
|
# lexeme: String
|
||||||
|
# in_: Type
|
||||||
|
# frame: Frame
|
||||||
|
# ..., value1, value2 -> ..., result
|
||||||
|
|
||||||
|
frame.pop()
|
||||||
|
if lexeme == "+":
|
||||||
|
if isinstance(in_, IntType):
|
||||||
|
return self.jvm.emitIADD()
|
||||||
|
else:
|
||||||
|
return self.jvm.emitFADD()
|
||||||
|
else:
|
||||||
|
if isinstance(in_, IntType):
|
||||||
|
return self.jvm.emitISUB()
|
||||||
|
else:
|
||||||
|
return self.jvm.emitFSUB()
|
||||||
|
|
||||||
|
'''
|
||||||
|
* generate imul, idiv, fmul or fdiv.
|
||||||
|
* @param lexeme the lexeme of the operator.
|
||||||
|
* @param in the type of the operands.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def emitMULOP(self, lexeme, in_, frame):
|
||||||
|
# lexeme: String
|
||||||
|
# in_: Type
|
||||||
|
# frame: Frame
|
||||||
|
# ..., value1, value2 -> ..., result
|
||||||
|
|
||||||
|
frame.pop()
|
||||||
|
if lexeme == "*":
|
||||||
|
if isinstance(in_, IntType):
|
||||||
|
return self.jvm.emitIMUL()
|
||||||
|
else:
|
||||||
|
return self.jvm.emitFMUL()
|
||||||
|
else:
|
||||||
|
if isinstance(in_, IntType):
|
||||||
|
return self.jvm.emitIDIV()
|
||||||
|
else:
|
||||||
|
return self.jvm.emitFDIV()
|
||||||
|
|
||||||
|
def emitDIV(self, frame):
|
||||||
|
# frame: Frame
|
||||||
|
|
||||||
|
frame.pop()
|
||||||
|
return self.jvm.emitIDIV()
|
||||||
|
|
||||||
|
def emitMOD(self, frame):
|
||||||
|
# frame: Frame
|
||||||
|
|
||||||
|
frame.pop()
|
||||||
|
return self.jvm.emitIREM()
|
||||||
|
|
||||||
|
'''
|
||||||
|
* generate iand
|
||||||
|
'''
|
||||||
|
|
||||||
|
def emitANDOP(self, frame):
|
||||||
|
# frame: Frame
|
||||||
|
|
||||||
|
frame.pop()
|
||||||
|
return self.jvm.emitIAND()
|
||||||
|
|
||||||
|
'''
|
||||||
|
* generate ior
|
||||||
|
'''
|
||||||
|
|
||||||
|
def emitOROP(self, frame):
|
||||||
|
# frame: Frame
|
||||||
|
|
||||||
|
frame.pop()
|
||||||
|
return self.jvm.emitIOR()
|
||||||
|
|
||||||
|
def emitREOP(self, op, in_, frame):
|
||||||
|
# op: String
|
||||||
|
# in_: Type
|
||||||
|
# frame: Frame
|
||||||
|
# ..., value1, value2 -> ..., result
|
||||||
|
|
||||||
|
result = list()
|
||||||
|
labelF = frame.getNewLabel()
|
||||||
|
labelO = frame.getNewLabel()
|
||||||
|
|
||||||
|
frame.pop()
|
||||||
|
frame.pop()
|
||||||
|
|
||||||
|
if isinstance(in_, FloatType):
|
||||||
|
frame.push()
|
||||||
|
result.append(self.jvm.emitFCMPL())
|
||||||
|
result.append(self.emitPUSHICONST(0, frame))
|
||||||
|
frame.pop()
|
||||||
|
|
||||||
|
if op == ">":
|
||||||
|
result.append(self.jvm.emitIFICMPLE(labelF))
|
||||||
|
elif op == ">=":
|
||||||
|
result.append(self.jvm.emitIFICMPLT(labelF))
|
||||||
|
elif op == "<":
|
||||||
|
result.append(self.jvm.emitIFICMPGE(labelF))
|
||||||
|
elif op == "<=":
|
||||||
|
result.append(self.jvm.emitIFICMPGT(labelF))
|
||||||
|
elif op == "<>":
|
||||||
|
result.append(self.jvm.emitIFICMPEQ(labelF))
|
||||||
|
elif op == "=":
|
||||||
|
result.append(self.jvm.emitIFICMPNE(labelF))
|
||||||
|
result.append(self.emitPUSHCONST("1", IntType(), frame))
|
||||||
|
frame.pop()
|
||||||
|
result.append(self.emitGOTO(labelO, frame))
|
||||||
|
result.append(self.emitLABEL(labelF, frame))
|
||||||
|
result.append(self.emitPUSHCONST("0", IntType(), frame))
|
||||||
|
result.append(self.emitLABEL(labelO, frame))
|
||||||
|
return ''.join(result)
|
||||||
|
|
||||||
|
def emitRELOP(self, op, in_, trueLabel, falseLabel, frame):
|
||||||
|
# op: String
|
||||||
|
# in_: Type
|
||||||
|
# trueLabel: Int
|
||||||
|
# falseLabel: Int
|
||||||
|
# frame: Frame
|
||||||
|
# ..., value1, value2 -> ..., result
|
||||||
|
|
||||||
|
result = list()
|
||||||
|
|
||||||
|
frame.pop()
|
||||||
|
frame.pop()
|
||||||
|
if op == ">":
|
||||||
|
result.append(self.jvm.emitIFICMPLE(falseLabel))
|
||||||
|
result.append(self.emitGOTO(trueLabel))
|
||||||
|
elif op == ">=":
|
||||||
|
result.append(self.jvm.emitIFICMPLT(falseLabel))
|
||||||
|
elif op == "<":
|
||||||
|
result.append(self.jvm.emitIFICMPGE(falseLabel))
|
||||||
|
elif op == "<=":
|
||||||
|
result.append(self.jvm.emitIFICMPGT(falseLabel))
|
||||||
|
elif op == "!=":
|
||||||
|
result.append(self.jvm.emitIFICMPEQ(falseLabel))
|
||||||
|
elif op == "==":
|
||||||
|
result.append(self.jvm.emitIFICMPNE(falseLabel))
|
||||||
|
result.append(self.jvm.emitGOTO(trueLabel))
|
||||||
|
return ''.join(result)
|
||||||
|
|
||||||
|
''' generate the method directive for a function.
|
||||||
|
* @param lexeme the qualified name of the method
|
||||||
|
* (i.e., class-name/method-name).
|
||||||
|
* @param in the type descriptor of the method.
|
||||||
|
* @param isStatic <code>true</code> if the method is static;
|
||||||
|
* <code>false</code> otherwise.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def emitMETHOD(self, lexeme, in_, isStatic, frame):
|
||||||
|
# lexeme: String
|
||||||
|
# in_: Type
|
||||||
|
# isStatic: Boolean
|
||||||
|
# frame: Frame
|
||||||
|
|
||||||
|
return self.jvm.emitMETHOD(lexeme, self.getJVMType(in_), isStatic)
|
||||||
|
|
||||||
|
''' generate the end directive for a function.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def emitENDMETHOD(self, frame):
|
||||||
|
# frame: Frame
|
||||||
|
|
||||||
|
buffer = list()
|
||||||
|
buffer.append(self.jvm.emitLIMITSTACK(frame.getMaxOpStackSize()))
|
||||||
|
buffer.append(self.jvm.emitLIMITLOCAL(frame.getMaxIndex()))
|
||||||
|
buffer.append(self.jvm.emitENDMETHOD())
|
||||||
|
return ''.join(buffer)
|
||||||
|
|
||||||
|
def getConst(self, ast):
|
||||||
|
# ast: Literal
|
||||||
|
if isinstance(ast, IntLiteral):
|
||||||
|
return (str(ast.value), IntType())
|
||||||
|
|
||||||
|
''' generate code to initialize a local array variable.<p>
|
||||||
|
* @param index the index of the local variable.
|
||||||
|
* @param in the type of the local array variable.
|
||||||
|
'''
|
||||||
|
|
||||||
|
''' generate code to initialize local array variables.
|
||||||
|
* @param in the list of symbol entries corresponding to
|
||||||
|
* local array variable.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def emitIFEQ(self, label, frame):
|
||||||
|
frame.pop()
|
||||||
|
return self.jvm.emitIFEQ(label)
|
||||||
|
|
||||||
|
def emitIFNE(self, label, frame):
|
||||||
|
frame.pop()
|
||||||
|
return self.jvm.emitIFNE(label)
|
||||||
|
|
||||||
|
''' generate code to jump to label if the value on top of
|
||||||
|
* operand stack is true.<p>
|
||||||
|
* ifgt label
|
||||||
|
* @param label the label where the execution continues if
|
||||||
|
* the value on top of stack is true.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def emitIFTRUE(self, label, frame):
|
||||||
|
# label: Int
|
||||||
|
# frame: Frame
|
||||||
|
|
||||||
|
frame.pop()
|
||||||
|
return self.jvm.emitIFGT(label)
|
||||||
|
|
||||||
|
'''
|
||||||
|
* generate code to jump to label if the value on top of
|
||||||
|
* operand stack is false.<p>
|
||||||
|
* ifle label
|
||||||
|
* @param label the label where the execution continues if
|
||||||
|
* the value on top of stack is false.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def emitIFFALSE(self, label, frame):
|
||||||
|
# label: Int
|
||||||
|
# frame: Frame
|
||||||
|
|
||||||
|
frame.pop()
|
||||||
|
return self.jvm.emitIFLE(label)
|
||||||
|
|
||||||
|
def emitIFICMPGT(self, label, frame):
|
||||||
|
# label: Int
|
||||||
|
# frame: Frame
|
||||||
|
|
||||||
|
frame.pop()
|
||||||
|
return self.jvm.emitIFICMPGT(label)
|
||||||
|
|
||||||
|
def emitIFICMPLT(self, label, frame):
|
||||||
|
# label: Int
|
||||||
|
# frame: Frame
|
||||||
|
|
||||||
|
frame.pop()
|
||||||
|
return self.jvm.emitIFICMPLT(label)
|
||||||
|
|
||||||
|
''' generate code to duplicate the value on the top of the operand stack.<p>
|
||||||
|
* Stack:<p>
|
||||||
|
* Before: ...,value1<p>
|
||||||
|
* After: ...,value1,value1<p>
|
||||||
|
'''
|
||||||
|
|
||||||
|
def emitDUP(self, frame):
|
||||||
|
# frame: Frame
|
||||||
|
|
||||||
|
frame.push()
|
||||||
|
return self.jvm.emitDUP()
|
||||||
|
|
||||||
|
def emitPOP(self, frame):
|
||||||
|
# frame: Frame
|
||||||
|
|
||||||
|
frame.pop()
|
||||||
|
return self.jvm.emitPOP()
|
||||||
|
|
||||||
|
''' generate code to exchange an integer on top of
|
||||||
|
stack to a floating-point number.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def emitI2F(self, frame):
|
||||||
|
# frame: Frame
|
||||||
|
|
||||||
|
return self.jvm.emitI2F()
|
||||||
|
|
||||||
|
''' generate code to return.
|
||||||
|
* <ul>
|
||||||
|
* <li>ireturn if the type is IntegerType or BooleanType
|
||||||
|
* <li>freturn if the type is RealType
|
||||||
|
* <li>return if the type is null
|
||||||
|
* </ul>
|
||||||
|
* @param in the type of the returned expression.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def emitRETURN(self, in_, frame):
|
||||||
|
# in_: Type
|
||||||
|
# frame: Frame
|
||||||
|
|
||||||
|
if isinstance(in_, (IntType, BoolType)):
|
||||||
|
frame.pop()
|
||||||
|
return self.jvm.emitIRETURN()
|
||||||
|
elif isinstance(in_, FloatType):
|
||||||
|
frame.pop()
|
||||||
|
return self.jvm.emitFRETURN()
|
||||||
|
elif isinstance(in_, VoidType):
|
||||||
|
return self.jvm.emitRETURN()
|
||||||
|
|
||||||
|
''' generate code that represents a label
|
||||||
|
* @param label the label
|
||||||
|
* @return code Label<label>:
|
||||||
|
'''
|
||||||
|
|
||||||
|
def emitLABEL(self, label, frame):
|
||||||
|
# label: Int
|
||||||
|
# frame: Frame
|
||||||
|
|
||||||
|
return self.jvm.emitLABEL(label)
|
||||||
|
|
||||||
|
''' generate code to jump to a label
|
||||||
|
* @param label the label
|
||||||
|
* @return code goto Label<label>
|
||||||
|
'''
|
||||||
|
|
||||||
|
def emitGOTO(self, label, frame):
|
||||||
|
# label: Int
|
||||||
|
# frame: Frame
|
||||||
|
|
||||||
|
return self.jvm.emitGOTO(label)
|
||||||
|
|
||||||
|
''' generate some starting directives for a class.<p>
|
||||||
|
* .source MPC.CLASSNAME.java<p>
|
||||||
|
* .class public MPC.CLASSNAME<p>
|
||||||
|
* .super java/lang/Object<p>
|
||||||
|
'''
|
||||||
|
|
||||||
|
def emitPROLOG(self, name, parent):
|
||||||
|
# name: String
|
||||||
|
# parent: String
|
||||||
|
|
||||||
|
result = list()
|
||||||
|
result.append(self.jvm.emitSOURCE(name + ".java"))
|
||||||
|
result.append(self.jvm.emitCLASS("public " + name))
|
||||||
|
result.append(
|
||||||
|
self.jvm.emitSUPER(
|
||||||
|
"java/land/Object" if parent == "" else parent))
|
||||||
|
return ''.join(result)
|
||||||
|
|
||||||
|
def emitLIMITSTACK(self, num):
|
||||||
|
# num: Int
|
||||||
|
|
||||||
|
return self.jvm.emitLIMITSTACK(num)
|
||||||
|
|
||||||
|
def emitLIMITLOCAL(self, num):
|
||||||
|
# num: Int
|
||||||
|
|
||||||
|
return self.jvm.emitLIMITLOCAL(num)
|
||||||
|
|
||||||
|
def emitEPILOG(self):
|
||||||
|
file = open(self.filename, "w")
|
||||||
|
file.write(''.join(self.buff))
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
''' print out the code to screen
|
||||||
|
* @param in the code to be printed out
|
||||||
|
'''
|
||||||
|
|
||||||
|
def printout(self, in_):
|
||||||
|
# in_: String
|
||||||
|
|
||||||
|
self.buff.append(in_)
|
||||||
|
|
||||||
|
def clearBuff(self):
|
||||||
|
self.buff.clear()
|
206
codegen/Frame.py
Normal file
206
codegen/Frame.py
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
# from Utils import (
|
||||||
|
# # IllegalEscape,
|
||||||
|
# # IllegalOperandException,
|
||||||
|
# # IllegalRuntimeException
|
||||||
|
# )
|
||||||
|
from codegen.CodeGenError import (
|
||||||
|
# IllegalOperandException,
|
||||||
|
IllegalRuntimeException
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Frame():
|
||||||
|
def __init__(self, name, returnType):
|
||||||
|
# name: String
|
||||||
|
# returnType: Type
|
||||||
|
|
||||||
|
self.name = name
|
||||||
|
self.returnType = returnType
|
||||||
|
self.currentLabel = 0
|
||||||
|
self.currOpStackSize = 0
|
||||||
|
self.maxOpStackSize = 0
|
||||||
|
self.currIndex = 0
|
||||||
|
self.maxIndex = 0
|
||||||
|
self.startLabel = list()
|
||||||
|
self.endLabel = list()
|
||||||
|
self.indexLocal = list()
|
||||||
|
self.conLabel = list()
|
||||||
|
self.brkLabel = list()
|
||||||
|
|
||||||
|
def getCurrIndex(self):
|
||||||
|
return self.currIndex
|
||||||
|
|
||||||
|
def setCurrIndex(self, index):
|
||||||
|
# index: Int
|
||||||
|
|
||||||
|
self.currIndex = index
|
||||||
|
|
||||||
|
'''
|
||||||
|
* return a new label in the method.
|
||||||
|
* @return an integer representing the label.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def getNewLabel(self):
|
||||||
|
tmp = self.currentLabel
|
||||||
|
self.currentLabel = self.currentLabel + 1
|
||||||
|
return tmp
|
||||||
|
|
||||||
|
'''
|
||||||
|
* simulate an instruction that pushes a value onto operand stack.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def push(self):
|
||||||
|
self.currOpStackSize = self.currOpStackSize + 1
|
||||||
|
if self.maxOpStackSize < self.currOpStackSize:
|
||||||
|
self.maxOpStackSize = self.currOpStackSize
|
||||||
|
|
||||||
|
'''
|
||||||
|
* simulate an instruction that pops a value out of operand stack.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def pop(self):
|
||||||
|
self.currOpStackSize = self.currOpStackSize - 1
|
||||||
|
if self.currOpStackSize < 0:
|
||||||
|
raise IllegalRuntimeException("Pop empty stack")
|
||||||
|
|
||||||
|
def getStackSize(self):
|
||||||
|
return self.currOpStackSize
|
||||||
|
|
||||||
|
'''
|
||||||
|
* return the maximum size of the operand stack that
|
||||||
|
* the method needs to use.
|
||||||
|
* @return an integer that represent the maximum stack size
|
||||||
|
'''
|
||||||
|
|
||||||
|
def getMaxOpStackSize(self):
|
||||||
|
return self.maxOpStackSize
|
||||||
|
|
||||||
|
'''
|
||||||
|
* check if the operand stack is empty or not.
|
||||||
|
* @throws IllegalRuntimeException if the operand stack is not empty.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def checkOpStack(self):
|
||||||
|
if self.currOpStackSize != 0:
|
||||||
|
raise IllegalRuntimeException("Stack not empty")
|
||||||
|
|
||||||
|
'''
|
||||||
|
* invoked when parsing into a new scope inside a method.<p>
|
||||||
|
* This method will create 2 new labels that represent the starting
|
||||||
|
* and ending points of the scope.<p>
|
||||||
|
* Then, these labels are pushed onto corresponding stacks.<p>
|
||||||
|
* These labels can be retrieved by getStartLabel() and getEndLabel().<p>
|
||||||
|
* In addition, this method also saves the current index of local variable
|
||||||
|
'''
|
||||||
|
|
||||||
|
def enterScope(self, isProc):
|
||||||
|
# isProc: Boolean
|
||||||
|
start = self.getNewLabel()
|
||||||
|
end = self.getNewLabel()
|
||||||
|
self.startLabel.append(start)
|
||||||
|
self.endLabel.append(end)
|
||||||
|
self.indexLocal.append(self.currIndex)
|
||||||
|
if isProc:
|
||||||
|
self.maxOpStackSize = 0
|
||||||
|
self.maxIndex = 0
|
||||||
|
|
||||||
|
'''
|
||||||
|
* invoked when parsing out of a scope in a method.<p>
|
||||||
|
* This method will pop the starting and ending labels of this scope
|
||||||
|
* and restore the current index
|
||||||
|
'''
|
||||||
|
|
||||||
|
def exitScope(self):
|
||||||
|
if not self.startLabel or not self.endLabel or not self.indexLocal:
|
||||||
|
raise IllegalRuntimeException("Error when exit scope")
|
||||||
|
self.startLabel.pop()
|
||||||
|
self.endLabel.pop()
|
||||||
|
self.currIndex = self.indexLocal.pop()
|
||||||
|
|
||||||
|
'''
|
||||||
|
* return the starting label of the current scope.
|
||||||
|
* @return an integer representing the starting label
|
||||||
|
'''
|
||||||
|
|
||||||
|
def getStartLabel(self):
|
||||||
|
if not self.startLabel:
|
||||||
|
raise IllegalRuntimeException("None start label")
|
||||||
|
return self.startLabel[-1]
|
||||||
|
|
||||||
|
'''
|
||||||
|
* return the ending label of the current scope.
|
||||||
|
* @return an integer representing the ending label
|
||||||
|
'''
|
||||||
|
|
||||||
|
def getEndLabel(self):
|
||||||
|
if not self.endLabel:
|
||||||
|
raise IllegalRuntimeException("None end label")
|
||||||
|
return self.endLabel[-1]
|
||||||
|
|
||||||
|
'''
|
||||||
|
* return a new index for a local variable declared in a scope.
|
||||||
|
* @return an integer that represents the index of the local variable
|
||||||
|
'''
|
||||||
|
|
||||||
|
def getNewIndex(self):
|
||||||
|
tmp = self.currIndex
|
||||||
|
self.currIndex = self.currIndex + 1
|
||||||
|
if self.currIndex > self.maxIndex:
|
||||||
|
self.maxIndex = self.currIndex
|
||||||
|
return tmp
|
||||||
|
|
||||||
|
'''
|
||||||
|
* return the maximum index used in generating code for the current method
|
||||||
|
* @return an integer representing the maximum index
|
||||||
|
'''
|
||||||
|
|
||||||
|
def getMaxIndex(self):
|
||||||
|
return self.maxIndex
|
||||||
|
|
||||||
|
'''
|
||||||
|
* invoked when parsing into a loop statement.<p>
|
||||||
|
* This method creates 2 new labels that represent the starting and
|
||||||
|
* ending label of the loop.<p>
|
||||||
|
* These labels are pushed onto corresponding stacks and are
|
||||||
|
* retrieved by getBeginLoopLabel() and getEndLoopLabel().
|
||||||
|
'''
|
||||||
|
|
||||||
|
def enterLoop(self):
|
||||||
|
con = self.getNewLabel()
|
||||||
|
brk = self.getNewLabel()
|
||||||
|
self.conLabel.append(con)
|
||||||
|
self.brkLabel.append(brk)
|
||||||
|
|
||||||
|
'''
|
||||||
|
* invoked when parsing out of a loop statement.
|
||||||
|
* This method will take 2 labels representing the starting and
|
||||||
|
* ending labels of the current loop out of its stacks.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def exitLoop(self):
|
||||||
|
if not self.conLabel or not self.brkLabel:
|
||||||
|
raise IllegalRuntimeException("Error when exit loop")
|
||||||
|
self.conLabel.pop()
|
||||||
|
self.brkLabel.pop()
|
||||||
|
|
||||||
|
'''
|
||||||
|
* return the label of the innest enclosing loop to which continue
|
||||||
|
* statement would jump
|
||||||
|
* @return an integer representing the continue label
|
||||||
|
'''
|
||||||
|
|
||||||
|
def getContinueLabel(self):
|
||||||
|
if not self.conLabel:
|
||||||
|
raise IllegalRuntimeException("None continue label")
|
||||||
|
return self.conLabel[-1]
|
||||||
|
|
||||||
|
'''
|
||||||
|
* return the label of the innest enclosing loop to which break
|
||||||
|
* statement would jump
|
||||||
|
* @return an integer representing the break label
|
||||||
|
'''
|
||||||
|
|
||||||
|
def getBreakLabel(self):
|
||||||
|
if not self.brkLabel:
|
||||||
|
raise IllegalRuntimeException("None break label")
|
||||||
|
return self.brkLabel[-1]
|
776
codegen/MachineCode.py
Normal file
776
codegen/MachineCode.py
Normal file
@ -0,0 +1,776 @@
|
|||||||
|
'''
|
||||||
|
* @author Dr.Nguyen Hua Phung
|
||||||
|
* @version 1.0
|
||||||
|
* 28/6/2006
|
||||||
|
* This class provides facilities for method generation
|
||||||
|
*
|
||||||
|
'''
|
||||||
|
from abc import ABC, abstractmethod # , ABCMeta
|
||||||
|
from codegen.CodeGenError import (
|
||||||
|
IllegalOperandException
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class MachineCode(ABC):
|
||||||
|
@abstractmethod
|
||||||
|
def emitPUSHNULL(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitICONST(self, i):
|
||||||
|
# i: Int
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitBIPUSH(self, i):
|
||||||
|
# i: Int
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitSIPUSH(self, i):
|
||||||
|
# i: Int
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitLDC(self, in_):
|
||||||
|
# in_: String
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitFCONST(self, i):
|
||||||
|
# i: String
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitILOAD(self, in_):
|
||||||
|
# in_: Int
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitFLOAD(self, in_):
|
||||||
|
# in_: Int
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitISTORE(self, in_):
|
||||||
|
# in_: Int
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitFSTORE(self, in_):
|
||||||
|
# in_: Int
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitALOAD(self, in_):
|
||||||
|
# in_: Int
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitASTORE(self, in_):
|
||||||
|
# in_: Int
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitIASTORE(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitFASTORE(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitBASTORE(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitAASTORE(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitIALOAD(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitFALOAD(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitBALOAD(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitAALOAD(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitGETSTATIC(self, lexeme, typ):
|
||||||
|
# lexeme: String
|
||||||
|
# typ: String
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitPUTSTATIC(self, lexeme, typ):
|
||||||
|
# lexeme: String
|
||||||
|
# typ: String
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitGETFIELD(self, lexeme, typ):
|
||||||
|
# lexeme: String
|
||||||
|
# typ: String
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitPUTFIELD(self, lexeme, typ):
|
||||||
|
# lexeme: String
|
||||||
|
# typ: String
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitIADD(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitFADD(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitISUB(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitFSUB(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitIMUL(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitFMUL(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitIDIV(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitFDIV(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitIAND(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitIOR(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitIREM(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitIFACMPEQ(self, label):
|
||||||
|
# label: Int
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitIFACMPNE(self, label):
|
||||||
|
# label: Int
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitIFICMPEQ(self, label):
|
||||||
|
# label: Int
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitIFICMPNE(self, label):
|
||||||
|
# label: Int
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitIFICMPLT(self, label):
|
||||||
|
# label: Int
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitIFICMPLE(self, label):
|
||||||
|
# label: Int
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitIFICMPGT(self, label):
|
||||||
|
# label: Int
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitIFICMPGE(self, label):
|
||||||
|
# label: Int
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitIFEQ(self, label):
|
||||||
|
# label: Int
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitIFNE(self, label):
|
||||||
|
# label: Int
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitIFLT(self, label):
|
||||||
|
# label: Int
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitIFLE(self, label):
|
||||||
|
# label: Int
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitIFGT(self, label):
|
||||||
|
# label: Int
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitIFGE(self, label):
|
||||||
|
# label: Int
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitLABEL(self, label):
|
||||||
|
# label: Int
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitGOTO(self, label):
|
||||||
|
# label: Int
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitINEG(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitFNEG(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitDUP(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitDUPX2(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitPOP(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitI2F(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitNEW(self, lexeme):
|
||||||
|
# lexeme: String
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitNEWARRAY(self, lexeme):
|
||||||
|
# lexeme: String
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitANEWARRAY(self, lexeme):
|
||||||
|
# lexeme: String
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitMULTIANEWARRAY(self, typ, dimensions):
|
||||||
|
# typ: String
|
||||||
|
# dimensions: Int
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitINVOKESTATIC(self, lexeme, typ):
|
||||||
|
# lexeme: String
|
||||||
|
# typ: String
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitINVOKESPECIAL(self, lexeme=None, typ=None):
|
||||||
|
# lexeme: String
|
||||||
|
# typ: String
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitINVOKEVIRTUAL(self, lexeme, typ):
|
||||||
|
# lexeme: String
|
||||||
|
# typ: String
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitI(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitF(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emit(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitLIMITSTACK(self, in_):
|
||||||
|
# in_: String
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitFCMPL(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitLIMITLOCAL(self, in_):
|
||||||
|
# in_: String
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitVAR(self, in_, varName, inType, fromLabel, toLabel):
|
||||||
|
# in_: Int
|
||||||
|
# varName: String
|
||||||
|
# inType: String
|
||||||
|
# fromLabel: Int
|
||||||
|
# toLabel: Int
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitMETHOD(self, lexeme, typ, isStatic):
|
||||||
|
# lexeme: String
|
||||||
|
# typ: String
|
||||||
|
# isStaic: Boolean
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitENDMETHOD(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitSOURCE(self, lexeme):
|
||||||
|
# lexeme: String
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitCLASS(self, lexeme):
|
||||||
|
# lexeme: String
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitSUPER(self, lexeme):
|
||||||
|
# lexeme: String
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitSTATICFIELD(self, lexeme, typ, isFinal):
|
||||||
|
# lexeme: String
|
||||||
|
# typ: String
|
||||||
|
# isFinal: Boolean
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitINSTANCEFIELD(self, lexeme, typ):
|
||||||
|
# lexeme: String
|
||||||
|
# typ: String
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitRETURN(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitIRETURN(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitFRETURN(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def emitARETURN(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class JasminCode(MachineCode):
|
||||||
|
END = "\n"
|
||||||
|
INDENT = "\t"
|
||||||
|
|
||||||
|
def emitPUSHNULL(self):
|
||||||
|
return JasminCode.INDENT + "aconst_null" + JasminCode.END
|
||||||
|
|
||||||
|
def emitICONST(self, i):
|
||||||
|
# i: Int
|
||||||
|
if i == -1:
|
||||||
|
return JasminCode.INDENT + "iconst_ml" + JasminCode.END
|
||||||
|
elif i >= 0 or i <= 5:
|
||||||
|
return JasminCode.INDENT + "iconst_" + str(i) + JasminCode.END
|
||||||
|
else:
|
||||||
|
raise IllegalOperandException(str(i))
|
||||||
|
|
||||||
|
def emitBIPUSH(self, i):
|
||||||
|
# i: Int
|
||||||
|
if (i >= -128 and i < -1) or (i > 5 and i <= 127):
|
||||||
|
return JasminCode.INDENT + "bipush " + str(i) + JasminCode.END
|
||||||
|
else:
|
||||||
|
raise IllegalOperandException(str(i))
|
||||||
|
|
||||||
|
def emitSIPUSH(self, i):
|
||||||
|
# i: Int
|
||||||
|
if (i >= -32768 and i < -128) or (i > 127 and i <= 32767):
|
||||||
|
return JasminCode.INDENT + "sipush " + str(i) + JasminCode.END
|
||||||
|
else:
|
||||||
|
raise IllegalOperandException(str(i))
|
||||||
|
|
||||||
|
def emitLDC(self, in_):
|
||||||
|
# in_: String
|
||||||
|
return JasminCode.INDENT + "ldc " + in_ + JasminCode.END
|
||||||
|
|
||||||
|
def emitFCONST(self, i):
|
||||||
|
# i: String
|
||||||
|
if i == "0.0":
|
||||||
|
return JasminCode.INDENT + "fconst_0" + JasminCode.END
|
||||||
|
elif i == "1.0":
|
||||||
|
return JasminCode.INDENT + "fconst_1" + JasminCode.END
|
||||||
|
elif i == "2.0":
|
||||||
|
return JasminCode.INDENT + "fconst_2" + JasminCode.END
|
||||||
|
else:
|
||||||
|
raise IllegalOperandException(i)
|
||||||
|
|
||||||
|
def emitILOAD(self, in_):
|
||||||
|
# in_: Int
|
||||||
|
if in_ >= 0 and in_ <= 3:
|
||||||
|
return JasminCode.INDENT + "iload_" + str(in_) + JasminCode.END
|
||||||
|
else:
|
||||||
|
return JasminCode.INDENT + "iload " + str(in_) + JasminCode.END
|
||||||
|
|
||||||
|
def emitFLOAD(self, in_):
|
||||||
|
# in_: Int
|
||||||
|
if in_ >= 0 and in_ <= 3:
|
||||||
|
return JasminCode.INDENT + "fload_" + str(in_) + JasminCode.END
|
||||||
|
else:
|
||||||
|
return JasminCode.INDENT + "fload " + str(in_) + JasminCode.END
|
||||||
|
|
||||||
|
def emitISTORE(self, in_):
|
||||||
|
# in_: Int
|
||||||
|
if in_ >= 0 and in_ <= 3:
|
||||||
|
return JasminCode.INDENT + "istore_" + str(in_) + JasminCode.END
|
||||||
|
else:
|
||||||
|
return JasminCode.INDENT + "istore " + str(in_) + JasminCode.END
|
||||||
|
|
||||||
|
def emitFSTORE(self, in_):
|
||||||
|
# in_: Int
|
||||||
|
if in_ >= 0 and in_ <= 3:
|
||||||
|
return JasminCode.INDENT + "fstore_" + str(in_) + JasminCode.END
|
||||||
|
else:
|
||||||
|
return JasminCode.INDENT + "fstore " + str(in_) + JasminCode.END
|
||||||
|
|
||||||
|
def emitALOAD(self, in_):
|
||||||
|
# in_: Int
|
||||||
|
if in_ >= 0 and in_ <= 3:
|
||||||
|
return JasminCode.INDENT + "aload_" + str(in_) + JasminCode.END
|
||||||
|
else:
|
||||||
|
return JasminCode.INDENT + "aload " + str(in_) + JasminCode.END
|
||||||
|
|
||||||
|
def emitASTORE(self, in_):
|
||||||
|
# in_: Int
|
||||||
|
if in_ >= 0 and in_ <= 3:
|
||||||
|
return JasminCode.INDENT + "astore_" + str(in_) + JasminCode.END
|
||||||
|
else:
|
||||||
|
return JasminCode.INDENT + "astore " + str(in_) + JasminCode.END
|
||||||
|
|
||||||
|
def emitIASTORE(self):
|
||||||
|
return JasminCode.INDENT + "iastore" + JasminCode.END
|
||||||
|
|
||||||
|
def emitFASTORE(self):
|
||||||
|
return JasminCode.INDENT + "fastore" + JasminCode.END
|
||||||
|
|
||||||
|
def emitBASTORE(self):
|
||||||
|
return JasminCode.INDENT + "bastore" + JasminCode.END
|
||||||
|
|
||||||
|
def emitAASTORE(self):
|
||||||
|
return JasminCode.INDENT + "aastore" + JasminCode.END
|
||||||
|
|
||||||
|
def emitIALOAD(self):
|
||||||
|
return JasminCode.INDENT + "iaload" + JasminCode.END
|
||||||
|
|
||||||
|
def emitFALOAD(self):
|
||||||
|
return JasminCode.INDENT + "faload" + JasminCode.END
|
||||||
|
|
||||||
|
def emitBALOAD(self):
|
||||||
|
return JasminCode.INDENT + "baload" + JasminCode.END
|
||||||
|
|
||||||
|
def emitAALOAD(self):
|
||||||
|
return JasminCode.INDENT + "aaload" + JasminCode.END
|
||||||
|
|
||||||
|
def emitGETSTATIC(self, lexeme, typ):
|
||||||
|
# lexeme: String
|
||||||
|
# typ: String
|
||||||
|
return JasminCode.INDENT + "getstatic " + lexeme + " " + typ + JasminCode.END
|
||||||
|
|
||||||
|
def emitPUTSTATIC(self, lexeme, typ):
|
||||||
|
# lexeme: String
|
||||||
|
# typ: String
|
||||||
|
return JasminCode.INDENT + "putstatic " + lexeme + " " + typ + JasminCode.END
|
||||||
|
|
||||||
|
def emitGETFIELD(self, lexeme, typ):
|
||||||
|
# lexeme: String
|
||||||
|
# typ: String
|
||||||
|
return JasminCode.INDENT + "getfield " + lexeme + " " + typ + JasminCode.END
|
||||||
|
|
||||||
|
def emitPUTFIELD(self, lexeme, typ):
|
||||||
|
# lexeme: String
|
||||||
|
# typ: String
|
||||||
|
return JasminCode.INDENT + "putfield " + lexeme + " " + typ + JasminCode.END
|
||||||
|
|
||||||
|
def emitIADD(self):
|
||||||
|
return JasminCode.INDENT + "iadd" + JasminCode.END
|
||||||
|
|
||||||
|
def emitFADD(self):
|
||||||
|
return JasminCode.INDENT + "fadd" + JasminCode.END
|
||||||
|
|
||||||
|
def emitISUB(self):
|
||||||
|
return JasminCode.INDENT + "isub" + JasminCode.END
|
||||||
|
|
||||||
|
def emitFSUB(self):
|
||||||
|
return JasminCode.INDENT + "fsub" + JasminCode.END
|
||||||
|
|
||||||
|
def emitIMUL(self):
|
||||||
|
return JasminCode.INDENT + "imul" + JasminCode.END
|
||||||
|
|
||||||
|
def emitFMUL(self):
|
||||||
|
return JasminCode.INDENT + "fmul" + JasminCode.END
|
||||||
|
|
||||||
|
def emitIDIV(self):
|
||||||
|
return JasminCode.INDENT + "idiv" + JasminCode.END
|
||||||
|
|
||||||
|
def emitFDIV(self):
|
||||||
|
return JasminCode.INDENT + "fdiv" + JasminCode.END
|
||||||
|
|
||||||
|
def emitIAND(self):
|
||||||
|
return JasminCode.INDENT + "iand" + JasminCode.END
|
||||||
|
|
||||||
|
def emitIOR(self):
|
||||||
|
return JasminCode.INDENT + "ior" + JasminCode.END
|
||||||
|
|
||||||
|
def emitIREM(self):
|
||||||
|
return JasminCode.INDENT + "irem" + JasminCode.END
|
||||||
|
|
||||||
|
def emitIFACMPEQ(self, label):
|
||||||
|
# label: Int
|
||||||
|
return JasminCode.INDENT + "if_acmpeq Label" + \
|
||||||
|
str(label) + JasminCode.END
|
||||||
|
|
||||||
|
def emitIFACMPNE(self, label):
|
||||||
|
# label: Int
|
||||||
|
return JasminCode.INDENT + "if_acmpne Label" + \
|
||||||
|
str(label) + JasminCode.END
|
||||||
|
|
||||||
|
def emitIFICMPEQ(self, label):
|
||||||
|
# label: Int
|
||||||
|
return JasminCode.INDENT + "if_icmpeq Label" + \
|
||||||
|
str(label) + JasminCode.END
|
||||||
|
|
||||||
|
def emitIFICMPNE(self, label):
|
||||||
|
# label: Int
|
||||||
|
return JasminCode.INDENT + "if_icmpne Label" + \
|
||||||
|
str(label) + JasminCode.END
|
||||||
|
|
||||||
|
def emitIFICMPLT(self, label):
|
||||||
|
# label: Int
|
||||||
|
return JasminCode.INDENT + "if_icmplt Label" + \
|
||||||
|
str(label) + JasminCode.END
|
||||||
|
|
||||||
|
def emitIFICMPLE(self, label):
|
||||||
|
# label: Int
|
||||||
|
return JasminCode.INDENT + "if_icmple Label" + \
|
||||||
|
str(label) + JasminCode.END
|
||||||
|
|
||||||
|
def emitIFICMPGT(self, label):
|
||||||
|
# label: Int
|
||||||
|
return JasminCode.INDENT + "if_icmpgt Label" + \
|
||||||
|
str(label) + JasminCode.END
|
||||||
|
|
||||||
|
def emitIFICMPGE(self, label):
|
||||||
|
# label: Int
|
||||||
|
return JasminCode.INDENT + "if_icmpge Label" + \
|
||||||
|
str(label) + JasminCode.END
|
||||||
|
|
||||||
|
def emitIFEQ(self, label):
|
||||||
|
# label: Int
|
||||||
|
return JasminCode.INDENT + "ifeq Label" + str(label) + JasminCode.END
|
||||||
|
|
||||||
|
def emitIFNE(self, label):
|
||||||
|
# label: Int
|
||||||
|
return JasminCode.INDENT + "ifne Label" + str(label) + JasminCode.END
|
||||||
|
|
||||||
|
def emitIFLT(self, label):
|
||||||
|
# label: Int
|
||||||
|
return JasminCode.INDENT + "iflt Label" + str(label) + JasminCode.END
|
||||||
|
|
||||||
|
def emitIFLE(self, label):
|
||||||
|
# label: Int
|
||||||
|
return JasminCode.INDENT + "ifle Label" + str(label) + JasminCode.END
|
||||||
|
|
||||||
|
def emitIFGT(self, label):
|
||||||
|
# label: Int
|
||||||
|
return JasminCode.INDENT + "ifgt Label" + str(label) + JasminCode.END
|
||||||
|
|
||||||
|
def emitIFGE(self, label):
|
||||||
|
# label: Int
|
||||||
|
return JasminCode.INDENT + "ifge Label" + str(label) + JasminCode.END
|
||||||
|
|
||||||
|
def emitLABEL(self, label):
|
||||||
|
# label: Int
|
||||||
|
return "Label" + str(label) + ":" + JasminCode.END
|
||||||
|
|
||||||
|
def emitGOTO(self, label):
|
||||||
|
# label: Int
|
||||||
|
return JasminCode.INDENT + "goto Label" + str(label) + JasminCode.END
|
||||||
|
|
||||||
|
def emitINEG(self):
|
||||||
|
return JasminCode.INDENT + "ineg" + JasminCode.END
|
||||||
|
|
||||||
|
def emitFNEG(self):
|
||||||
|
return JasminCode.INDENT + "fneg" + JasminCode.END
|
||||||
|
|
||||||
|
def emitDUP(self):
|
||||||
|
return JasminCode.INDENT + "dup" + JasminCode.END
|
||||||
|
|
||||||
|
def emitDUPX2(self):
|
||||||
|
return JasminCode.INDENT + "dup_x2" + JasminCode.END
|
||||||
|
|
||||||
|
def emitPOP(self):
|
||||||
|
return JasminCode.INDENT + "pop" + JasminCode.END
|
||||||
|
|
||||||
|
def emitI2F(self):
|
||||||
|
return JasminCode.INDENT + "i2f" + JasminCode.END
|
||||||
|
|
||||||
|
def emitNEW(self, lexeme):
|
||||||
|
# lexeme: String
|
||||||
|
return JasminCode.INDENT + "new " + lexeme + JasminCode.END
|
||||||
|
|
||||||
|
def emitNEWARRAY(self, lexeme):
|
||||||
|
# lexeme: String
|
||||||
|
return JasminCode.INDENT + "newarray " + lexeme + JasminCode.END
|
||||||
|
|
||||||
|
def emitANEWARRAY(self, lexeme):
|
||||||
|
# lexeme: String
|
||||||
|
return JasminCode.INDENT + "anewarray " + lexeme + JasminCode.END
|
||||||
|
|
||||||
|
def emitMULTIANEWARRAY(self, typ, dimensions):
|
||||||
|
# typ: String
|
||||||
|
# dimensions: Int
|
||||||
|
return JasminCode.INDENT + "multianewarray " + \
|
||||||
|
typ + " " + dimensions + JasminCode.END
|
||||||
|
|
||||||
|
def emitINVOKESTATIC(self, lexeme, typ):
|
||||||
|
# lexeme: String
|
||||||
|
# typ: String
|
||||||
|
return JasminCode.INDENT + "invokestatic " + lexeme + typ + JasminCode.END
|
||||||
|
|
||||||
|
def emitINVOKESPECIAL(self, lexeme=None, typ=None):
|
||||||
|
# lexeme: String
|
||||||
|
# typ: String
|
||||||
|
if lexeme is None and typ is None:
|
||||||
|
return JasminCode.INDENT + "invokespecial java/lang/Object/<init>()V" + \
|
||||||
|
JasminCode.END
|
||||||
|
elif lexeme is not None and typ is not None:
|
||||||
|
return JasminCode.INDENT + "invokespecial " + lexeme + typ + JasminCode.END
|
||||||
|
|
||||||
|
def emitINVOKEVIRTUAL(self, lexeme, typ):
|
||||||
|
# lexeme: String
|
||||||
|
# typ: String
|
||||||
|
return JasminCode.INDENT + "invokevirtual " + lexeme + typ + JasminCode.END
|
||||||
|
|
||||||
|
def emitI(self):
|
||||||
|
return JasminCode.INDENT + "i" + JasminCode.END
|
||||||
|
|
||||||
|
def emitF(self):
|
||||||
|
return JasminCode.INDENT + "f" + JasminCode.END
|
||||||
|
|
||||||
|
def emit(self):
|
||||||
|
return JasminCode.INDENT + "" + JasminCode.END
|
||||||
|
|
||||||
|
def emitLIMITSTACK(self, in_):
|
||||||
|
# in_: Int
|
||||||
|
return ".limit stack " + str(in_) + JasminCode.END
|
||||||
|
|
||||||
|
def emitFCMPL(self):
|
||||||
|
return JasminCode.INDENT + "fcmpl" + JasminCode.END
|
||||||
|
|
||||||
|
def emitLIMITLOCAL(self, in_):
|
||||||
|
# in_: Int
|
||||||
|
return ".limit locals " + str(in_) + JasminCode.END
|
||||||
|
|
||||||
|
def emitVAR(self, in_, varName, inType, fromLabel, toLabel):
|
||||||
|
# in_: Int
|
||||||
|
# varName: String
|
||||||
|
# inType: String
|
||||||
|
# fromLabel: Int
|
||||||
|
# toLabel: Int
|
||||||
|
return ".var " + str(in_) + " is " + varName + " " + inType + " from Label" + \
|
||||||
|
str(fromLabel) + " to Label" + str(toLabel) + JasminCode.END
|
||||||
|
|
||||||
|
def emitMETHOD(self, lexeme, typ, isStatic):
|
||||||
|
# lexeme: String
|
||||||
|
# typ: String
|
||||||
|
# isStaic: Boolean
|
||||||
|
if isStatic:
|
||||||
|
return JasminCode.END + ".method public static " + lexeme + typ + JasminCode.END
|
||||||
|
else:
|
||||||
|
return JasminCode.END + ".method public " + lexeme + typ + JasminCode.END
|
||||||
|
|
||||||
|
def emitENDMETHOD(self):
|
||||||
|
return ".end method" + JasminCode.END
|
||||||
|
|
||||||
|
def emitSOURCE(self, lexeme):
|
||||||
|
# lexeme: String
|
||||||
|
return ".source " + lexeme + JasminCode.END
|
||||||
|
|
||||||
|
def emitCLASS(self, lexeme):
|
||||||
|
# lexeme: String
|
||||||
|
return ".class " + lexeme + JasminCode.END
|
||||||
|
|
||||||
|
def emitSUPER(self, lexeme):
|
||||||
|
# lexeme: String
|
||||||
|
return ".super " + lexeme + JasminCode.END
|
||||||
|
|
||||||
|
def emitSTATICFIELD(self, lexeme, typ, isFinal):
|
||||||
|
# lexeme: String
|
||||||
|
# typ: String
|
||||||
|
# isFinal: Boolean
|
||||||
|
if isFinal:
|
||||||
|
return ".field static final " + lexeme + " " + typ + JasminCode.END
|
||||||
|
else:
|
||||||
|
return ".field static " + lexeme + " " + typ + JasminCode.END
|
||||||
|
|
||||||
|
def emitINSTANCEFIELD(self, lexeme, typ):
|
||||||
|
# lexeme: String
|
||||||
|
# typ: String
|
||||||
|
return ".field " + lexeme + " " + typ + JasminCode.END
|
||||||
|
|
||||||
|
def emitRETURN(self):
|
||||||
|
return JasminCode.INDENT + "return" + JasminCode.END
|
||||||
|
|
||||||
|
def emitIRETURN(self):
|
||||||
|
return JasminCode.INDENT + "ireturn" + JasminCode.END
|
||||||
|
|
||||||
|
def emitFRETURN(self):
|
||||||
|
return JasminCode.INDENT + "freturn" + JasminCode.END
|
||||||
|
|
||||||
|
def emitARETURN(self):
|
||||||
|
return JasminCode.INDENT + "areturn" + JasminCode.END
|
0
codegen/__init__.py
Normal file
0
codegen/__init__.py
Normal file
37
genANTLR4.py
Normal file
37
genANTLR4.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
|
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'
|
||||||
|
|
||||||
|
|
||||||
|
def generate():
|
||||||
|
files_from_antlr4 = [
|
||||||
|
'MP.interp',
|
||||||
|
'MPLexer.interp',
|
||||||
|
'MPLexer.py',
|
||||||
|
'MPLexer.tokens',
|
||||||
|
'MPParser.py',
|
||||||
|
'MP.tokens',
|
||||||
|
'MPVisitor.py'
|
||||||
|
]
|
||||||
|
if all(list(map(os.path.isfile, files_from_antlr4))):
|
||||||
|
return
|
||||||
|
gen_antlr_class_cmd = [
|
||||||
|
"java",
|
||||||
|
"-jar",
|
||||||
|
ANTLR_JAR,
|
||||||
|
"-no-listener",
|
||||||
|
"-visitor",
|
||||||
|
"parser/MP.g4"
|
||||||
|
]
|
||||||
|
subprocess.run(gen_antlr_class_cmd)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
generate()
|
BIN
libs/io.class
Normal file
BIN
libs/io.class
Normal file
Binary file not shown.
156
libs/io.java
Normal file
156
libs/io.java
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
//import bkool.codegeneration.IllegalRuntimeException;
|
||||||
|
|
||||||
|
|
||||||
|
public class io {
|
||||||
|
//private static final DataInputStream input = new DataInputStream(System.in);
|
||||||
|
public static BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
|
||||||
|
public static Writer writer = new BufferedWriter(new OutputStreamWriter(System.out));
|
||||||
|
|
||||||
|
//public io(String name) throws IOException {
|
||||||
|
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
/** reads and returns an integer value from the standard input
|
||||||
|
* @return int an integer number read from standard input
|
||||||
|
*/
|
||||||
|
public static int getInt() {
|
||||||
|
String tmp = "";
|
||||||
|
try {
|
||||||
|
tmp = input.readLine();
|
||||||
|
return Integer.parseInt(tmp);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** print out the value of the integer i to the standard output
|
||||||
|
* @param i the value is printed out
|
||||||
|
*/
|
||||||
|
public static void putInt(int i) {
|
||||||
|
|
||||||
|
System.out.print(i+"");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** same as putInt except that it also prints a newline
|
||||||
|
* @param i the value is printed out
|
||||||
|
*/
|
||||||
|
public static void putIntLn(int i) {
|
||||||
|
System.out.println(i+"");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** return a floating-point value read from the standard input
|
||||||
|
* @return float the floating-point value
|
||||||
|
*/
|
||||||
|
public static float getFloat() {
|
||||||
|
String tmp ="";
|
||||||
|
try {
|
||||||
|
tmp = input.readLine();
|
||||||
|
return Float.parseFloat(tmp);
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
e.printStackTrace();;
|
||||||
|
}
|
||||||
|
catch (NumberFormatException e) {
|
||||||
|
e.printStackTrace();;
|
||||||
|
}
|
||||||
|
return 0.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** print out the value of the float f to the standard output
|
||||||
|
* @param f the floating-point value is printed out
|
||||||
|
*/
|
||||||
|
public static void putFloat(float f) {
|
||||||
|
System.out.print(f+"");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** same as putFloat except that it also prints a newline
|
||||||
|
* @param f the floating-point value is printed out
|
||||||
|
*/
|
||||||
|
public static void putFloatLn(float f) {
|
||||||
|
System.out.println(f+"");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** reads and returns a boolean value from the standard input
|
||||||
|
* @return int a boolean value read from standard input
|
||||||
|
*/
|
||||||
|
public static boolean getBool() {
|
||||||
|
String tmp = "";
|
||||||
|
try {
|
||||||
|
tmp = input.readLine();
|
||||||
|
if (tmp.equalsIgnoreCase("true"))
|
||||||
|
return true;
|
||||||
|
else //if (tmp.equalsIgnoreCase("false"))
|
||||||
|
return false;
|
||||||
|
// else throw new IllegalRuntimeException(tmp);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** print out the value of the boolean b to the standard output
|
||||||
|
* @param b the boolean value is printed out
|
||||||
|
*/
|
||||||
|
public static void putBool(boolean b) {
|
||||||
|
System.out.print(b+"");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** same as putBoolLn except that it also prints a new line
|
||||||
|
* @param b the boolean value is printed out
|
||||||
|
*/
|
||||||
|
public static void putBoolLn(boolean b) {
|
||||||
|
System.out.println(b+"");
|
||||||
|
}
|
||||||
|
/** reads and returns a boolean value from the standard input
|
||||||
|
* @return int a boolean value read from standard input
|
||||||
|
*/
|
||||||
|
/*public static String Str() {
|
||||||
|
String tmp = "";
|
||||||
|
try {
|
||||||
|
tmp = input.readLine();
|
||||||
|
return tmp;
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return tmp;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/** prints the value of the string to the standard output
|
||||||
|
* @param a the string is printed out
|
||||||
|
*/
|
||||||
|
public static void putString(String a ) {
|
||||||
|
System.out.print(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** same as putString except that it also prints a new line
|
||||||
|
* @param a the string is printed out
|
||||||
|
*/
|
||||||
|
public static void putStringLn(String a) {
|
||||||
|
System.out.println(a);
|
||||||
|
}
|
||||||
|
/** print out an empty line
|
||||||
|
**/
|
||||||
|
public static void putLn() {
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void close() {
|
||||||
|
try {
|
||||||
|
writer.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
112
mpc.py
Normal file
112
mpc.py
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
from antlr4 import FileStream, CommonTokenStream # Token
|
||||||
|
from antlr4.error.ErrorListener import ConsoleErrorListener # ErrorListener
|
||||||
|
|
||||||
|
try:
|
||||||
|
from parser.MPLexer import MPLexer as Lexer
|
||||||
|
from parser.MPParser import MPParser as Parser
|
||||||
|
from astgen.ASTGeneration import ASTGeneration
|
||||||
|
from checker.StaticCheck import StaticChecker
|
||||||
|
from codegen.CodeGenerator import CodeGenerator
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
print('Generate ANTLR4 first')
|
||||||
|
print('python genANTLR4.py')
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
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):
|
||||||
|
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 = os.path.dirname(inputfile)
|
||||||
|
filename = os.path.basename(inputfile).split('.')[0]
|
||||||
|
codeGen = CodeGenerator()
|
||||||
|
codeGen.gen(asttree, path, filename)
|
||||||
|
|
||||||
|
subprocess.call(
|
||||||
|
# "java -jar " + JASMIN_JAR + " " + path + "/MPClass.j",
|
||||||
|
"java -jar {} {}/{}.j -d {}".format(JASMIN_JAR, path, filename, 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 cvfm {}/{}.jar {}/manifest.mf {} {}.class'.format(
|
||||||
|
'jar cvfe {0}.jar {0} io.class {0}.class'.format(
|
||||||
|
filename
|
||||||
|
),
|
||||||
|
cwd=path,
|
||||||
|
shell=True,
|
||||||
|
stderr=subprocess.STDOUT
|
||||||
|
)
|
||||||
|
|
||||||
|
os.remove('{}/{}.j'.format(path, filename))
|
||||||
|
os.remove('{}/{}.class'.format(path, filename))
|
||||||
|
os.remove('{}/io.class'.format(path))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
argv = sys.argv
|
||||||
|
if len(argv) != 2:
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
try:
|
||||||
|
print("Compiling {}".format(os.path.relpath(argv[1])))
|
||||||
|
compile(argv[1])
|
||||||
|
except BaseException as e:
|
||||||
|
print(e)
|
||||||
|
exit(1)
|
||||||
|
print("Compiled successfully")
|
588
parser/MP.g4
Normal file
588
parser/MP.g4
Normal file
@ -0,0 +1,588 @@
|
|||||||
|
// 1611617
|
||||||
|
|
||||||
|
grammar MP;
|
||||||
|
|
||||||
|
@lexer::header {
|
||||||
|
from parser.lexererr import *
|
||||||
|
}
|
||||||
|
|
||||||
|
options{
|
||||||
|
language=Python3;
|
||||||
|
}
|
||||||
|
|
||||||
|
program
|
||||||
|
: manydecl EOF
|
||||||
|
;
|
||||||
|
|
||||||
|
manydecl
|
||||||
|
: decl manydecl
|
||||||
|
| decl
|
||||||
|
;
|
||||||
|
|
||||||
|
decl
|
||||||
|
: var_decl
|
||||||
|
| func_decl
|
||||||
|
| proc_decl
|
||||||
|
;
|
||||||
|
|
||||||
|
var_decl
|
||||||
|
: VAR varlist
|
||||||
|
;
|
||||||
|
|
||||||
|
varlist
|
||||||
|
: var SEMI varlist
|
||||||
|
| var SEMI
|
||||||
|
;
|
||||||
|
|
||||||
|
var
|
||||||
|
: idenlist COLON mptype
|
||||||
|
;
|
||||||
|
|
||||||
|
idenlist
|
||||||
|
: IDENT COMMA idenlist
|
||||||
|
| IDENT
|
||||||
|
;
|
||||||
|
|
||||||
|
mptype
|
||||||
|
: primitive_type
|
||||||
|
| compound_type
|
||||||
|
;
|
||||||
|
|
||||||
|
primitive_type
|
||||||
|
: INTEGER
|
||||||
|
| REAL
|
||||||
|
| BOOLEAN
|
||||||
|
| STRING
|
||||||
|
;
|
||||||
|
|
||||||
|
compound_type
|
||||||
|
: ARRAY array_value OF primitive_type
|
||||||
|
;
|
||||||
|
|
||||||
|
array_value
|
||||||
|
: LB MINUS? NUM_INT DOUBLE_DOT MINUS? NUM_INT RB
|
||||||
|
;
|
||||||
|
|
||||||
|
func_decl
|
||||||
|
: FUNCTION IDENT LR param_list? RR COLON mptype SEMI var_decl* compound_statement
|
||||||
|
;
|
||||||
|
|
||||||
|
param_list
|
||||||
|
: var SEMI param_list
|
||||||
|
| var
|
||||||
|
;
|
||||||
|
|
||||||
|
proc_decl
|
||||||
|
: PROCEDURE IDENT LR param_list? RR SEMI var_decl* compound_statement
|
||||||
|
;
|
||||||
|
|
||||||
|
expression
|
||||||
|
: expression (AND THEN | OR ELSE) expression_lv1
|
||||||
|
| expression_lv1
|
||||||
|
;
|
||||||
|
|
||||||
|
expression_lv1
|
||||||
|
: expression_lv2 (EQUAL | NOT_EQUAL | LT | LE | GE | GT) expression_lv2
|
||||||
|
| expression_lv2
|
||||||
|
;
|
||||||
|
|
||||||
|
expression_lv2
|
||||||
|
: expression_lv2 (PLUS | MINUS | OR) expression_lv3
|
||||||
|
| expression_lv3
|
||||||
|
;
|
||||||
|
|
||||||
|
expression_lv3
|
||||||
|
: expression_lv3 (STAR | SLASH | DIV | MOD | AND) expression_lv4
|
||||||
|
| expression_lv4
|
||||||
|
;
|
||||||
|
|
||||||
|
expression_lv4
|
||||||
|
: (NOT | MINUS) expression_lv4
|
||||||
|
| index_expression
|
||||||
|
;
|
||||||
|
|
||||||
|
index_expression
|
||||||
|
: index_expression LB expression RB
|
||||||
|
| factor
|
||||||
|
;
|
||||||
|
|
||||||
|
invocation_expression
|
||||||
|
: LR call_param? RR
|
||||||
|
;
|
||||||
|
|
||||||
|
factor
|
||||||
|
: LR expression RR
|
||||||
|
| literal
|
||||||
|
| IDENT
|
||||||
|
| IDENT invocation_expression
|
||||||
|
;
|
||||||
|
|
||||||
|
statement
|
||||||
|
: normal_statement SEMI
|
||||||
|
| structured_statement
|
||||||
|
;
|
||||||
|
|
||||||
|
structured_statement
|
||||||
|
: if_statement
|
||||||
|
| for_statement
|
||||||
|
| compound_statement
|
||||||
|
| with_statement
|
||||||
|
| while_statement
|
||||||
|
;
|
||||||
|
|
||||||
|
normal_statement
|
||||||
|
: assignment_statement
|
||||||
|
| break_statement
|
||||||
|
| continue_statement
|
||||||
|
| return_statement
|
||||||
|
| call_statement
|
||||||
|
;
|
||||||
|
|
||||||
|
assignment_statement
|
||||||
|
: assignment_lhs_list expression
|
||||||
|
;
|
||||||
|
|
||||||
|
assignment_lhs_list
|
||||||
|
: lhs ASSIGN assignment_lhs_list
|
||||||
|
| lhs ASSIGN
|
||||||
|
;
|
||||||
|
|
||||||
|
lhs
|
||||||
|
: index_expression
|
||||||
|
| IDENT
|
||||||
|
;
|
||||||
|
|
||||||
|
if_statement
|
||||||
|
: IF expression THEN statement (ELSE statement)?
|
||||||
|
;
|
||||||
|
|
||||||
|
while_statement
|
||||||
|
: WHILE expression DO statement
|
||||||
|
;
|
||||||
|
|
||||||
|
for_statement
|
||||||
|
: FOR IDENT ASSIGN expression (TO | DOWNTO) expression DO statement
|
||||||
|
;
|
||||||
|
|
||||||
|
break_statement
|
||||||
|
: BREAK
|
||||||
|
;
|
||||||
|
|
||||||
|
continue_statement
|
||||||
|
: CONTINUE
|
||||||
|
;
|
||||||
|
|
||||||
|
return_statement
|
||||||
|
: RETURN expression?
|
||||||
|
;
|
||||||
|
|
||||||
|
compound_statement
|
||||||
|
: BEGIN statement* END
|
||||||
|
;
|
||||||
|
|
||||||
|
with_statement
|
||||||
|
: WITH varlist DO statement
|
||||||
|
;
|
||||||
|
|
||||||
|
call_statement
|
||||||
|
: IDENT LR call_param? RR
|
||||||
|
;
|
||||||
|
|
||||||
|
call_param
|
||||||
|
: expression COMMA call_param
|
||||||
|
| expression
|
||||||
|
;
|
||||||
|
|
||||||
|
empty
|
||||||
|
:
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment A
|
||||||
|
: ('A' | 'a')
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment B
|
||||||
|
: ('B' | 'b')
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment C
|
||||||
|
: ('C' | 'c')
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment D
|
||||||
|
: ('D' | 'd')
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment E
|
||||||
|
: ('E' | 'e')
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment F
|
||||||
|
: ('F' | 'f')
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment G
|
||||||
|
: ('G' | 'g')
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment H
|
||||||
|
: ('H' | 'h')
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment I
|
||||||
|
: ('I' | 'i')
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment J
|
||||||
|
: ('J' | 'j')
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment K
|
||||||
|
: ('K' | 'k')
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment L
|
||||||
|
: ('L' | 'l')
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment M
|
||||||
|
: ('M' | 'm')
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment N
|
||||||
|
: ('N' | 'n')
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment O
|
||||||
|
: ('O' | 'o')
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment P
|
||||||
|
: ('P' | 'p')
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment Q
|
||||||
|
: ('Q' | 'q')
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment R
|
||||||
|
: ('R' | 'r')
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment S
|
||||||
|
: ('S' | 's')
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment T
|
||||||
|
: ('T' | 't')
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment U
|
||||||
|
: ('U' | 'u')
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment V
|
||||||
|
: ('V' | 'v')
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment W
|
||||||
|
: ('W' | 'w')
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment X
|
||||||
|
: ('X' | 'x')
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment Y
|
||||||
|
: ('Y' | 'y')
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment Z
|
||||||
|
: ('Z' | 'z')
|
||||||
|
;
|
||||||
|
|
||||||
|
literal
|
||||||
|
: number
|
||||||
|
| BOOL_LIT
|
||||||
|
| STRING_LITERAL
|
||||||
|
;
|
||||||
|
|
||||||
|
STRING_LITERAL
|
||||||
|
: UNCLOSE_STRING '"'
|
||||||
|
{self.text = self.text[1:-1]}
|
||||||
|
;
|
||||||
|
|
||||||
|
UNCLOSE_STRING
|
||||||
|
: '"' ('\\' [btrnf\\'"] | ~[\b\t\r\n\f\\'"])*
|
||||||
|
{raise UncloseString(self.text[1:])}
|
||||||
|
;
|
||||||
|
|
||||||
|
ILLEGAL_ESCAPE
|
||||||
|
: UNCLOSE_STRING '\\' ~[btnfr"'\\]
|
||||||
|
{raise IllegalEscape(self.text[1:])}
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment ESCAPE_STRING
|
||||||
|
: '\\b'
|
||||||
|
| '\\f'
|
||||||
|
| '\\r'
|
||||||
|
| '\\n'
|
||||||
|
| '\\t'
|
||||||
|
| '\\\''
|
||||||
|
| '\\"'
|
||||||
|
| '\\\\'
|
||||||
|
;
|
||||||
|
|
||||||
|
number
|
||||||
|
: NUM_INT
|
||||||
|
| NUM_REAL
|
||||||
|
;
|
||||||
|
|
||||||
|
NUM_INT
|
||||||
|
: [0-9]+
|
||||||
|
;
|
||||||
|
|
||||||
|
NUM_REAL
|
||||||
|
: [0-9]+ '.' [0-9]* EXPONENT?
|
||||||
|
| '.' [0-9]+ EXPONENT?
|
||||||
|
| [0-9]+ EXPONENT
|
||||||
|
;
|
||||||
|
|
||||||
|
BOOL_LIT
|
||||||
|
: TRUE
|
||||||
|
| FALSE
|
||||||
|
;
|
||||||
|
|
||||||
|
fragment EXPONENT
|
||||||
|
: ('e' | 'E') '-'? ('0' .. '9')+
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
LCURLY
|
||||||
|
: '{'
|
||||||
|
;
|
||||||
|
|
||||||
|
RCURLY
|
||||||
|
: '}'
|
||||||
|
;
|
||||||
|
|
||||||
|
LR
|
||||||
|
: '('
|
||||||
|
;
|
||||||
|
|
||||||
|
RR
|
||||||
|
: ')'
|
||||||
|
;
|
||||||
|
|
||||||
|
LB
|
||||||
|
: '['
|
||||||
|
;
|
||||||
|
|
||||||
|
RB
|
||||||
|
: ']'
|
||||||
|
;
|
||||||
|
|
||||||
|
SEMI
|
||||||
|
: ';'
|
||||||
|
;
|
||||||
|
|
||||||
|
DOUBLE_DOT
|
||||||
|
: '..'
|
||||||
|
;
|
||||||
|
|
||||||
|
COMMA
|
||||||
|
: ','
|
||||||
|
;
|
||||||
|
|
||||||
|
COLON
|
||||||
|
: ':'
|
||||||
|
;
|
||||||
|
|
||||||
|
BREAK
|
||||||
|
: B R E A K
|
||||||
|
;
|
||||||
|
|
||||||
|
CONTINUE
|
||||||
|
: C O N T I N U E
|
||||||
|
;
|
||||||
|
|
||||||
|
FOR
|
||||||
|
: F O R
|
||||||
|
;
|
||||||
|
|
||||||
|
TO
|
||||||
|
: T O
|
||||||
|
;
|
||||||
|
|
||||||
|
DOWNTO
|
||||||
|
: D O W N T O
|
||||||
|
;
|
||||||
|
|
||||||
|
DO
|
||||||
|
: D O
|
||||||
|
;
|
||||||
|
|
||||||
|
IF
|
||||||
|
: I F
|
||||||
|
;
|
||||||
|
|
||||||
|
THEN
|
||||||
|
: T H E N
|
||||||
|
;
|
||||||
|
|
||||||
|
ELSE
|
||||||
|
: E L S E
|
||||||
|
;
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
: R E T U R N
|
||||||
|
;
|
||||||
|
|
||||||
|
WHILE
|
||||||
|
: W H I L E
|
||||||
|
;
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
: B E G I N
|
||||||
|
;
|
||||||
|
|
||||||
|
END
|
||||||
|
: E N D
|
||||||
|
;
|
||||||
|
|
||||||
|
FUNCTION
|
||||||
|
: F U N C T I O N
|
||||||
|
;
|
||||||
|
|
||||||
|
PROCEDURE
|
||||||
|
: P R O C E D U R E
|
||||||
|
;
|
||||||
|
|
||||||
|
VAR
|
||||||
|
: V A R
|
||||||
|
;
|
||||||
|
|
||||||
|
TRUE
|
||||||
|
: T R U E
|
||||||
|
;
|
||||||
|
|
||||||
|
FALSE
|
||||||
|
: F A L S E
|
||||||
|
;
|
||||||
|
|
||||||
|
ARRAY
|
||||||
|
: A R R A Y
|
||||||
|
;
|
||||||
|
|
||||||
|
OF
|
||||||
|
: O F
|
||||||
|
;
|
||||||
|
|
||||||
|
REAL
|
||||||
|
: R E A L
|
||||||
|
;
|
||||||
|
|
||||||
|
BOOLEAN
|
||||||
|
: B O O L E A N
|
||||||
|
;
|
||||||
|
|
||||||
|
INTEGER
|
||||||
|
: I N T E G E R
|
||||||
|
;
|
||||||
|
|
||||||
|
STRING
|
||||||
|
: S T R I N G
|
||||||
|
;
|
||||||
|
|
||||||
|
NOT
|
||||||
|
: N O T
|
||||||
|
;
|
||||||
|
|
||||||
|
AND
|
||||||
|
: A N D
|
||||||
|
;
|
||||||
|
|
||||||
|
OR
|
||||||
|
: O R
|
||||||
|
;
|
||||||
|
|
||||||
|
DIV
|
||||||
|
: D I V
|
||||||
|
;
|
||||||
|
|
||||||
|
MOD
|
||||||
|
: M O D
|
||||||
|
;
|
||||||
|
|
||||||
|
WITH
|
||||||
|
: W I T H
|
||||||
|
;
|
||||||
|
|
||||||
|
PLUS
|
||||||
|
: '+'
|
||||||
|
;
|
||||||
|
|
||||||
|
MINUS
|
||||||
|
: '-'
|
||||||
|
;
|
||||||
|
|
||||||
|
STAR
|
||||||
|
: '*'
|
||||||
|
;
|
||||||
|
|
||||||
|
SLASH
|
||||||
|
: '/'
|
||||||
|
;
|
||||||
|
|
||||||
|
EQUAL
|
||||||
|
: '='
|
||||||
|
;
|
||||||
|
|
||||||
|
NOT_EQUAL
|
||||||
|
: '<>'
|
||||||
|
;
|
||||||
|
|
||||||
|
LT
|
||||||
|
: '<'
|
||||||
|
;
|
||||||
|
|
||||||
|
LE
|
||||||
|
: '<='
|
||||||
|
;
|
||||||
|
|
||||||
|
GE
|
||||||
|
: '>='
|
||||||
|
;
|
||||||
|
|
||||||
|
GT
|
||||||
|
: '>'
|
||||||
|
;
|
||||||
|
|
||||||
|
ASSIGN
|
||||||
|
: ':='
|
||||||
|
;
|
||||||
|
|
||||||
|
IDENT
|
||||||
|
: [a-zA-Z_] [a-zA-Z0-9_]*
|
||||||
|
;
|
||||||
|
|
||||||
|
COMMENT_3
|
||||||
|
: '//' .*? '\r'* '\n'+ -> skip
|
||||||
|
;
|
||||||
|
|
||||||
|
WS
|
||||||
|
: [ \t\r\n] -> skip
|
||||||
|
; // skip spaces, tabs
|
||||||
|
|
||||||
|
COMMENT_1
|
||||||
|
: '(*' .*? '*)' -> skip
|
||||||
|
;
|
||||||
|
|
||||||
|
COMMENT_2
|
||||||
|
: '{' .*? '}' -> skip
|
||||||
|
;
|
||||||
|
|
||||||
|
ERROR_CHAR
|
||||||
|
: .
|
||||||
|
{raise ErrorToken(self.text)}
|
||||||
|
;
|
0
parser/__init__.py
Normal file
0
parser/__init__.py
Normal file
14
parser/lexererr.py
Normal file
14
parser/lexererr.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
class ErrorToken(Exception):
|
||||||
|
def __init__(self, s):
|
||||||
|
self.message = "Error Token " + s
|
||||||
|
|
||||||
|
|
||||||
|
class UncloseString(Exception):
|
||||||
|
def __init__(self, s):
|
||||||
|
self.message = "Unclosed String: " + s
|
||||||
|
|
||||||
|
|
||||||
|
class IllegalEscape(Exception):
|
||||||
|
def __init__(self, s):
|
||||||
|
self.message = "Illegal Escape In String: " + s
|
534
utils/AST.py
Normal file
534
utils/AST.py
Normal file
@ -0,0 +1,534 @@
|
|||||||
|
from abc import ABC, abstractmethod, ABCMeta
|
||||||
|
# from Visitor import Visitor
|
||||||
|
|
||||||
|
# cheated = True
|
||||||
|
cheated = False
|
||||||
|
|
||||||
|
|
||||||
|
class AST(ABC):
|
||||||
|
def __eq__(self, other):
|
||||||
|
return self.__dict__ == other.__dict__
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def accept(self, v, param):
|
||||||
|
return v.visit(self, param)
|
||||||
|
|
||||||
|
|
||||||
|
class Type(AST):
|
||||||
|
__metaclass__ = ABCMeta
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class IntType(Type):
|
||||||
|
global cheated
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if not cheated:
|
||||||
|
return "IntType"
|
||||||
|
else:
|
||||||
|
return "IntType()"
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
return v.visitIntType(self, param)
|
||||||
|
|
||||||
|
|
||||||
|
class FloatType(Type):
|
||||||
|
global cheated
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if not cheated:
|
||||||
|
return "FloatType"
|
||||||
|
else:
|
||||||
|
return "FloatType()"
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
return v.visitFloatType(self, param)
|
||||||
|
|
||||||
|
|
||||||
|
class BoolType(Type):
|
||||||
|
global cheated
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if not cheated:
|
||||||
|
return "BoolType"
|
||||||
|
else:
|
||||||
|
return "BoolType()"
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
return v.visitBoolType(self, param)
|
||||||
|
|
||||||
|
|
||||||
|
class StringType(Type):
|
||||||
|
global cheated
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if not cheated:
|
||||||
|
return "StringType"
|
||||||
|
else:
|
||||||
|
return "StringType()"
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
return v.visitStringType(self, param)
|
||||||
|
|
||||||
|
|
||||||
|
class ArrayType(Type):
|
||||||
|
global cheated
|
||||||
|
# lower:int
|
||||||
|
# upper:int
|
||||||
|
# eleType:Type
|
||||||
|
|
||||||
|
def __init__(self, lower, upper, eleType):
|
||||||
|
self.lower = lower
|
||||||
|
self.upper = upper
|
||||||
|
self.eleType = eleType
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "ArrayType(" + str(self.lower) + "," + \
|
||||||
|
str(self.upper) + "," + str(self.eleType) + ")"
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
return v.visitArrayType(self, param)
|
||||||
|
|
||||||
|
|
||||||
|
class VoidType(Type):
|
||||||
|
global cheated
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "VoidType()"
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
return v.visitVoidType(self, param)
|
||||||
|
|
||||||
|
|
||||||
|
class Program(AST):
|
||||||
|
global cheated
|
||||||
|
# decl:list(Decl)
|
||||||
|
|
||||||
|
def __init__(self, decl):
|
||||||
|
self.decl = decl
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "Program([" + ','.join(str(i) for i in self.decl) + "])"
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
return v.visitProgram(self, param)
|
||||||
|
|
||||||
|
|
||||||
|
class Decl(AST):
|
||||||
|
__metaclass__ = ABCMeta
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class VarDecl(Decl):
|
||||||
|
global cheated
|
||||||
|
# variable:Id
|
||||||
|
# varType: Type
|
||||||
|
|
||||||
|
def __init__(self, variable, varType):
|
||||||
|
self.variable = variable
|
||||||
|
self.varType = varType
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "VarDecl(" + str(self.variable) + "," + str(self.varType) + ")"
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
return v.visitVarDecl(self, param)
|
||||||
|
|
||||||
|
|
||||||
|
class FuncDecl(Decl):
|
||||||
|
global cheated
|
||||||
|
# name: Id
|
||||||
|
# param: list(VarDecl)
|
||||||
|
# returnType: Type => VoidType for Procedure
|
||||||
|
# local:list(VarDecl)
|
||||||
|
# body: list(Stmt)
|
||||||
|
|
||||||
|
def __init__(self, name, param, local, body, returnType=VoidType()):
|
||||||
|
self.name = name
|
||||||
|
self.param = param
|
||||||
|
self.returnType = returnType
|
||||||
|
self.local = local
|
||||||
|
self.body = body
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if not cheated:
|
||||||
|
return "FuncDecl(" + str(self.name) + ",[" + \
|
||||||
|
','.join(str(i) for i in self.param) + "]," + \
|
||||||
|
str(self.returnType) + ",[" + \
|
||||||
|
','.join(str(i) for i in self.local) + "],[" + \
|
||||||
|
','.join(str(i) for i in self.body) + "])"
|
||||||
|
else:
|
||||||
|
return "FuncDecl(" + str(self.name) + ",[" + \
|
||||||
|
','.join(str(i) for i in self.param) + "],[" + \
|
||||||
|
','.join(str(i) for i in self.local) + "],[" + \
|
||||||
|
','.join(str(i) for i in self.body) + "]," + \
|
||||||
|
str(self.returnType) + ")"
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
return v.visitFuncDecl(self, param)
|
||||||
|
|
||||||
|
|
||||||
|
class Stmt(AST):
|
||||||
|
__metaclass__ = ABCMeta
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Assign(Stmt):
|
||||||
|
global cheated
|
||||||
|
# lhs:Expr
|
||||||
|
# exp:Expr
|
||||||
|
|
||||||
|
def __init__(self, lhs, exp):
|
||||||
|
self.lhs = lhs
|
||||||
|
self.exp = exp
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if not cheated:
|
||||||
|
return "AssignStmt(" + str(self.lhs) + "," + str(self.exp) + ")"
|
||||||
|
else:
|
||||||
|
return "Assign(" + str(self.lhs) + "," + str(self.exp) + ")"
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
return v.visitAssign(self, param)
|
||||||
|
|
||||||
|
|
||||||
|
class If(Stmt):
|
||||||
|
global cheated
|
||||||
|
# expr:Expr
|
||||||
|
# thenStmt:list(Stmt)
|
||||||
|
# elseStmt:list(Stmt)
|
||||||
|
|
||||||
|
def __init__(self, expr, thenStmt, elseStmt=[]):
|
||||||
|
self.expr = expr
|
||||||
|
self.thenStmt = thenStmt
|
||||||
|
self.elseStmt = elseStmt
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "If(" + str(self.expr) + ",[" + \
|
||||||
|
','.join(str(i) for i in self.thenStmt) + "],[" + \
|
||||||
|
','.join(str(i) for i in self.elseStmt) + "])"
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
return v.visitIf(self, param)
|
||||||
|
|
||||||
|
|
||||||
|
class While(Stmt):
|
||||||
|
global cheated
|
||||||
|
# sl:list(Stmt)
|
||||||
|
# exp: Expr
|
||||||
|
|
||||||
|
def __init__(self, exp, sl):
|
||||||
|
self.sl = sl
|
||||||
|
self.exp = exp
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "While(" + str(self.exp) + \
|
||||||
|
",[" + ','.join(str(i) for i in self.sl) + "])"
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
return v.visitWhile(self, param)
|
||||||
|
|
||||||
|
|
||||||
|
class For(Stmt):
|
||||||
|
global cheated
|
||||||
|
# id:Id
|
||||||
|
# expr1,expr2:Expr
|
||||||
|
# loop:list(Stmt)
|
||||||
|
# up:Boolean #True => increase; False => decrease
|
||||||
|
|
||||||
|
def __init__(self, id, expr1, expr2, up, loop):
|
||||||
|
self.id = id
|
||||||
|
self.expr1 = expr1
|
||||||
|
self.expr2 = expr2
|
||||||
|
self.up = up
|
||||||
|
self.loop = loop
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if not cheated:
|
||||||
|
return "For(" + str(self.id) + ","\
|
||||||
|
+ str(self.expr1) + "," \
|
||||||
|
+ str(self.expr2) + ","\
|
||||||
|
+ str(self.up) + ',[' \
|
||||||
|
+ ','.join(str(i) for i in self.loop) + "])"
|
||||||
|
else:
|
||||||
|
return "For(" + str(self.id) + ","\
|
||||||
|
+ str(self.expr1) + "," \
|
||||||
|
+ str(self.expr2) + ","\
|
||||||
|
+ str(self.up) + ',[' \
|
||||||
|
+ ','.join(str(i) for i in self.loop) + "])"
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
return v.visitFor(self, param)
|
||||||
|
|
||||||
|
|
||||||
|
class Break(Stmt):
|
||||||
|
global cheated
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if not cheated:
|
||||||
|
return "Break"
|
||||||
|
else:
|
||||||
|
return "Break()"
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
return v.visitBreak(self, param)
|
||||||
|
|
||||||
|
|
||||||
|
class Continue(Stmt):
|
||||||
|
global cheated
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if not cheated:
|
||||||
|
return "Continue"
|
||||||
|
else:
|
||||||
|
return "Continue()"
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
return v.visitContinue(self, param)
|
||||||
|
|
||||||
|
|
||||||
|
class Return(Stmt):
|
||||||
|
global cheated
|
||||||
|
# expr:Expr
|
||||||
|
|
||||||
|
def __init__(self, expr=None):
|
||||||
|
self.expr = expr
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if not cheated:
|
||||||
|
return "Return(" + ("None" if (self.expr is None)
|
||||||
|
else "Some(" + str(self.expr) + ")") + ")"
|
||||||
|
else:
|
||||||
|
return "Return()" if self.expr is None \
|
||||||
|
else "Return(" + str(self.expr) + ")"
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
return v.visitReturn(self, param)
|
||||||
|
|
||||||
|
|
||||||
|
class With(Stmt):
|
||||||
|
global cheated
|
||||||
|
# decl:list(VarDecl)
|
||||||
|
# stmt:list(Stmt)
|
||||||
|
|
||||||
|
def __init__(self, decl, stmt):
|
||||||
|
self.decl = decl
|
||||||
|
self.stmt = stmt
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "With([" + ','.join(str(i) for i in self.decl) + \
|
||||||
|
"],[" + ','.join(str(i) for i in self.stmt) + "])"
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
return v.visitWith(self, param)
|
||||||
|
|
||||||
|
|
||||||
|
class CallStmt(Stmt):
|
||||||
|
global cheated
|
||||||
|
# method:Id
|
||||||
|
# param:list(Expr)
|
||||||
|
|
||||||
|
def __init__(self, method, param):
|
||||||
|
self.method = method
|
||||||
|
self.param = param
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "CallStmt(" + str(self.method) + \
|
||||||
|
",[" + ','.join(str(i) for i in self.param) + "])"
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
return v.visitCallStmt(self, param)
|
||||||
|
|
||||||
|
|
||||||
|
class Expr(AST):
|
||||||
|
__metaclass__ = ABCMeta
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class BinaryOp(Expr):
|
||||||
|
global cheated
|
||||||
|
# op:string: AND THEN => andthen; OR ELSE => orelse; other => keep it
|
||||||
|
# left:Expr
|
||||||
|
# right:Expr
|
||||||
|
|
||||||
|
def __init__(self, op, left, right):
|
||||||
|
self.op = op
|
||||||
|
self.left = left
|
||||||
|
self.right = right
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if not cheated:
|
||||||
|
return "BinaryOp(" + self.op + "," + str(self.left) + \
|
||||||
|
"," + str(self.right) + ")"
|
||||||
|
else:
|
||||||
|
return "BinaryOp(\"" + self.op + "\"," + str(self.left) + \
|
||||||
|
"," + str(self.right) + ")"
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
return v.visitBinaryOp(self, param)
|
||||||
|
|
||||||
|
|
||||||
|
class UnaryOp(Expr):
|
||||||
|
global cheated
|
||||||
|
# op:string
|
||||||
|
# body:Expr
|
||||||
|
|
||||||
|
def __init__(self, op, body):
|
||||||
|
self.op = op
|
||||||
|
self.body = body
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if not cheated:
|
||||||
|
return "UnaryOp(" + self.op + "," + str(self.body) + ")"
|
||||||
|
else:
|
||||||
|
return "UnaryOp(\"" + self.op + "\"," + str(self.body) + ")"
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
return v.visitUnaryOp(self, param)
|
||||||
|
|
||||||
|
|
||||||
|
class CallExpr(Expr):
|
||||||
|
global cheated
|
||||||
|
# method:Id
|
||||||
|
# param:list(Expr)
|
||||||
|
|
||||||
|
def __init__(self, method, param):
|
||||||
|
self.method = method
|
||||||
|
self.param = param
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "CallExpr(" + str(self.method) + \
|
||||||
|
",[" + ','.join(str(i) for i in self.param) + "])"
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
return v.visitCallExpr(self, param)
|
||||||
|
|
||||||
|
|
||||||
|
class LHS(Expr):
|
||||||
|
global cheated
|
||||||
|
__metaclass__ = ABCMeta
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Id(LHS):
|
||||||
|
global cheated
|
||||||
|
# name:string
|
||||||
|
|
||||||
|
def __init__(self, name):
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if not cheated:
|
||||||
|
return "Id(" + self.name + ")"
|
||||||
|
else:
|
||||||
|
return "Id(\"" + self.name + "\")"
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
return v.visitId(self, param)
|
||||||
|
|
||||||
|
|
||||||
|
class ArrayCell(LHS):
|
||||||
|
global cheated
|
||||||
|
# arr:Expr
|
||||||
|
# idx:Expr
|
||||||
|
|
||||||
|
def __init__(self, arr, idx):
|
||||||
|
self.arr = arr
|
||||||
|
self.idx = idx
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "ArrayCell(" + str(self.arr) + "," + str(self.idx) + ")"
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
return v.visitArrayCell(self, param)
|
||||||
|
|
||||||
|
|
||||||
|
class Literal(Expr):
|
||||||
|
global cheated
|
||||||
|
__metaclass__ = ABCMeta
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class IntLiteral(Literal):
|
||||||
|
global cheated
|
||||||
|
# value:int
|
||||||
|
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "IntLiteral(" + str(self.value) + ")"
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
|
||||||
|
return v.visitIntLiteral(self, param)
|
||||||
|
|
||||||
|
|
||||||
|
class FloatLiteral(Literal):
|
||||||
|
global cheated
|
||||||
|
# value:float
|
||||||
|
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "FloatLiteral(" + str(self.value) + ")"
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
return v.visitFloatLiteral(self, param)
|
||||||
|
|
||||||
|
|
||||||
|
class StringLiteral(Literal):
|
||||||
|
global cheated
|
||||||
|
# value:string
|
||||||
|
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if not cheated:
|
||||||
|
return "StringLiteral(" + self.value + ")"
|
||||||
|
else:
|
||||||
|
return "StringLiteral(\"" + self.value + "\")"
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
return v.visitStringLiteral(self, param)
|
||||||
|
|
||||||
|
|
||||||
|
class BooleanLiteral(Literal):
|
||||||
|
global cheated
|
||||||
|
# value:boolean
|
||||||
|
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "BooleanLiteral(" + str(self.value) + ")"
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
return v.visitBooleanLiteral(self, param)
|
||||||
|
|
||||||
|
|
||||||
|
class ArrayPointerType(Type):
|
||||||
|
def __init__(self, ctype):
|
||||||
|
# cname: String
|
||||||
|
self.eleType = ctype
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "ArrayPointerType({0})".format(
|
||||||
|
str(self.eleType)
|
||||||
|
)
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class ClassType(Type):
|
||||||
|
def __init__(self, cname):
|
||||||
|
self.cname = cname
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "Class({0})".format(str(self.cname))
|
||||||
|
|
||||||
|
def accept(self, v, param):
|
||||||
|
return None
|
7
utils/Utils.py
Normal file
7
utils/Utils.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
class Utils:
|
||||||
|
def lookup(self, name, lst, func):
|
||||||
|
for x in lst:
|
||||||
|
if name == func(x):
|
||||||
|
return x
|
||||||
|
return None
|
199
utils/Visitor.py
Normal file
199
utils/Visitor.py
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
from abc import ABC, abstractmethod # , ABCMeta
|
||||||
|
|
||||||
|
|
||||||
|
class Visitor(ABC):
|
||||||
|
|
||||||
|
def visit(self, ast, param):
|
||||||
|
return ast.accept(self, param)
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visitProgram(self, asttree, param):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visitVarDecl(self, asttree, param):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visitFuncDecl(self, asttree, param):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visitIntType(self, asttree, param):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visitFloatType(self, asttree, param):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visitBoolType(self, asttree, param):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visitStringType(self, asttree, param):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visitVoidType(self, asttree, param):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visitArrayType(self, asttree, param):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visitBinaryOp(self, asttree, param):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visitUnaryOp(self, asttree, param):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visitCallExpr(self, asttree, param):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visitId(self, asttree, param):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visitArrayCell(self, asttree, param):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visitAssign(self, asttree, param):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visitWith(self, asttree, param):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visitIf(self, asttree, param):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visitFor(self, asttree, param):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visitContinue(self, asttree, param):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visitBreak(self, asttree, param):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visitReturn(self, asttree, param):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visitWhile(self, asttree, param):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visitCallStmt(self, asttree, param):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visitIntLiteral(self, asttree, param):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visitFloatLiteral(self, asttree, param):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visitBooleanLiteral(self, asttree, param):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visitStringLiteral(self, asttree, param):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class BaseVisitor(Visitor):
|
||||||
|
|
||||||
|
def visitProgram(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitVarDecl(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitFuncDecl(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitIntType(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitFloatType(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitBoolType(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitStringType(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitVoidType(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitArrayType(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitBinaryOp(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitUnaryOp(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitCallExpr(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitId(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitArrayCell(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitAssign(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitWith(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitIf(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitFor(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitContinue(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitBreak(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitReturn(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitWhile(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitCallStmt(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitIntLiteral(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitFloatLiteral(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitBooleanLiteral(self, asttree, param):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def visitStringLiteral(self, asttree, param):
|
||||||
|
return None
|
0
utils/__init__.py
Normal file
0
utils/__init__.py
Normal file
Loading…
Reference in New Issue
Block a user