commit 7af458832b95c125b8120e6951e3d2852b2eb939
Author: drmortalwombat <90205530+drmortalwombat@users.noreply.github.com>
Date: Mon Sep 6 18:34:52 2021 +0200
Initial commit
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..dfe0770
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+# Auto detect text files and perform LF normalization
+* text=auto
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..16f442b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,337 @@
+## 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/
+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
+*.tmp_proj
+*_wpftmp.csproj
+*.log
+*.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/
+
+# 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)
+__pycache__/
+*.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/
+*.asm
+*.map
+*.prg
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..e62ec04
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,674 @@
+GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..3c01e51
--- /dev/null
+++ b/README.md
@@ -0,0 +1,2 @@
+# oscar64
+ Optimizing small space C Compiler Assembler and Runtime for C64
diff --git a/autotest/arraytest.c b/autotest/arraytest.c
new file mode 100644
index 0000000..64a7c75
--- /dev/null
+++ b/autotest/arraytest.c
@@ -0,0 +1,23 @@
+#include
+#include
+
+int sum(int * a, int s)
+{
+ int sum = 0;
+ for(int i=0; i
+#include
+
+float sum(float * a, int s)
+{
+ float sum = 0;
+ for(int i=0; i
+#include
+
+
+bool feq(float a, float b)
+{
+ return a == b;
+}
+
+bool flt(float a, float b)
+{
+ return a < b;
+}
+
+bool fgt(float a, float b)
+{
+ return a > b;
+}
+
+void cmpflt(float a, float b, bool eq, bool lt, bool gt)
+{
+ assert(feq(a, b) == eq);
+ assert(flt(a, b) == lt);
+ assert(fgt(a, b) == gt);
+}
+
+int main(void)
+{
+ cmpflt( 0.0, 1.0, false, true, false);
+ cmpflt( 0.0, -1.0, false, false, true);
+ cmpflt( 1.0, 0.0, false, false, true);
+ cmpflt(-1.0, 0.0, false, true, false);
+
+
+ cmpflt( 1.0, 1.0, true, false, false);
+ cmpflt( 1.0, 2.0, false, true, false);
+ cmpflt( 2.0, 1.0, false, false, true);
+
+ cmpflt(-1.0, -1.0, true, false, false);
+ cmpflt(-1.0, -2.0, false, false, true);
+ cmpflt(-2.0, -1.0, false, true, false);
+
+ cmpflt( 1.0, -1.0, false, false, true);
+ cmpflt( 1.0, -2.0, false, false, true);
+ cmpflt( 2.0, -1.0, false, false, true);
+
+ cmpflt(-1.0, 1.0, false, true, false);
+ cmpflt(-1.0, 2.0, false, true, false);
+ cmpflt(-2.0, 1.0, false, true, false);
+
+ cmpflt( 0.0, 0.0, true, false, false);
+ cmpflt(-0.0, 0.0, true, false, false);
+ cmpflt( 0.0, -0.0, true, false, false);
+ cmpflt(-0.0, -0.0, true, false, false);
+
+ cmpflt( 1.0, 1.000001, false, true, false);
+ cmpflt( 1.000001, 1.0, false, false, true);
+ cmpflt( 1.000001, 1.000001, true, false, false);
+
+ cmpflt( -1.0, -1.000001, false, false, true);
+ cmpflt( -1.000001, -1.0, false, true, false);
+ cmpflt( -1.000001, -1.000001, true, false, false);
+
+ return 0;
+}
diff --git a/autotest/floatmultest.c b/autotest/floatmultest.c
new file mode 100644
index 0000000..f95cad7
--- /dev/null
+++ b/autotest/floatmultest.c
@@ -0,0 +1,30 @@
+#include
+#include
+#include
+
+float c = 1.25;
+float d = 1.0001;
+
+int main(void)
+{
+ int i;
+ float a = 0.0;
+
+ for(i=0; i<50; i++)
+ {
+// printf("%d %f %f %f\n", i, i * c, a, i * c - a);
+ assert(i * c == a);
+ a += c;
+ }
+
+ a = d;
+
+ for(i=1; i<50; i++)
+ {
+// printf("%d %f %f %f\n", i, i * d, a, fabs(i * d - a) / i);
+ assert(fabs(i * d - a) < i * 1.0e-6);
+ a += d;
+ }
+
+ return 0;
+}
diff --git a/autotest/optiontest.c b/autotest/optiontest.c
new file mode 100644
index 0000000..ee07ee8
--- /dev/null
+++ b/autotest/optiontest.c
@@ -0,0 +1,15 @@
+#include
+#include
+
+int option(bool a, int b, int c)
+{
+ return a ? b : c;
+}
+
+int main(void)
+{
+ assert(option(true, 1, 2) == 1);
+ assert(option(false, 1, 2) == 2);
+
+ return 0;
+}
\ No newline at end of file
diff --git a/autotest/recursiontest.c b/autotest/recursiontest.c
new file mode 100644
index 0000000..b045828
--- /dev/null
+++ b/autotest/recursiontest.c
@@ -0,0 +1,89 @@
+#include
+#include
+#include
+
+int fib(int a)
+{
+ if (a < 2)
+ return a;
+ else
+ return fib(a - 1) + fib(a - 2);
+}
+
+struct Node
+{
+ char value;
+ Node * left, * right;
+};
+
+typedef Node * NodePtr;
+
+
+NodePtr newnode(void)
+{
+ return (NodePtr)malloc(sizeof(Node));
+}
+
+Node * insert(Node * tree, char v)
+{
+ if (tree)
+ {
+ if (v < tree->value)
+ {
+ tree->left = insert(tree->left, v);
+ }
+ else
+ {
+ tree->right = insert(tree->right, v);
+ }
+ }
+ else
+ {
+ tree = newnode();
+ tree->value = v;
+ tree->left = nullptr;
+ tree->right = nullptr;
+ }
+
+ return tree;
+}
+
+char * collect(Node * tree, char * p)
+{
+ if (tree)
+ {
+ p = collect(tree->left, p);
+ *p++= tree->value;
+ p = collect(tree->right, p);
+ }
+
+ return p;
+}
+
+void btest(void)
+{
+ const char * str = "HELLO WORLD";
+ char buff[20];
+
+ int i = 0;
+ Node * tree = nullptr;
+
+ while (str[i])
+ {
+ tree = insert(tree, str[i]);
+ i++;
+ }
+
+ collect(tree, buff)[0] = 0;
+
+ assert(strcmp(buff, " DEHLLLOORW") == 0);
+}
+
+int main(void)
+{
+ assert(fib(23) == 28657);
+
+ btest();
+
+ return 0;
+}
diff --git a/autotest/stdlibtest.c b/autotest/stdlibtest.c
new file mode 100644
index 0000000..260bb32
--- /dev/null
+++ b/autotest/stdlibtest.c
@@ -0,0 +1,73 @@
+// stdlibtest
+
+#include
+#include
+#include
+#include
+
+void numcheck(int n)
+{
+ char buffer[10];
+ itoa(n, buffer, 10);
+ int m = atoi(buffer);
+
+ printf("%d : %s -> %d\n", n, buffer, m);
+
+ if (m != n)
+ exit(-1);
+}
+
+void numchecks(void)
+{
+ numcheck(0);
+ numcheck(-1);
+ numcheck(1);
+ numcheck(12345);
+ numcheck(-12345);
+ numcheck(INT_MIN);
+ numcheck(INT_MAX);
+}
+
+void heapcheck(void)
+{
+ void * memp[100];
+ int mems[100];
+ int n, k, s, i;
+
+ for(n=0; n<100; n++)
+ {
+ s = rand() % 100 + 3;
+ mems[n] = s;
+ memp[n] = malloc(s);
+ memset(memp[n], n, s);
+ }
+
+ for(k=0; k<1000; k++)
+ {
+ n = rand() % 100;
+ int s = mems[n];
+ char * p = memp[n];
+ for(i=0; i
+#include
+
+int main(void)
+{
+ assert(strcmp("ABCD", "ABCD") == 0);
+ assert(strcmp("ABCE", "ABCD") == 1);
+ assert(strcmp("ABCD", "ABCE") == -1);
+
+ return 0;
+}
diff --git a/autotest/testint16.c b/autotest/testint16.c
new file mode 100644
index 0000000..66e5ace
--- /dev/null
+++ b/autotest/testint16.c
@@ -0,0 +1,121 @@
+#include
+
+void testmuli(int a, int b, int ab)
+{
+ assert (a * b == ab);
+}
+
+void testdivi(int a, int b, int ab)
+{
+ assert (a / b == ab);
+}
+
+void shltesti(int a, int b, int ab)
+{
+ assert (a << b == ab);
+}
+
+void shrtesti(int a, int b, int ab)
+{
+ assert (a >> b == ab);
+}
+
+int sieve(int size)
+{
+ bool sieve[1000];
+
+ for(int i=0; i
+
+void assert(bool b)
+{
+ if (!b)
+ exit(-1);
+}
diff --git a/include/assert.h b/include/assert.h
new file mode 100644
index 0000000..4f48d6d
--- /dev/null
+++ b/include/assert.h
@@ -0,0 +1,8 @@
+#ifndef ASSERT_H
+#define ASSERT_H
+
+void assert(bool b);
+
+#pragma compile("assert.c")
+
+#endif
diff --git a/include/crt.c b/include/crt.c
new file mode 100644
index 0000000..b46dee4
--- /dev/null
+++ b/include/crt.c
@@ -0,0 +1,2486 @@
+// crt.c
+#include
+
+unsigned int CodeStart = 0x0a00;
+unsigned int StackTop = 0xa000 - 2;
+
+
+__asm startup
+{
+ lda CodeStart + 0
+ sta ip
+ lda CodeStart + 1
+ sta ip + 1
+
+ lda StackTop + 0
+ sta sp
+ lda StackTop + 1
+ sta sp + 1
+
+ ldy #0
+exec:
+ lda (ip), y
+ sta execjmp + 1
+ iny
+ bmi incip
+execjmp:
+ jmp (0x0900)
+incip:
+ tya
+ ldy #0
+ clc
+ adc ip
+ sta ip
+ bcc execjmp
+ inc ip + 1
+ bne execjmp
+}
+
+#pragma startup(startup)
+
+// divide accu by tmp
+
+__asm divmod
+{
+ sty tmpy
+ lda #0
+ sta tmp + 2
+ sta tmp + 3
+ ldy #16
+ clc
+L1: rol accu
+ rol accu + 1
+ rol tmp + 2
+ rol tmp + 3
+ sec
+ lda tmp + 2
+ sbc tmp
+ tax
+ lda tmp + 3
+ sbc tmp + 1
+ bcc W1
+ stx tmp + 2
+ sta tmp + 3
+W1: dey
+ bne L1
+ rol accu
+ rol accu + 1
+ ldy tmpy
+ rts
+}
+
+/*
+!align 255, 0
+inptable
+ !word inp_nop
+ !word inp_exit
+
+ !word inp_const_p8, inp_const_n8, inp_const_16, inp_const_32
+
+ !word inp_load_reg_16, inp_store_reg_16, inp_addr_reg, inp_load_reg_32, inp_store_reg_32
+
+ !word inp_load_abs_u8, inp_load_abs_s8, inp_load_abs_16, inp_load_abs_32
+ !word inp_store_abs_8, inp_store_abs_16, inp_store_abs_32
+ !word inp_lea_abs
+
+ !word inp_load_local_u8, inp_load_local_s8, inp_load_local_16, inp_load_local_32
+ !word inp_store_local_8, inp_store_local_16, inp_store_local_32
+ !word inp_lea_local
+
+ !word inp_store_frame_8, inp_store_frame_16, inp_store_frame_32
+
+ !word inp_load_addr_u8, inp_load_addr_s8, inp_load_addr_16, inp_load_addr_32
+ !word inp_store_addr_8, inp_store_addr_16, inp_store_addr_32
+
+ !word inp_binop_addr_16, inp_binop_subr_16
+ !word inp_binop_andr_16, inp_binop_orr_16, inp_binop_xorr_16
+ !word inp_binop_mulr_16, inp_binop_divr_u16, inp_binop_modr_u16, inp_binop_divr_s16, inp_binop_modr_s16
+ !word inp_binop_shlr_16, inp_binop_shrr_u16, inp_binop_shrr_s16
+
+ !word inp_binop_addi_16, inp_binop_subi_16, inp_binop_andi_16, inp_binop_ori_16, inp_binop_muli8_16
+ !word inp_binop_shli_16, inp_binop_shri_u16, inp_binop_shri_s16
+
+ !word inp_binop_cmpr_u16, inp_binop_cmpr_s16
+ !word inp_binop_cmpi_u16, inp_binop_cmpi_s16
+
+ !word inp_op_negate_16, inp_op_invert_16
+
+ !word inp_binop_add_f32, inp_binop_sub_f32, inp_binop_mul_f32, inp_binop_div_f32
+ !word inp_binop_cmp_f32
+ !word inp_op_negate_f32, inp_op_abs_f32, inp_op_floor_f32, inp_op_ceil_f32
+
+ !word inp_conv_u16_f32, inp_conv_i16_f32, inp_conv_f32_u16, inp_conv_f32_i16
+
+ !word inp_jumps
+ !word inp_branchs_eq, inp_branchs_ne
+ !word inp_branchs_gt, inp_branchs_ge
+ !word inp_branchs_lt, inp_branchs_le
+
+ !word inp_jumpf
+ !word inp_branchf_eq, inp_branchf_ne
+ !word inp_branchf_gt, inp_branchf_ge
+ !word inp_branchf_lt, inp_branchf_le
+
+ !word inp_set_eq, inp_set_ne
+ !word inp_set_gt, inp_set_ge
+ !word inp_set_lt, inp_set_le
+
+ !word inp_enter
+ !word inp_return
+ !word inp_call
+ !word inp_push_frame, inp_pop_frame
+
+ !word inp_jsr
+
+ !word inp_copy, inp_copyl
+*/
+
+__asm inp_nop
+{
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_NOP, inp_nop)
+
+__asm inp_exit
+{
+ lda #$4c
+ sta $54
+ rts
+}
+
+#pragma bytecode(BC_EXIT, inp_exit)
+
+__asm inp_jsr
+{
+ lda (ip), y
+ sta P1 + 1
+ iny
+ lda (ip), y
+ sta P1 + 2
+ tya
+ sec
+ adc ip
+ sta ip
+ bcc P1
+ inc ip + 1
+P1:
+ jsr $0000
+ ldy #0
+ jmp startup.exec
+}
+#pragma bytecode(BC_JSR, inp_jsr)
+
+__asm inp_const_p8
+{
+ lda (ip), y
+ tax
+ iny
+ lda (ip), y
+ sta $00, x
+ lda #0
+ sta $01, x
+ iny
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_CONST_P8, inp_const_p8)
+
+__asm inp_const_n8
+{
+ lda (ip), y
+ tax
+ iny
+ lda (ip), y
+ sta $00, x
+ lda #$ff
+ sta $01, x
+ iny
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_CONST_N8, inp_const_n8)
+
+__asm inp_const_16
+{
+ lda (ip), y
+ tax
+ iny
+ lda (ip), y
+ sta $00, x
+ iny
+ lda (ip), y
+ sta $01, x
+ iny
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_CONST_16, inp_const_16)
+
+__asm inp_const_32
+{
+ lda (ip), y
+ tax
+ iny
+ lda (ip), y
+ sta $00, x
+ iny
+ lda (ip), y
+ sta $01, x
+ iny
+ lda (ip), y
+ sta $02, x
+ iny
+ lda (ip), y
+ sta $03, x
+ iny
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_CONST_32, inp_const_32)
+
+__asm inp_load_reg_16
+{
+ lda (ip), y
+ tax
+ iny
+ lda $00, x
+ sta accu
+ lda $01, x
+ sta accu + 1
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_LOAD_REG_16, inp_load_reg_16)
+
+__asm inp_store_reg_16
+{
+ lda (ip), y
+ tax
+ iny
+ lda accu
+ sta $00, x
+ lda accu + 1
+ sta $01, x
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_STORE_REG_16, inp_store_reg_16)
+
+__asm inp_load_reg_32
+{
+ lda (ip), y
+ tax
+ iny
+ lda $00, x
+ sta accu
+ lda $01, x
+ sta accu + 1
+ lda $02, x
+ sta accu + 2
+ lda $03, x
+ sta accu + 3
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_LOAD_REG_32, inp_load_reg_32)
+
+__asm inp_store_reg_32
+{
+ lda (ip), y
+ tax
+ iny
+ lda accu
+ sta $00, x
+ lda accu + 1
+ sta $01, x
+ lda accu + 2
+ sta $02, x
+ lda accu + 3
+ sta $03, x
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_STORE_REG_32, inp_store_reg_32)
+
+__asm inp_addr_reg
+{
+ lda (ip), y
+ tax
+ iny
+ lda $00, x
+ sta addr
+ lda $01, x
+ sta addr + 1
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_ADDR_REG, inp_addr_reg)
+
+__asm inp_load_abs_u8
+{
+ lda (ip), y
+ sta addr
+ iny
+ lda (ip), y
+ sta addr + 1
+ iny
+inp_load_addr_u8:
+ lda (ip), y
+ tax
+ iny
+ sty tmpy
+ ldy #0
+ lda (addr), y
+ sta $00, x
+ lda #0
+ sta $01, x
+ ldy tmpy
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_LOAD_ABS_U8, inp_load_abs_u8)
+#pragma bytecode(BC_LOAD_ADDR_U8, inp_load_abs_u8.inp_load_addr_u8)
+
+__asm inp_load_abs_s8
+{
+ lda (ip), y
+ sta addr
+ iny
+ lda (ip), y
+ sta addr + 1
+ iny
+inp_load_addr_s8:
+ lda (ip), y
+ tax
+ iny
+ sty tmpy
+ ldy #0
+ lda (addr), y
+ sta $00, x
+ bmi W1
+ lda #0
+ byt $2c
+W1: lda #$ff
+ sta $01, x
+ ldy tmpy
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_LOAD_ABS_I8, inp_load_abs_s8)
+#pragma bytecode(BC_LOAD_ADDR_I8, inp_load_abs_s8.inp_load_addr_s8)
+
+__asm inp_load_abs_16
+{
+ lda (ip), y
+ sta addr
+ iny
+ lda (ip), y
+ sta addr + 1
+ iny
+inp_load_addr_16:
+ lda (ip), y
+ tax
+ iny
+ sty tmpy
+ ldy #0
+ lda (addr), y
+ sta $00, x
+ iny
+ lda (addr), y
+ sta $01, x
+ ldy tmpy
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_LOAD_ABS_16, inp_load_abs_16)
+#pragma bytecode(BC_LOAD_ADDR_16, inp_load_abs_16.inp_load_addr_16)
+
+__asm inp_load_abs_32
+{
+ lda (ip), y
+ sta addr
+ iny
+ lda (ip), y
+ sta addr + 1
+ iny
+inp_load_addr_32:
+ lda (ip), y
+ tax
+ iny
+ sty tmpy
+ ldy #0
+ lda (addr), y
+ sta $00, x
+ iny
+ lda (addr), y
+ sta $01, x
+ iny
+ lda (addr), y
+ sta $02, x
+ iny
+ lda (addr), y
+ sta $03, x
+ ldy tmpy
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_LOAD_ABS_32, inp_load_abs_32)
+#pragma bytecode(BC_LOAD_ADDR_32, inp_load_abs_32.inp_load_addr_32)
+
+__asm inp_store_abs_8
+{
+ lda (ip), y
+ sta addr
+ iny
+ lda (ip), y
+ sta addr + 1
+ iny
+inp_store_addr_8:
+ lda (ip), y
+ tax
+ iny
+ sty tmpy
+ ldy #0
+ lda $00, x
+ sta (addr), y
+ ldy tmpy
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_STORE_ABS_8, inp_store_abs_8)
+#pragma bytecode(BC_STORE_ADDR_8, inp_store_abs_8.inp_store_addr_8)
+
+__asm inp_store_abs_16
+{
+ lda (ip), y
+ sta addr
+ iny
+ lda (ip), y
+ sta addr + 1
+ iny
+inp_store_addr_16:
+ lda (ip), y
+ tax
+ iny
+ sty tmpy
+ ldy #0
+ lda $00, x
+ sta (addr), y
+ iny
+ lda $01, x
+ sta (addr), y
+ ldy tmpy
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_STORE_ABS_16, inp_store_abs_16)
+#pragma bytecode(BC_STORE_ADDR_16, inp_store_abs_16.inp_store_addr_16)
+
+__asm inp_store_abs_32
+{
+ lda (ip), y
+ sta addr
+ iny
+ lda (ip), y
+ sta addr + 1
+ iny
+inp_store_addr_32:
+ lda (ip), y
+ tax
+ iny
+ sty tmpy
+ ldy #0
+ lda $00, x
+ sta (addr), y
+ iny
+ lda $01, x
+ sta (addr), y
+ iny
+ lda $02, x
+ sta (addr), y
+ iny
+ lda $03, x
+ sta (addr), y
+ ldy tmpy
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_STORE_ABS_32, inp_store_abs_32)
+#pragma bytecode(BC_STORE_ADDR_32, inp_store_abs_32.inp_store_addr_32)
+
+__asm inp_lea_abs
+{
+ lda (ip), y
+ tax
+ iny
+ lda (ip), y
+ sta $00, x
+ iny
+ lda (ip), y
+ sta $01, x
+ iny
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_LEA_ABS, inp_lea_abs)
+
+__asm inp_load_local_16
+{
+ lda (ip), y
+ tax
+ iny
+ lda (ip), y
+ iny
+ sty tmpy
+ tay
+ lda (fp), y
+ sta $00, x
+ iny
+ lda (fp), y
+ sta $01, x
+ ldy tmpy
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_LOAD_LOCAL_16, inp_load_local_16)
+
+__asm inp_load_local_32
+{
+ lda (ip), y
+ tax
+ iny
+ lda (ip), y
+ iny
+ sty tmpy
+ tay
+ lda (fp), y
+ sta $00, x
+ iny
+ lda (fp), y
+ sta $01, x
+ iny
+ lda (fp), y
+ sta $02, x
+ iny
+ lda (fp), y
+ sta $03, x
+ ldy tmpy
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_LOAD_LOCAL_32, inp_load_local_32)
+
+__asm inp_load_local_u8
+{
+ lda (ip), y
+ tax
+ iny
+ lda (ip), y
+ iny
+ sty tmpy
+ tay
+ lda (fp), y
+ sta $00, x
+ lda #0
+ sta $01, x
+ ldy tmpy
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_LOAD_LOCAL_U8, inp_load_local_u8)
+
+__asm inp_load_local_s8
+{
+ lda (ip), y
+ tax
+ iny
+ lda (ip), y
+ iny
+ sty tmpy
+ tay
+ lda (fp), y
+ sta $00, x
+ bmi W1
+ lda #0
+ byt $2c
+W1: lda #$ff
+ sta $01, x
+ ldy tmpy
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_LOAD_LOCAL_I8, inp_load_local_s8)
+
+__asm inp_store_local_8
+{
+ lda (ip), y
+ tax
+ iny
+ lda (ip), y
+ iny
+ sty tmpy
+ tay
+ lda $00, x
+ sta (fp), y
+ ldy tmpy
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_STORE_LOCAL_8, inp_store_local_8)
+
+__asm inp_store_local_16
+{
+ lda (ip), y
+ tax
+ iny
+ lda (ip), y
+ iny
+ sty tmpy
+ tay
+ lda $00, x
+ sta (fp), y
+ iny
+ lda $01, x
+ sta (fp), y
+ ldy tmpy
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_STORE_LOCAL_16, inp_store_local_16)
+
+__asm inp_store_local_32
+{
+ lda (ip), y
+ tax
+ iny
+ lda (ip), y
+ iny
+ sty tmpy
+ tay
+ lda $00, x
+ sta (fp), y
+ iny
+ lda $01, x
+ sta (fp), y
+ iny
+ lda $02, x
+ sta (fp), y
+ iny
+ lda $03, x
+ sta (fp), y
+ ldy tmpy
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_STORE_LOCAL_32, inp_store_local_32)
+
+__asm inp_lea_local
+{
+ lda (ip), y
+ tax
+ iny
+ clc
+ lda (ip), y
+ adc fp
+ sta $00, x
+ iny
+ lda (ip), y
+ adc fp + 1
+ sta $01, x
+ iny
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_LEA_LOCAL, inp_lea_local)
+
+__asm inp_store_frame_8
+{
+ lda (ip), y
+ tax
+ iny
+ lda (ip), y
+ iny
+ sty tmpy
+ tay
+ lda $00, x
+ sta (sp), y
+ ldy tmpy
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_STORE_FRAME_8, inp_store_frame_8)
+
+__asm inp_store_frame_16
+{
+ lda (ip), y
+ tax
+ iny
+ lda (ip), y
+ iny
+ sty tmpy
+ tay
+ lda $00, x
+ sta (sp), y
+ iny
+ lda $01, x
+ sta (sp), y
+ ldy tmpy
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_STORE_FRAME_16, inp_store_frame_16)
+
+__asm inp_store_frame_32
+{
+ lda (ip), y
+ tax
+ iny
+ lda (ip), y
+ iny
+ sty tmpy
+ tay
+ lda $00, x
+ sta (sp), y
+ iny
+ lda $01, x
+ sta (sp), y
+ iny
+ lda $02, x
+ sta (sp), y
+ iny
+ lda $03, x
+ sta (sp), y
+ ldy tmpy
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_STORE_FRAME_32, inp_store_frame_32)
+
+__asm inp_op_negate_16
+{
+ sec
+ lda #0
+ sbc accu
+ sta accu
+ lda #0
+ sbc accu + 1
+ sta accu + 1
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_OP_NEGATE_16, inp_op_negate_16)
+
+__asm inp_op_invert_16
+{
+ lda accu
+ eor #$ff
+ sta accu
+ lda accu + 1
+ eor #$ff
+ sta accu + 1
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_OP_INVERT_16, inp_op_invert_16)
+
+__asm inp_binop_addr_16
+{
+ lda (ip), y
+ tax
+ iny
+ clc
+ lda accu
+ adc $00, x
+ sta accu
+ lda accu + 1
+ adc $01, x
+ sta accu + 1
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_BINOP_ADDR_16, inp_binop_addr_16)
+
+__asm inp_binop_subr_16
+{
+ lda (ip), y
+ tax
+ iny
+ sec
+ lda accu
+ sbc $00, x
+ sta accu
+ lda accu + 1
+ sbc $01, x
+ sta accu + 1
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_BINOP_SUBR_16, inp_binop_subr_16)
+
+__asm inp_binop_andr_16
+{
+ lda (ip), y
+ tax
+ iny
+ lda accu
+ and $00, x
+ sta accu
+ lda accu + 1
+ and $01, x
+ sta accu + 1
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_BINOP_ANDR_16, inp_binop_andr_16)
+
+__asm inp_binop_orr_16
+{
+ lda (ip), y
+ tax
+ iny
+ lda accu
+ ora $00, x
+ sta accu
+ lda accu + 1
+ ora $01, x
+ sta accu + 1
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_BINOP_ORR_16, inp_binop_orr_16)
+
+__asm inp_binop_xorr_16
+{
+ lda (ip), y
+ tax
+ iny
+ lda accu
+ eor $00, x
+ sta accu
+ lda accu + 1
+ eor $01, x
+ sta accu + 1
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_BINOP_XORR_16, inp_binop_xorr_16)
+
+__asm inp_binop_mulr_16
+{
+ lda (ip), y
+ iny
+ tax
+ lda #0
+ sta tmp + 2
+ sta tmp + 3
+
+ lda $00, x
+ sta tmp + 0
+ lda $01, x
+ sta tmp + 1
+ ldx #16
+L1: lsr tmp + 1
+ ror tmp + 0
+ bcc W1
+ clc
+ lda tmp + 2
+ adc accu
+ sta tmp + 2
+ lda tmp + 3
+ adc accu + 1
+ sta tmp + 3
+W1: asl accu
+ rol accu + 1
+ dex
+ bne L1
+ lda tmp + 2
+ sta accu
+ lda tmp + 3
+ sta accu + 1
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_BINOP_MULR_16, inp_binop_mulr_16)
+
+__asm inp_binop_muli8_16
+{
+ lda (ip), y
+ iny
+ tax
+
+ lda #0
+ sta tmp + 2
+ sta tmp + 3
+
+ lda $00, x
+ sta tmp + 0
+ lda $01, x
+ sta tmp + 1
+
+ lda (ip), y
+ iny
+
+ lsr
+ sta tmp + 4
+ bcc L2
+L1:
+ clc
+ lda tmp + 2
+ adc tmp + 0
+ sta tmp + 2
+ lda tmp + 3
+ adc tmp + 1
+ sta tmp + 3
+L2:
+ asl tmp + 0
+ rol tmp + 1
+ lsr tmp + 4
+ bcs L1
+ bne L2
+
+ lda tmp + 2
+ sta $00, x
+ lda tmp + 3
+ sta $01, x
+
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_BINOP_MULI8_16, inp_binop_muli8_16)
+
+__asm inp_binop_divr_u16
+{
+ lda (ip), y
+ iny
+ tax
+ lda $00, x
+ sta tmp + 0
+ lda $01, x
+ sta tmp + 1
+ jsr divmod
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_BINOP_DIVR_U16, inp_binop_divr_u16)
+
+__asm inp_binop_modr_u16
+{
+ lda (ip), y
+ iny
+ tax
+ lda $00, x
+ sta tmp + 0
+ lda $01, x
+ sta tmp + 1
+ jsr divmod
+ lda tmp + 2
+ sta accu
+ lda tmp + 3
+ sta accu + 1
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_BINOP_MODR_U16, inp_binop_modr_u16)
+
+__asm negaccu
+{
+ sec
+ lda #0
+ sbc accu
+ sta accu
+ lda #0
+ sbc accu + 1
+ sta accu + 1
+ rts
+}
+
+__asm negtmp
+{
+ sec
+ lda #0
+ sbc tmp
+ sta tmp
+ lda #0
+ sbc tmp + 1
+ sta tmp + 1
+ rts
+}
+
+__asm inp_binop_divr_s16
+{
+ lda (ip), y
+ iny
+ tax
+ lda $00, x
+ sta tmp + 0
+ lda $01, x
+ sta tmp + 1
+ bit accu + 1
+ bpl L1
+ jsr negaccu
+ bit tmp + 1
+ bpl L2
+ jsr negtmp
+L3: jsr divmod
+ jmp startup.exec
+L1: bit tmp + 1
+ bpl L3
+ jsr negtmp
+L2: jsr divmod
+ jsr negaccu
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_BINOP_DIVR_I16, inp_binop_divr_s16)
+
+__asm inp_binop_modr_s16
+{
+ lda (ip), y
+ iny
+ tax
+ lda $00, x
+ sta tmp + 0
+ lda $01, x
+ sta tmp + 1
+ bit accu + 1
+ bpl L1
+ jsr negaccu
+ bit tmp + 1
+ bpl L2
+ jsr negtmp
+L3: jsr divmod
+ lda tmp + 2
+ sta accu
+ lda tmp + 3
+ sta accu + 1
+ jmp startup.exec
+L1: bit tmp + 1
+ bpl L3
+ jsr negtmp
+L2: jsr divmod
+ lda tmp + 2
+ sta accu
+ lda tmp + 3
+ sta accu + 1
+ jsr negaccu
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_BINOP_MODR_I16, inp_binop_modr_s16)
+
+__asm inp_binop_addi_16
+{
+ lda (ip), y
+ iny
+ tax
+ clc
+ lda $00, x
+ adc (ip), y
+ iny
+ sta $00, x
+ lda $01, x
+ adc (ip), y
+ iny
+ sta $01, x
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_BINOP_ADDI_16, inp_binop_addi_16)
+
+__asm inp_binop_subi_16
+{
+ lda (ip), y
+ iny
+ tax
+ sec
+ lda (ip), y
+ iny
+ sbc $00, x
+ sta $00, x
+ lda (ip), y
+ iny
+ sbc $01, x
+ sta $01, x
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_BINOP_SUBI_16, inp_binop_subi_16)
+
+__asm inp_binop_andi_16
+{
+ lda (ip), y
+ iny
+ tax
+ lda $00, x
+ and (ip), y
+ iny
+ sta $00, x
+ lda $01, x
+ and (ip), y
+ iny
+ sta $01, x
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_BINOP_ANDI_16, inp_binop_andi_16)
+
+__asm inp_binop_ori_16
+{
+ lda (ip), y
+ iny
+ tax
+ lda $00, x
+ ora (ip), y
+ iny
+ sta $00, x
+ lda $01, x
+ ora (ip), y
+ iny
+ sta $01, x
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_BINOP_ORI_16, inp_binop_ori_16)
+
+__asm inp_binop_shli_16
+{
+ lda (ip), y
+ iny
+ bne inp_binop_shlt_16
+inp_binop_shlr_16:
+ lda (ip), y
+ iny
+ tax
+ lda $00, x
+inp_binop_shlt_16:
+ and #$0f
+ beq W1
+ tax
+ lda accu + 1
+L1: asl accu
+ rol
+ dex
+ bne L1
+ sta accu + 1
+W1: jmp startup.exec
+}
+
+#pragma bytecode(BC_BINOP_SHLI_16, inp_binop_shli_16)
+#pragma bytecode(BC_BINOP_SHLR_16, inp_binop_shli_16.inp_binop_shlr_16)
+
+__asm inp_binop_shri_u16
+{
+ lda (ip), y
+ iny
+ bne inp_binop_shrt_u16
+inp_binop_shrr_u16:
+ lda (ip), y
+ iny
+ tax
+ lda $00, x
+inp_binop_shrt_u16:
+ and #$0f
+ beq W1
+ tax
+ lda accu + 1
+L1: lsr
+ ror accu
+ dex
+ bne L1
+ sta accu + 1
+W1: jmp startup.exec
+}
+
+#pragma bytecode(BC_BINOP_SHRI_U16, inp_binop_shri_u16)
+#pragma bytecode(BC_BINOP_SHRR_U16, inp_binop_shri_u16.inp_binop_shrr_u16)
+
+__asm inp_binop_shri_s16
+{
+ lda (ip), y
+ iny
+ bne inp_binop_shrt_s16
+inp_binop_shrr_s16:
+ lda (ip), y
+ iny
+ tax
+ lda $00, x
+inp_binop_shrt_s16:
+ and #$0f
+ beq W1
+ tax
+ lda accu + 1
+L1: cmp #$80
+ ror
+ ror accu
+ dex
+ bne L1
+ sta accu + 1
+W1: jmp startup.exec
+}
+
+#pragma bytecode(BC_BINOP_SHRI_I16, inp_binop_shri_s16)
+#pragma bytecode(BC_BINOP_SHRR_I16, inp_binop_shri_s16.inp_binop_shrr_s16)
+
+__asm cmp
+{
+inp_binop_cmpr_s16:
+ lda accu + 1
+ eor #$80
+ sta accu + 1
+ lda (ip), y
+ tax
+ iny
+ lda $01, x
+ eor #$80
+ cmp accu + 1
+ bne cmpne
+ lda $00 , x
+ cmp accu
+ bne cmpne
+ beq cmp_eq
+
+inp_binop_cmpr_u16:
+ lda (ip), y
+ tax
+ iny
+ lda $01, x
+ cmp accu + 1
+ bne cmpne
+ lda $00 , x
+ cmp accu
+ bne cmpne
+ beq cmp_eq
+
+inp_binop_cmpi_u16:
+ lda (ip), y
+ tax
+ iny
+ lda (ip), y
+ iny
+ cmp accu + 1
+ bne cmpne
+ cpx accu
+ bne cmpne
+cmp_eq:
+ lda #0
+ sta accu
+ sta accu + 1
+ jmp startup.exec
+cmp_lt:
+ lda #$ff
+ sta accu
+ sta accu +1
+ jmp startup.exec
+cmpne:
+ bcc cmp_lt
+ lda #1
+ sta accu
+ lda #0
+ sta accu + 1
+ jmp startup.exec
+
+inp_binop_cmpi_s16:
+ lda accu + 1
+ eor #$80
+ sta accu + 1
+ lda (ip), y
+ iny
+ tax
+ lda (ip), y
+ iny
+ eor #$80
+ cmp accu + 1
+ bne cmpne
+ cpx accu
+ bne cmpne
+ beq cmp_eq
+}
+
+#pragma bytecode(BC_BINOP_CMPSR_16, cmp.inp_binop_cmpr_s16)
+#pragma bytecode(BC_BINOP_CMPSI_16, cmp.inp_binop_cmpi_s16)
+#pragma bytecode(BC_BINOP_CMPUR_16, cmp.inp_binop_cmpr_u16)
+#pragma bytecode(BC_BINOP_CMPUI_16, cmp.inp_binop_cmpi_u16)
+
+__asm bra
+{
+inp_jumps:
+ lda (ip), y
+ bmi W1
+ sec
+ adc ip
+ sta ip
+ bcc W2
+ inc ip + 1
+W2: jmp startup.exec
+W1: sec
+ adc ip
+ sta ip
+ bcs W3
+ dec ip + 1
+W3: jmp startup.exec
+
+inp_branchs_eq:
+ lda accu
+ ora accu + 1
+ beq inp_jumps
+ iny
+ jmp startup.exec
+inp_branchs_ne:
+ lda accu
+ ora accu + 1
+ bne inp_jumps
+ iny
+ jmp startup.exec
+inp_branchs_gt:
+ lda accu + 1
+ bmi W4
+ ora accu
+ bne inp_jumps
+W4: iny
+ jmp startup.exec
+inp_branchs_ge:
+ lda accu + 1
+ bpl inp_jumps
+ iny
+ jmp startup.exec
+inp_branchs_lt:
+ lda accu + 1
+ bmi inp_jumps
+ iny
+ jmp startup.exec
+inp_branchs_le:
+ lda accu + 1
+ bmi inp_jumps
+ ora accu
+ beq inp_jumps
+ iny
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_JUMPS, bra.inp_jumps)
+#pragma bytecode(BC_BRANCHS_EQ, bra.inp_branchs_eq)
+#pragma bytecode(BC_BRANCHS_NE, bra.inp_branchs_ne)
+#pragma bytecode(BC_BRANCHS_GT, bra.inp_branchs_gt)
+#pragma bytecode(BC_BRANCHS_GE, bra.inp_branchs_ge)
+#pragma bytecode(BC_BRANCHS_LT, bra.inp_branchs_lt)
+#pragma bytecode(BC_BRANCHS_LE, bra.inp_branchs_le)
+
+__asm set
+{
+set_false:
+ lda #0
+ byt $2c
+set_true:
+ lda #1
+ sta accu
+ lda #0
+ sta accu + 1
+ jmp startup.exec
+
+inp_set_eq:
+ lda accu
+ ora accu + 1
+ beq set_true
+ bne set_false
+inp_set_ne:
+ lda accu
+ ora accu + 1
+ bne set_true
+ beq set_false
+inp_set_gt:
+ lda accu + 1
+ bmi set_false
+ ora accu
+ bne set_true
+ beq set_false
+
+inp_set_ge:
+ lda accu + 1
+ bpl set_true
+ bmi set_false
+inp_set_lt:
+ lda accu + 1
+ bmi set_true
+ bpl set_false
+inp_set_le:
+ lda accu + 1
+ bmi set_true
+ ora accu
+ beq set_true
+ bne set_false
+}
+
+#pragma bytecode(BC_SET_EQ, set.inp_set_eq)
+#pragma bytecode(BC_SET_NE, set.inp_set_ne)
+#pragma bytecode(BC_SET_GT, set.inp_set_gt)
+#pragma bytecode(BC_SET_GE, set.inp_set_ge)
+#pragma bytecode(BC_SET_LT, set.inp_set_lt)
+#pragma bytecode(BC_SET_LE, set.inp_set_le)
+
+__asm braf
+{
+inp_jumpf:
+ sec
+ lda (ip), y
+ adc ip
+ tax
+ iny
+ lda (ip) , y
+ adc ip + 1
+ sta ip + 1
+ stx ip
+ jmp startup.exec
+
+inp_branchf_eq:
+ lda accu
+ ora accu + 1
+ beq inp_jumpf
+ iny
+ iny
+ jmp startup.exec
+inp_branchf_ne:
+ lda accu
+ ora accu + 1
+ bne inp_jumpf
+ iny
+ iny
+ jmp startup.exec
+inp_branchf_gt:
+ lda accu + 1
+ bmi W1
+ ora accu
+ bne inp_jumpf
+W1: iny
+ iny
+ jmp startup.exec
+inp_branchf_ge:
+ lda accu + 1
+ bpl inp_jumpf
+ iny
+ iny
+ jmp startup.exec
+inp_branchf_lt:
+ lda accu + 1
+ bmi inp_jumpf
+ iny
+ iny
+ jmp startup.exec
+inp_branchf_le:
+ lda accu + 1
+ bmi inp_jumpf
+ ora accu
+ beq inp_jumpf
+ iny
+ iny
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_JUMPF, braf.inp_jumpf)
+#pragma bytecode(BC_BRANCHF_EQ, braf.inp_branchf_eq)
+#pragma bytecode(BC_BRANCHF_NE, braf.inp_branchf_ne)
+#pragma bytecode(BC_BRANCHF_GT, braf.inp_branchf_gt)
+#pragma bytecode(BC_BRANCHF_GE, braf.inp_branchf_ge)
+#pragma bytecode(BC_BRANCHF_LT, braf.inp_branchf_lt)
+#pragma bytecode(BC_BRANCHF_LE, braf.inp_branchf_le)
+
+__asm inp_enter
+{
+ // allocate space on stack
+ sec
+ lda sp
+ sbc (ip), y
+ iny
+ sta sp
+ lda sp + 1
+ sbc (ip), y
+ iny
+ sta sp + 1
+
+ // number of registers to save
+ lda (ip), y
+ iny
+ sty tmpy
+
+ // save frame pointer at end of list
+
+ tay
+ lda fp
+ sta (sp), y
+ iny
+ lda fp + 1
+ sta (sp), y
+
+ // calculate new frame pointer
+
+ tya
+ sec
+ adc sp
+ sta fp
+ lda #0
+ adc sp + 1
+ sta fp + 1
+
+ // copy registers
+ dey
+ beq W1
+
+L1: lda regs - 1, y
+ dey
+ sta (sp), y
+ bne L1
+
+ // done
+
+W1: ldy tmpy
+
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_ENTER, inp_enter)
+
+__asm inp_return
+{
+ // number of registers to restore
+
+ lda (ip), y
+ iny
+ sty tmpy
+
+ // restore frame pointer
+
+ tay
+ lda (sp), y
+ sta fp
+ iny
+ lda (sp), y
+ sta fp + 1
+
+ // copy registers
+
+ dey
+ beq W1
+
+ dey
+ beq W2
+
+L1: lda (sp), y
+ sta regs, y
+ dey
+ bne L1
+W2: lda (sp), y
+ sta regs, y
+W1:
+
+ // adjust stack space
+
+ ldy tmpy
+ clc
+ lda (ip), y
+ iny
+ adc sp
+ sta sp
+ lda (ip), y
+ iny
+ adc sp + 1
+ sta sp + 1
+
+ // reload ip from stack
+
+ ldy #0
+ lda (sp), y
+ sta ip
+ iny
+ lda (sp), y
+ sta ip + 1
+ dey
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_RETURN, inp_return)
+
+__asm inp_push_frame
+{
+ sec
+ lda sp
+ sbc (ip), y
+ iny
+ sta sp
+ lda sp + 1
+ sbc (ip), y
+ iny
+ sta sp + 1
+
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_PUSH_FRAME, inp_push_frame)
+
+__asm inp_pop_frame
+{
+ clc
+ lda (ip), y
+ iny
+ adc sp
+ sta sp
+ lda (ip), y
+ iny
+ adc sp + 1
+ sta sp + 1
+
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_POP_FRAME, inp_pop_frame)
+
+__asm inp_call
+{
+ tya
+ ldy #0
+ clc
+ adc ip
+ sta (sp), y
+ iny
+ lda ip + 1
+ adc #0
+ sta (sp), y
+ lda addr
+ sta ip
+ lda addr + 1
+ sta ip + 1
+ ldy #0
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_CALL, inp_call)
+
+__asm inp_copy
+{
+ lda (ip), y
+ iny
+ sty tmpy
+ tay
+ dey
+ beq W1
+L1: lda (accu), y
+ sta (addr), y
+ dey
+ bne L1
+W1:
+ lda (accu), y
+ sta (addr), y
+ ldy tmpy
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_COPY, inp_copy)
+
+__asm inp_copyl
+{
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_COPY_LONG, inp_copyl)
+
+__asm freg
+{
+split_exp:
+ lda (ip), y
+ iny
+ tax
+ lda $00, x
+ sta tmp + 0
+ lda $01, x
+ sta tmp + 1
+ lda $02, x
+ sta tmp + 2
+ lda $03, x
+ sta tmp + 3
+
+ lda tmp + 2
+ asl
+ lda tmp + 3
+ rol
+ sta tmp + 5
+ beq ZT
+ lda tmp + 2
+ ora #$80
+ sta tmp + 2
+ZT:
+
+split_aexp:
+ lda accu + 2
+ asl
+ lda accu + 3
+ rol
+ sta tmp + 4
+ beq ZA
+ lda accu + 2
+ ora #$80
+ sta accu + 2
+ZA:
+ rts
+
+merge_aexp:
+ asl accu + 3
+ lda tmp + 4
+ ror
+ sta accu + 3
+ bcs W1
+ lda accu + 2
+ and #$7f
+ sta accu + 2
+W1:
+ rts
+}
+
+__asm inp_binop_add_f32
+{
+ jsr freg.split_exp
+faddsub:
+ sec
+ lda tmp + 4
+ sbc tmp + 5
+ beq fas_aligned
+ tax
+
+ bcs fas_align2nd
+
+ // check if first operand is below rounding
+ cpx #-23
+ bcs W1
+
+ lda tmp + 5
+ sta tmp + 4
+ lda #0
+ sta accu
+ sta accu + 1
+ sta accu + 2
+ beq fas_aligned
+W1:
+ lsr accu + 2
+ ror accu + 1
+ ror accu
+ inx
+ bne W1
+ lda tmp + 5
+ sta tmp + 4
+ jmp fas_aligned
+
+fas_align2nd:
+ // check if second operand is below rounding
+ cpx #24
+ bcs fas_done
+
+L2: lsr tmp + 2
+ ror tmp + 1
+ ror tmp
+ dex
+ bne L2
+
+fas_aligned:
+ lda accu + 3
+ and #$80
+ sta accu + 3
+ eor tmp + 3
+ bmi fas_sub
+
+ clc
+ lda accu
+ adc tmp
+ sta accu
+ lda accu + 1
+ adc tmp + 1
+ sta accu + 1
+ lda accu + 2
+ adc tmp + 2
+ sta accu + 2
+ bcc fas_done
+ ror accu + 2
+ ror accu + 1
+ ror accu
+ inc tmp + 4
+fas_done:
+ lda tmp + 4
+ lsr
+ ora accu + 3
+ sta accu + 3
+ bcs W2
+ lda accu + 2
+ and #$7f
+ sta accu + 2
+W2:
+ jmp startup.exec
+
+fas_sub:
+ sec
+ lda accu
+ sbc tmp
+ sta accu
+ lda accu + 1
+ sbc tmp + 1
+ sta accu + 1
+ lda accu + 2
+ sbc tmp + 2
+ sta accu + 2
+ bcs fas_pos
+ sec
+ lda #0
+ sbc accu
+ sta accu
+ lda #0
+ sbc accu + 1
+ sta accu + 1
+ lda #0
+ sbc accu + 2
+ sta accu + 2
+ lda accu + 3
+ eor #$80
+ sta accu + 3
+fas_pos:
+ lda accu + 2
+ bmi fas_done
+
+ ora accu + 1
+ ora accu + 0
+ beq fas_zero
+L3:
+ dec tmp + 4
+ beq fas_zero // underflow
+ asl accu
+ rol accu + 1
+ rol accu + 2
+ bpl L3
+ jmp fas_done
+fas_zero:
+ lda #0
+ sta accu + 0
+ sta accu + 1
+ sta accu + 2
+ sta accu + 3
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_BINOP_ADD_F32, inp_binop_add_f32)
+
+__asm inp_binop_sub_f32
+{
+ jsr freg.split_exp
+ lda tmp + 3
+ eor #$80
+ sta tmp + 3
+ jmp inp_binop_add_f32.faddsub
+}
+
+#pragma bytecode(BC_BINOP_SUB_F32, inp_binop_sub_f32)
+
+__asm fmul8
+{
+ sec
+ ror
+ bcc L2
+L1: tax
+ clc
+ lda tmp + 6
+ adc accu
+ sta tmp + 6
+ lda tmp + 7
+ adc accu + 1
+ sta tmp + 7
+ lda tmp + 8
+ adc accu + 2
+ ror
+ sta tmp + 8
+ txa
+ ror tmp + 7
+ ror tmp + 6
+ lsr
+ beq W1
+ bcs L1
+L2:
+ ror tmp + 8
+ ror tmp + 7
+ ror tmp + 6
+ lsr
+ bcc L2
+ bne L1
+W1:
+ rts
+}
+
+__asm inp_binop_mul_f32
+{
+ jsr freg.split_exp
+
+ lda accu
+ ora accu + 1
+ ora accu + 2
+ bne W1
+ sta accu + 3
+ jmp startup.exec
+W1:
+ lda tmp
+ ora tmp + 1
+ ora tmp + 2
+ bne W2
+ sta accu
+ sta accu + 1
+ sta accu + 2
+ sta accu + 3
+ jmp startup.exec
+W2:
+ lda #0
+ sta tmp + 6
+ sta tmp + 7
+ sta tmp + 8
+
+ lda tmp
+ jsr fmul8
+ lda tmp + 1
+ jsr fmul8
+ lda tmp + 2
+ jsr fmul8
+
+ sec
+ lda tmp + 8
+ bmi W3
+ asl tmp + 6
+ rol tmp + 7
+ rol
+ clc
+W3: and #$7f
+ sta tmp + 8
+
+ lda accu + 3
+ eor tmp + 3
+ and #$80
+ sta accu + 3
+
+ lda tmp + 4
+ sbc #$7e
+
+ clc
+ adc tmp + 5
+ lsr
+ ora accu + 3
+ sta accu + 3
+ lda #0
+ ror
+ ora tmp + 8
+ sta accu + 2
+ lda tmp + 7
+ sta accu + 1
+ lda tmp + 6
+ sta accu
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_BINOP_MUL_F32, inp_binop_mul_f32)
+
+__asm inp_binop_div_f32
+{
+ jsr freg.split_exp
+
+ lda accu
+ ora accu + 1
+ ora accu + 2
+ bne W1
+ sta accu + 3
+ jmp startup.exec
+W1:
+ lda accu + 3
+ eor tmp + 3
+ and #$80
+ sta accu + 3
+
+ lda #0
+ sta tmp + 6
+ sta tmp + 7
+ sta tmp + 8
+ ldx #24
+
+L1:
+ lda accu + 0
+ cmp tmp + 0
+ lda accu + 1
+ sbc tmp + 1
+ lda accu + 2
+ sbc tmp + 2
+ bcc W2
+
+L2:
+ lda accu + 0
+ sbc tmp + 0
+ sta accu + 0
+ lda accu + 1
+ sbc tmp + 1
+ sta accu + 1
+ lda accu + 2
+ sbc tmp + 2
+ sta accu + 2
+ sec
+W2:
+ rol tmp + 6
+ rol tmp + 7
+ rol tmp + 8
+ dex
+ beq W3
+
+ asl accu
+ rol accu + 1
+ rol accu + 2
+ bcs L2
+ bcc L1
+W3:
+ sec
+ lda tmp + 8
+ bmi W4
+ asl tmp + 6
+ rol tmp + 7
+ rol
+ clc
+W4:
+ and #$7f
+ sta tmp + 8
+
+ lda tmp + 5
+ eor #$7f
+ adc tmp + 4
+ sec
+ sbc #1
+
+ lsr
+ ora accu + 3
+ sta accu + 3
+ lda #0
+ ror
+ ora tmp + 8
+ sta accu + 2
+ lda tmp + 7
+ sta accu + 1
+ lda tmp + 6
+ sta accu
+
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_BINOP_DIV_F32, inp_binop_div_f32)
+
+__asm inp_binop_cmp_f32
+{
+ lda (ip), y
+ iny
+ tax
+
+ lda accu + 3
+ eor $03, x
+ and #$80
+ beq W1
+
+ // different sig, check zero case
+
+ lda accu + 3
+ and #$7f
+ ora accu + 2
+ ora accu + 1
+ ora accu
+ bne W2
+
+ lda $03, x
+
+ and #$7f
+ ora $02, x
+ ora $01, x
+ ora $00, x
+ beq ibcmpf32eq
+W2: lda accu + 3
+ bmi ibcmpf32gt
+ bpl ibcmpf32lt
+
+W1:
+ // same sign
+ lda accu + 3
+ cmp $03, x
+ bne W3
+ lda accu + 2
+ cmp $02, x
+ bne W3
+ lda accu + 1
+ cmp $01, x
+ bne W3
+ lda accu
+ cmp $00, x
+ bne W3
+
+ibcmpf32eq:
+ lda #0
+ sta accu
+ sta accu + 1
+ jmp startup.exec
+
+W3: bcs W4
+
+ bit accu + 3
+ bmi ibcmpf32lt
+
+ibcmpf32gt:
+ lda #0
+ sta accu + 1
+ lda #1
+ sta accu
+ jmp startup.exec
+
+W4: bit accu + 3
+ bmi ibcmpf32gt
+
+ibcmpf32lt:
+ lda #$ff
+ sta accu
+ sta accu + 1
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_BINOP_CMP_F32, inp_binop_cmp_f32)
+
+__asm inp_op_negate_f32
+{
+ lda accu + 3
+ eor #$80
+ sta accu + 3
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_OP_NEGATE_F32, inp_op_negate_f32)
+
+__asm uin16_to_float
+{
+ lda accu
+ ora accu + 1
+ bne W1
+ sta accu + 2
+ sta accu + 3
+ rts
+W1:
+ ldx #$8e
+ lda accu + 1
+ bmi W2
+L1:
+ dex
+ asl accu
+ rol
+ bpl L1
+W2:
+ and #$7f
+ sta accu + 2
+ lda accu
+ sta accu + 1
+ txa
+ lsr
+ sta accu + 3
+ lda #0
+ sta accu
+ ror
+ ora accu + 2
+ sta accu + 2
+ rts
+}
+
+__asm inp_conv_u16_f32
+{
+ jsr uin16_to_float
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_CONV_U16_F32, inp_conv_u16_f32)
+
+__asm inp_conv_i16_f32
+{
+ bit accu + 1
+ bmi W1
+ jsr uin16_to_float
+ jmp startup.exec
+W1:
+ sec
+ lda #0
+ sbc accu
+ sta accu
+ lda #0
+ sbc accu + 1
+ sta accu + 1
+ jsr uin16_to_float
+ lda accu + 3
+ ora #$80
+ sta accu + 3
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_CONV_I16_F32, inp_conv_i16_f32)
+
+__asm inp_conv_f32_i16
+{
+ jsr freg.split_aexp
+ lda tmp + 4
+ cmp #$7f
+ bcs W1
+ lda #0
+ sta accu
+ sta accu + 1
+ jmp startup.exec
+W1:
+ sec
+ sbc #$8e
+ bcc W2
+ lda #$ff
+ sta accu
+ lda #$7f
+ sta accu + 1
+ bne W3
+W2:
+ tax
+L1:
+ lsr accu + 2
+ ror accu + 1
+ inx
+ bne L1
+W3:
+ bit accu + 3
+ bpl W4
+
+ sec
+ lda #0
+ sbc accu + 1
+ sta accu
+ lda #0
+ sbc accu + 2
+ sta accu + 1
+ jmp startup.exec
+W4:
+ lda accu + 1
+ sta accu
+ lda accu + 2
+ sta accu + 1
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_CONV_F32_I16, inp_conv_f32_i16)
+
+__asm inp_conv_f32_u16
+{
+ jsr freg.split_aexp
+ lda tmp + 4
+ cmp #$7f
+ bcs W1
+ lda #0
+ sta accu
+ sta accu + 1
+ jmp startup.exec
+W1:
+ sec
+ sbc #$8e
+ beq W2
+ bcc W3
+ lda #$ff
+ sta accu
+ sta accu + 1
+ jmp startup.exec
+W3:
+ tax
+L1:
+ lsr accu + 2
+ ror accu + 1
+ inx
+ bne L1
+W2:
+ lda accu + 1
+ sta accu
+ lda accu + 2
+ sta accu + 1
+
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_CONV_F32_U16, inp_conv_f32_u16)
+
+__asm inp_op_abs_f32
+{
+ lda accu + 3
+ and #$7f
+ sta accu + 3
+ jmp startup.exec
+}
+
+#pragma bytecode(BC_OP_ABS_F32, inp_op_abs_f32)
+
+unsigned char ubitmask[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
+
+__asm fround {
+frdzero:
+ lda #0
+ sta accu
+ sta accu + 1
+ sta accu + 2
+ sta accu + 3
+ jmp startup.exec
+
+frdown:
+ lda tmp + 4
+ cmp #$7f
+ bcc frdzero
+ cmp #$87
+ bcc frd1
+ cmp #$8f
+ bcc frd2
+ cmp #$97
+ bcs frd3
+
+ sec
+ sbc #$8f
+ tax
+ lda accu
+ and ubitmask, x
+ sta accu
+
+ jmp frd3
+frd1:
+ sec
+ sbc #$7f
+ tax
+ lda accu + 2
+ and ubitmask, x
+ sta accu + 2
+ lda #0
+ sta accu
+ sta accu + 1
+
+ jmp frd3
+frd2:
+ sec
+ sbc #$87
+ tax
+ lda accu + 1
+ and ubitmask, x
+ sta accu + 1
+ lda #0
+ sta accu
+
+ jmp frd3
+
+frd3:
+ jsr freg.merge_aexp
+ jmp startup.exec
+
+frone:
+ lda #$7f
+ sta tmp + 4
+ lda #0
+ sta accu + 0
+ sta accu + 1
+ lda #$80
+ sta accu + 2
+ jsr freg.merge_aexp
+ jmp startup.exec
+frup:
+ lda accu
+ ora accu + 1
+ ora accu + 2
+ beq frdzero
+ lda tmp + 4
+ cmp #$7f
+ bcc frone
+ cmp #$87
+ bcc fru1
+ cmp #$8f
+ bcc fru2
+ cmp #$97
+ bcs fru3
+
+ sec
+ sbc #$8f
+ tax
+
+ clc
+ lda ubitmask, x
+ eor #$ff
+ adc accu
+ sta accu
+ lda #0
+ adc accu + 1
+ sta accu + 1
+ lda #0
+ adc accu + 2
+ bcc W1
+ ror
+ ror accu + 1
+ ror accu
+ inc tmp + 4
+W1: sta accu + 2
+ jmp frdown
+fru1:
+ sec
+ sbc #$7f
+ tax
+
+ clc
+ lda #$ff
+ adc accu
+ lda #$ff
+ adc accu + 1
+ lda ubitmask, x
+ eor #$ff
+ adc accu + 2
+ bcc W2
+ ror
+ ror accu + 1
+ ror accu
+ inc tmp + 4
+W2: sta accu + 2
+ jmp frdown
+fru2:
+ sec
+ sbc #$87
+ tax
+
+ clc
+ lda #$ff
+ adc accu
+ lda ubitmask, x
+ eor #$ff
+ adc accu + 1
+ sta accu + 1
+ lda #0
+ adc accu + 2
+ bcc W3
+ ror
+ ror accu + 1
+ ror accu
+ inc tmp + 4
+W3: sta accu + 2
+ jmp frdown
+fru3:
+ jsr freg.merge_aexp
+ jmp startup.exec
+}
+
+__asm inp_op_floor_f32
+{
+ jsr freg.split_aexp
+ bit accu + 3
+ bpl W1
+ jmp fround.frup
+W1: jmp fround.frdown
+}
+
+#pragma bytecode(BC_OP_FLOOR_F32, inp_op_floor_f32)
+
+
+__asm inp_op_ceil_f32
+{
+ jsr freg.split_aexp
+ bit accu + 3
+ bpl W1
+ jmp fround.frdown
+W1: jmp fround.frup
+}
+
+#pragma bytecode(BC_OP_CEIL_F32, inp_op_ceil_f32)
+
diff --git a/include/crt.h b/include/crt.h
new file mode 100644
index 0000000..5483cdc
--- /dev/null
+++ b/include/crt.h
@@ -0,0 +1,153 @@
+#ifndef CRT_H
+#define CRT_H
+
+#define tmpy 0x02
+#define tmp 0x03
+
+#define ip 0x19
+#define accu 0x1b
+#define addr 0x1f
+#define sp 0x23
+#define fp 0x25
+
+#define sregs 0x43
+#define regs 0x53
+
+
+enum ByteCode
+{
+ BC_NOP,
+ BC_EXIT,
+
+ BC_CONST_P8,
+ BC_CONST_N8,
+ BC_CONST_16,
+ BC_CONST_32,
+
+ BC_LOAD_REG_16,
+ BC_STORE_REG_16,
+ BC_ADDR_REG,
+ BC_LOAD_REG_32,
+ BC_STORE_REG_32,
+
+ BC_LOAD_ABS_U8,
+ BC_LOAD_ABS_I8,
+ BC_LOAD_ABS_16,
+ BC_LOAD_ABS_32,
+
+ BC_STORE_ABS_8,
+ BC_STORE_ABS_16,
+ BC_STORE_ABS_32,
+
+ BC_LEA_ABS,
+
+ BC_LOAD_LOCAL_U8,
+ BC_LOAD_LOCAL_I8,
+ BC_LOAD_LOCAL_16,
+ BC_LOAD_LOCAL_32,
+
+ BC_STORE_LOCAL_8,
+ BC_STORE_LOCAL_16,
+ BC_STORE_LOCAL_32,
+
+ BC_LEA_LOCAL,
+
+ BC_STORE_FRAME_8,
+ BC_STORE_FRAME_16,
+ BC_STORE_FRAME_32,
+
+ BC_LOAD_ADDR_U8,
+ BC_LOAD_ADDR_I8,
+ BC_LOAD_ADDR_16,
+ BC_LOAD_ADDR_32,
+
+ BC_STORE_ADDR_8,
+ BC_STORE_ADDR_16,
+ BC_STORE_ADDR_32,
+
+ BC_BINOP_ADDR_16,
+ BC_BINOP_SUBR_16,
+ BC_BINOP_ANDR_16,
+ BC_BINOP_ORR_16,
+ BC_BINOP_XORR_16,
+ BC_BINOP_MULR_16,
+ BC_BINOP_DIVR_U16,
+ BC_BINOP_MODR_U16,
+ BC_BINOP_DIVR_I16,
+ BC_BINOP_MODR_I16,
+ BC_BINOP_SHLR_16,
+ BC_BINOP_SHRR_U16,
+ BC_BINOP_SHRR_I16,
+
+ BC_BINOP_ADDI_16,
+ BC_BINOP_SUBI_16,
+ BC_BINOP_ANDI_16,
+ BC_BINOP_ORI_16,
+ BC_BINOP_MULI8_16,
+
+ BC_BINOP_SHLI_16,
+ BC_BINOP_SHRI_U16,
+ BC_BINOP_SHRI_I16,
+
+ BC_BINOP_CMPUR_16,
+ BC_BINOP_CMPSR_16,
+
+ BC_BINOP_CMPUI_16,
+ BC_BINOP_CMPSI_16,
+
+ BC_OP_NEGATE_16,
+ BC_OP_INVERT_16,
+
+ BC_BINOP_ADD_F32,
+ BC_BINOP_SUB_F32,
+ BC_BINOP_MUL_F32,
+ BC_BINOP_DIV_F32,
+ BC_BINOP_CMP_F32,
+ BC_OP_NEGATE_F32,
+ BC_OP_ABS_F32,
+ BC_OP_FLOOR_F32,
+ BC_OP_CEIL_F32,
+
+ BC_CONV_U16_F32,
+ BC_CONV_I16_F32,
+ BC_CONV_F32_U16,
+ BC_CONV_F32_I16,
+
+ BC_JUMPS,
+ BC_BRANCHS_EQ,
+ BC_BRANCHS_NE,
+ BC_BRANCHS_GT,
+ BC_BRANCHS_GE,
+ BC_BRANCHS_LT,
+ BC_BRANCHS_LE,
+
+ BC_JUMPF,
+ BC_BRANCHF_EQ,
+ BC_BRANCHF_NE,
+ BC_BRANCHF_GT,
+ BC_BRANCHF_GE,
+ BC_BRANCHF_LT,
+ BC_BRANCHF_LE,
+
+ BC_SET_EQ,
+ BC_SET_NE,
+ BC_SET_GT,
+ BC_SET_GE,
+ BC_SET_LT,
+ BC_SET_LE,
+
+ BC_ENTER,
+ BC_RETURN,
+ BC_CALL,
+ BC_PUSH_FRAME,
+ BC_POP_FRAME,
+
+ BC_JSR,
+
+ BC_COPY,
+ BC_COPY_LONG
+};
+
+#pragma compile("crt.c")
+
+#endif
diff --git a/include/limits.h b/include/limits.h
new file mode 100644
index 0000000..7796fd1
--- /dev/null
+++ b/include/limits.h
@@ -0,0 +1,18 @@
+#ifndef LIMITS_H
+#define LIMITS_H
+
+#define CHAR_BIT 8
+
+#define SCHAR_MIN -128
+#define SCHAR_MAX 127
+
+#define UCHAR_MAX 255
+
+#define CHAR_MIN SCHAR_MIN
+#define CHAR_MAX SCHAR_MAX
+
+#define INT_MIN -32767
+#define INT_MAX 32767
+#define UINT_MAX 65535
+
+#endif
diff --git a/include/math.c b/include/math.c
new file mode 100644
index 0000000..fcda6ef
--- /dev/null
+++ b/include/math.c
@@ -0,0 +1,201 @@
+#include "math.h"
+#include "stdio.h"
+
+float cos(float f)
+{
+ return sin(f + 0.5 * PI);
+}
+
+#define F_SIN_1 6.283168
+#define F_SIN_2 0.053878661
+#define F_SIN_3 -42.5385038
+#define F_SIN_4 9.23583223
+#define F_SIN_5 55.7310503
+
+
+float sin(float f)
+{
+ float g = fabs(f);
+ float m = f < 0.0 ? -1.0 : 1.0;
+
+ g *= 0.5 / PI;
+ g -= floor(g);
+
+ if (g >= 0.5)
+ {
+ m = -m;
+ g -= 0.5;
+ }
+ if (g >= 0.25)
+ g = 0.5 - g;
+
+ float s = F_SIN_5;
+ s *= g; s += F_SIN_4;
+ s *= g; s += F_SIN_3;
+ s *= g; s += F_SIN_2;
+ s *= g; s += F_SIN_1;
+ s *= g;
+
+ return s * m;
+}
+
+float tan(float f)
+{
+ return sin(f) / cos(f);
+}
+
+float acos(float f)
+{
+ return atan2(sqrt(1.0 - f * f), f);
+}
+
+float asin(float f)
+{
+ return atan2(f, sqrt(1.0 - f * f));
+}
+
+float atan(float f)
+{
+ return atan2(f, 1.0);
+}
+
+#define F_ATAN_0 -6.435678E-5
+#define F_ATAN_1 0.999648382
+#define F_ATAN_2 0.018278903
+#define F_ATAN_3 -0.444599298
+#define F_ATAN_4 0.263177486
+#define F_ATAN_5 -0.051078392
+
+
+float atan2(float p, float q)
+{
+ int quad = 0;
+
+ if (p < 0)
+ {
+ quad |= 4;
+ p = -p;
+ }
+ if (q < 0)
+ {
+ quad |= 2;
+ q = -q;
+ }
+
+ float g;
+ if (p > q)
+ {
+ g = q / p;
+ quad |= 1;
+ }
+ else
+ {
+ g = p / q;
+ }
+
+ float s = F_ATAN_5;
+ s *= g; s += F_ATAN_4;
+ s *= g; s += F_ATAN_3;
+ s *= g; s += F_ATAN_2;
+ s *= g; s += F_ATAN_1;
+ s *= g; s += F_ATAN_0
+
+ if (quad & 1)
+ s = 0.5 * PI - s;
+ if (quad & 2)
+ s = PI - s;
+ if (quad & 4)
+ s = -s;
+
+ return s;
+}
+
+#define F_EXP_0 1.0000003
+#define F_EXP_1 0.693147059
+#define F_EXP_2 0.240173099
+#define F_EXP_3 0.055816392
+#define F_EXP_4 0.008965036
+#define F_EXP_5 0.001898429
+
+float exp(float f)
+{
+ f *= 1.442695041;
+
+ float ff = floor(f), g = f - ff;
+
+ int fi = (int)ff;
+
+ float fx = 0;
+ ((int*)&fx)[1] = (fi + 0x7f) << 7;
+
+ float s = F_EXP_5;
+ s *= g; s += F_EXP_4;
+ s *= g; s += F_EXP_3;
+ s *= g; s += F_EXP_2;
+ s *= g; s += F_EXP_1;
+ s *= g; s += F_EXP_0
+
+ return s * fx;
+}
+
+#define F_LOG_0 -2.79423993
+#define F_LOG_1 5.05984692
+#define F_LOG_2 -3.49247429
+#define F_LOG_3 1.58181193
+#define F_LOG_4 -0.396821126
+#define F_LOG_5 0.041845518
+
+float log(float f)
+{
+ if (f == 0.0)
+ return 1.0;
+
+ float fx = f;
+ int ei = ((int*)&fx)[1];
+ int ex = (ei >> 7) - 0x7f;
+ ((int*)&fx)[1] = (ei & 0x007f) | 0x3f80;
+
+ float g = fx;
+
+ float fex = ex;
+
+ float s = F_LOG_5;
+ s *= g; s += F_LOG_4;
+ s *= g; s += F_LOG_3;
+ s *= g; s += F_LOG_2;
+ s *= g; s += F_LOG_1;
+ s *= g; s += F_LOG_0
+
+ return (fex + s) * 0.6931471806;
+}
+
+float log10(float f)
+{
+ return log(f) * 0.4342944819;
+}
+
+float pow(float p, float q)
+{
+ return exp(p * log(q));
+}
+
+float sqrt(float f)
+{
+ if (f >= 0)
+ {
+ float fx = f;
+ int ex = (((int*)&fx)[1] >> 7) - 0x7f;
+ ex /= 2;
+ ((int*)&fx)[1] = (ex + 0x7f) << 7;
+ float fq = fx;
+ fq = 0.5 * (fq + f / fq);
+ fq = 0.5 * (fq + f / fq);
+ fq = 0.5 * (fq + f / fq);
+ fq = 0.5 * (fq + f / fq);
+ return fq;
+ }
+ else
+ return 0.0;
+}
+
+
diff --git a/include/math.h b/include/math.h
new file mode 100644
index 0000000..6d86800
--- /dev/null
+++ b/include/math.h
@@ -0,0 +1,34 @@
+#ifndef MATH_H
+#define MATH_H
+
+#define PI 3.141592653
+
+
+float fabs(float f);
+float floor(float f);
+float ceil(float f);
+
+float cos(float f);
+float sin(float f);
+float tan(float f);
+float acos(float f);
+float asin(float f);
+float atan(float f);
+float atan2(float p, float q);
+
+float exp(float f);
+float log(float f);
+float log10(float f);
+
+float pow(float p, float q);
+float sqrt(float f);
+
+#pragma intrinsic(fabs)
+#pragma intrinsic(floor)
+#pragma intrinsic(ceil)
+
+#pragma compile("math.c")
+
+
+#endif
+
diff --git a/include/stdio.c b/include/stdio.c
new file mode 100644
index 0000000..0b65bc6
--- /dev/null
+++ b/include/stdio.c
@@ -0,0 +1,165 @@
+#include "stdio.h"
+#include
+
+void putchar(char c)
+{
+ __asm {
+ ldy #2
+ lda (fp), y
+ jsr 0xffd2
+ }
+}
+
+char getchar(void)
+{
+ __asm {
+ jsr 0xffcf
+ sta 0x1b
+ lda #0
+ sta 0x1c
+ }
+}
+
+void puts(const char * str)
+{
+ __asm {
+ ldy #2
+ lda (fp), y
+ sta 0x02
+ iny
+ lda (fp), y
+ sta 0x03
+ ldy #0
+ lda (0x02), y
+ beq done
+ loop:
+ jsr 0xffd2
+ inc 0x02
+ bne next
+ inc 0x03
+ next:
+ ldy #0
+ lda (0x02), y
+ bne loop
+ done:
+ }
+}
+
+char * gets(char * str)
+{
+ __asm {
+ ldy #2
+ lda (fp), y
+ sta 0x02
+ iny
+ lda (fp), y
+ sta 0x03
+ loop:
+ jsr 0xffcf
+ ldy #0
+ cmp #13
+ beq done
+ sta (0x02), y
+ inc 0x02
+ bne loop
+ inc 0x03
+ bne loop
+ done:
+ lda #0
+ sta (0x02), y
+ }
+
+ return str;
+}
+
+void printf(const char * fmt, ...)
+{
+ const char * p = fmt;
+ char c, buff[14];
+ int * fps = (int *)&fmt + 1;
+
+ while (c = *p++)
+ {
+ if (c == '%')
+ {
+ c = *p++;
+ if (c == 'd')
+ {
+ itoa(*fps++, buff, 10);
+ puts(buff);
+ }
+ else if (c == 'x')
+ {
+ utoa(*fps++, buff, 16);
+ puts(buff);
+ }
+ else if (c == 'f')
+ {
+ ftoa(*(float *)fps, buff);
+ puts(buff);
+ fps ++;
+ fps ++;
+ }
+ else if (c == 's')
+ {
+ puts((char *)*fps++);
+ }
+ else if (c)
+ {
+ putchar(c);
+ }
+ }
+ else
+ putchar(c);
+ }
+}
+
+int sprintf(char * str, const char * fmt, ...)
+{
+ const char * p = fmt, * d = str;
+ char c;
+ int * fps = (int *)&fmt + 1;
+
+ while (c = *p++)
+ {
+ if (c == '%')
+ {
+ c = *p++;
+ if (c == 'd')
+ {
+ itoa(*fps++, d, 10);
+ while (*d)
+ d++;
+ }
+ else if (c == 'x')
+ {
+ utoa(*fps++, d, 16);
+ while (*d)
+ d++;
+ }
+ else if (c == 'f')
+ {
+ ftoa(*(float *)fps, d);
+ fps += 2;
+ while (*d)
+ d++;
+ }
+ else if (c == 's')
+ {
+ char * s = (char *)*fps++;
+ while (c = *s++)
+ *d++ = c;
+ }
+ else if (c)
+ {
+ *d++ = c;
+ }
+ }
+ else
+ *d++ = c;
+ }
+ *d = 0;
+ return d - str;
+}
+
+
diff --git a/include/stdio.h b/include/stdio.h
new file mode 100644
index 0000000..292b9cf
--- /dev/null
+++ b/include/stdio.h
@@ -0,0 +1,21 @@
+#ifndef STDIO_H
+#define STDIO_H
+
+#include
+
+void putchar(char c);
+
+char getchar(void);
+
+void puts(const char * str);
+
+char * gets(char * str);
+
+void printf(const char * fmt, ...);
+
+int sprintf(char * str, const char * fmt, ...);
+
+#pragma compile("stdio.c")
+
+#endif
+
diff --git a/include/stdlib.c b/include/stdlib.c
new file mode 100644
index 0000000..ec1ff19
--- /dev/null
+++ b/include/stdlib.c
@@ -0,0 +1,307 @@
+#include "stdlib.h"
+#include "string.h"
+#include "stdio.h"
+
+void itoa(int n, char * s, int radix)
+{
+ bool neg = n < 0;
+ if (neg)
+ {
+ n = - n;
+ }
+
+ int i = 0;
+ do {
+ int d = n % radix;
+ if (d < 10)
+ d += '0';
+ else
+ d += 'A' - 10;
+ s[i++] = d;
+ } while ((n /= radix) > 0);
+
+ if (neg)
+ {
+ s[i++] = '-';
+ }
+ s[i] = 0;
+ int j = 0;
+ while (j + 1 < i)
+ {
+ char c = s[j];
+ s[j++] = s[--i];
+ s[i] = c;
+ }
+}
+
+void utoa(unsigned int n, char * s, unsigned int radix)
+{
+ int i = 0;
+ do {
+ unsigned int d = n % radix;
+ if (d < 10)
+ d += '0';
+ else
+ d += 'A' - 10;
+ s[i++] = d;
+ } while ((n /= radix) > 0);
+
+ s[i] = 0;
+ int j = 0;
+ while (j + 1 < i)
+ {
+ char c = s[j];
+ s[j++] = s[--i];
+ s[i] = c;
+ }
+}
+
+void ftoa(float f, char * s)
+{
+ if (f < 0.0)
+ {
+ f = -f;
+ *s++ = '-';
+ }
+
+ int digits = 0;
+ while (f >= 1000.0)
+ {
+ f /= 1000;
+ digits += 3;
+ }
+
+ if (f != 0.0)
+ {
+ while (f < 1.0)
+ {
+ f *= 1000;
+ digits -= 3;
+ }
+
+ while (f >= 10.0)
+ {
+ f /= 10;
+ digits ++;
+ }
+
+ f += 0.0000005;
+ if (f >= 10.0)
+ {
+ f /= 10.0;
+ digits ++;
+ }
+ }
+
+ int exp = 0;
+ if (digits < 0)
+ {
+ exp = digits;
+ digits = 0;
+ }
+ else if (digits > 6)
+ {
+ exp = digits;
+ digits = 0;
+ }
+
+ for(int i=0; i<7; i++)
+ {
+ int c = (int)f;
+ f -= (float)c;
+ f *= 10.0;
+ *s++ = c + '0';
+ if (i == digits)
+ *s++ = '.';
+ }
+ if (exp)
+ {
+ *s++ = 'E';
+ if (exp < 0)
+ {
+ *s++ = '-';
+ exp = -exp;
+ }
+ else
+ *s++ = '+';
+
+ if (exp >= 10)
+ {
+ *s++ = exp / 10 + '0';
+ exp %= 10;
+ }
+ *s++ = exp + '0';
+ }
+
+ *s++= 0;
+}
+
+int atoi(const char * s)
+{
+ char c;
+ while ((c = *s++) <= ' ')
+ if (!c) return 0;
+
+ bool neg = false;
+ if (c == '-')
+ {
+ neg = true;
+ c = *s++;
+ }
+ else if (c == '+')
+ c = *s++;
+
+ int v = 0;
+ while (c >= '0' && c <= '9')
+ {
+ v = v * 10 + (c - '0');
+ c = *s++;
+ }
+
+ if (neg)
+ v = -v;
+
+ return v;
+}
+
+void exit(int status)
+{
+ __asm {
+ ldy #status
+ lda (fp), y
+ sta accu + 0
+ iny
+ lda (fp), y
+ sta accu + 1
+ pla
+ pla
+ }
+}
+
+struct Heap {
+ unsigned int size;
+ Heap * next;
+} * freeHeap;
+
+bool freeHeapInit = false;
+
+void * malloc(unsigned int size)
+{
+ size = (size + 7) & ~3;
+ if (!freeHeapInit)
+ {
+ freeHeap = (Heap *)*(int *)0x2d;
+ freeHeap->next = nullptr;
+ freeHeap->size = 0xa000 - 4096 - (int)freeHeap;
+ freeHeapInit = true;
+ }
+
+ Heap * pheap = nullptr, * heap = freeHeap;
+ while (heap)
+ {
+ if (size <= heap->size)
+ {
+ if (size == heap->size)
+ {
+ if (pheap)
+ pheap->next = heap->next;
+ else
+ freeHeap = heap->next;
+ }
+ else
+ {
+ Heap * nheap = (Heap *)((int)heap + size);
+ nheap->size = heap->size - size;
+ nheap->next = heap->next;
+ if (pheap)
+ pheap->next = nheap;
+ else
+ freeHeap = nheap;
+ heap->size = size;
+ }
+
+ return (void *)((int)heap + 2);
+ }
+ pheap = heap;
+ heap = heap->next;
+ }
+
+ return nullptr;
+}
+
+void free(void * ptr)
+{
+ if (!ptr)
+ return;
+
+ Heap * fheap = (Heap *)((int)ptr - 2);
+ Heap * eheap = (Heap *)((int)ptr - 2 + fheap->size);
+
+ if (freeHeap)
+ {
+ if (eheap == freeHeap)
+ {
+ fheap->size += freeHeap->size;
+ fheap->next = freeHeap->next;
+ freeHeap = fheap;
+ }
+ else if (eheap < freeHeap)
+ {
+ fheap->next = freeHeap;
+ freeHeap = fheap;
+ }
+ else
+ {
+ Heap * pheap = freeHeap;
+ while (pheap->next && pheap->next < fheap)
+ pheap = pheap->next;
+ Heap * nheap = (Heap *)((int)pheap + pheap->size);
+
+ if (nheap == fheap)
+ {
+ pheap->size += fheap->size;
+ if (pheap->next == eheap)
+ {
+ pheap->size += pheap->next->size;
+ pheap->next = pheap->next->next;
+ }
+ }
+ else if (pheap->next == eheap)
+ {
+ fheap->next = pheap->next->next;
+ fheap->size += pheap->next->size;
+ pheap->next = fheap;
+ }
+ else
+ {
+ fheap->next = pheap->next;
+ pheap->next = fheap;
+ }
+ }
+ }
+ else
+ {
+ freeHeap = fheap;
+ freeHeap->next = nullptr;
+ }
+}
+
+void * calloc(int num, int size)
+{
+ size *= num;
+ void * p = malloc(size);
+ if (p)
+ memclr(p, size);
+ return p;
+}
+
+unsigned seed = 31232;
+
+unsigned int rand(void)
+{
+ seed ^= seed << 7;
+ seed ^= seed >> 9;
+ seed ^= seed << 8;
+ return seed;
+}
+
diff --git a/include/stdlib.h b/include/stdlib.h
new file mode 100644
index 0000000..8074ef4
--- /dev/null
+++ b/include/stdlib.h
@@ -0,0 +1,24 @@
+#ifndef STDLIB_H
+#define STDLIB_H
+
+void itoa(int n, char * s, int radix);
+
+void utoa(unsigned int n, char * s, unsigned int radix);
+
+void ftoa(float f, char * s);
+
+int atoi(const char * s);
+
+void exit(int status);
+
+void * malloc(unsigned int size);
+
+void free(void * ptr);
+
+void * calloc(int num, int size);
+
+unsigned int rand(void);
+
+#pragma compile("stdlib.c")
+
+#endif
diff --git a/include/string.c b/include/string.c
new file mode 100644
index 0000000..ba50754
--- /dev/null
+++ b/include/string.c
@@ -0,0 +1,148 @@
+#include "string.h"
+
+char * strcpy(char * dst, const char * src)
+{
+ char * d = dst;
+ const char * s = src;
+
+ do {} while (*d++ = *s++);
+
+ return dst;
+}
+
+int strcmp(const char * ptr1, const char * ptr2)
+{
+ const char * p = ptr1, * q = ptr2;
+ char c, d;
+ while ((c = *p++) == (d = *q++))
+ {
+ if (!c)
+ return 0;
+ }
+ if (c < d)
+ return -1;
+ else
+ return 1;
+}
+
+int strlen(const char * str)
+{
+ const char * s = str;
+
+ int i = 0;
+ while (s[i])
+ i++;
+ return i;
+}
+
+char * strcat(char * dst, const char * src)
+{
+ char * d = dst;
+ const char * s = src;
+
+ while (*d)
+ d++;
+
+ do {} while (*d++ = *s++);
+
+ return dst;
+}
+
+void * memset(void * dst, int value, int size)
+{
+ __asm
+ {
+ ldy #dst
+ lda (fp), y
+ sta $1f
+ iny
+ lda (fp), y
+ sta $20
+
+ ldy #size
+ lda (fp), y
+ sta $1b
+ iny
+ lda (fp), y
+ sta $1c
+
+ ldy #value
+ lda (fp), y
+
+ ldx $1c
+ beq _w1
+ ldy #0
+ _loop1:
+ sta ($1f), y
+ iny
+ bne _loop1
+ inc $20
+ dex
+ bne _loop1
+ _w1:
+ ldy $1b
+ beq _w2
+ _loop2:
+ dey
+ sta ($1f), y
+ bne _loop2
+ _w2:
+ }
+ return dst;
+}
+
+
+void * memclr(void * dst, int size)
+{
+ char * d = dst;
+ while (size--)
+ *d++ = 0;
+ return dst;
+}
+
+void * memcpy(void * dst, const void * src, int size)
+{
+ char * d = dst, * s = src;
+ while (size--)
+ *d++ = *s++;
+ return dst;
+}
+
+void * memmove(void * dst, const void * src, int size)
+{
+ char * d = dst, * s = src;
+ if (d < s)
+ {
+ while (size--)
+ *d++ = *s++;
+ }
+ else if (d > s)
+ {
+ d += size;
+ s += size;
+ while (size--)
+ *--d = *--s;
+ }
+ return dst;
+}
+
+int memcmp(const void * ptr1, const void * ptr2, int size)
+{
+ char * p = ptr1, * q = ptr2;
+ char c, d;
+
+ while (size--)
+ {
+ c = *p++;
+ d = *q++;
+ if (c < d)
+ return -1;
+ else if (c > d)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
diff --git a/include/string.h b/include/string.h
new file mode 100644
index 0000000..5aa4102
--- /dev/null
+++ b/include/string.h
@@ -0,0 +1,25 @@
+#ifndef STRING_H
+#define STRING_H
+
+char * strcpy(char * dst, const char * src);
+
+int strcmp(const char * ptr1, const char * ptr2);
+
+int strlen(const char * str);
+
+char * strcat(char * dst, const char * src);
+
+void * memclr(void * dst, int size);
+
+void * memset(void * dst, int value, int size);
+
+void * memcpy(void * dst, const void * src, int size);
+
+int memcmp(const void * ptr1, const void * ptr2, int size);
+
+void * memmove(void * dst, const void * src, int size);
+
+#pragma compile("string.c")
+
+#endif
+
diff --git a/oscar64.sln b/oscar64.sln
new file mode 100644
index 0000000..45839bc
--- /dev/null
+++ b/oscar64.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31624.102
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "oscar64", "oscar64\oscar64.vcxproj", "{1DBC623E-6109-41FE-B1BB-9B43FC984F7D}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {1DBC623E-6109-41FE-B1BB-9B43FC984F7D}.Debug|x64.ActiveCfg = Debug|x64
+ {1DBC623E-6109-41FE-B1BB-9B43FC984F7D}.Debug|x64.Build.0 = Debug|x64
+ {1DBC623E-6109-41FE-B1BB-9B43FC984F7D}.Debug|x86.ActiveCfg = Debug|Win32
+ {1DBC623E-6109-41FE-B1BB-9B43FC984F7D}.Debug|x86.Build.0 = Debug|Win32
+ {1DBC623E-6109-41FE-B1BB-9B43FC984F7D}.Release|x64.ActiveCfg = Release|x64
+ {1DBC623E-6109-41FE-B1BB-9B43FC984F7D}.Release|x64.Build.0 = Release|x64
+ {1DBC623E-6109-41FE-B1BB-9B43FC984F7D}.Release|x86.ActiveCfg = Release|Win32
+ {1DBC623E-6109-41FE-B1BB-9B43FC984F7D}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {C5E1AB04-FB65-4F70-B2F1-3787E7F84A41}
+ EndGlobalSection
+EndGlobal
diff --git a/oscar64/Array.h b/oscar64/Array.h
new file mode 100644
index 0000000..cba8bc9
--- /dev/null
+++ b/oscar64/Array.h
@@ -0,0 +1,250 @@
+#pragma once
+
+#include
+
+template
+class DynamicArray
+{
+protected:
+ int size, range;
+ T* array;
+
+ void Grow(int by)
+ {
+ T* a2;
+ int i;
+
+ if (size + by > range)
+ {
+ range = (size + by) * 2;
+ a2 = new T[range];
+ for (i = 0; i < size; i++) a2[i] = array[i];
+ delete[] array;
+ array = a2;
+ }
+
+ size += by;
+
+ }
+public:
+ DynamicArray(void)
+ {
+ size = 0;
+ range = 4;
+ array = new T[range];
+ }
+
+ ~DynamicArray(void)
+ {
+ delete[] array;
+ }
+
+ T* GetAndReleaseArray(void)
+ {
+ T* a2 = array;
+
+ size = 0;
+ range = 4;
+ array = new T[range];
+
+ return a2;
+ }
+
+ int Size(void) { return size; }
+
+ bool Insert(T t)
+ {
+ Grow(1);
+ array[size - 1] = t;
+
+ return true;
+ }
+
+ bool Insert(int n, T t)
+ {
+ int m;
+
+ if (n >= 0 && n <= size)
+ {
+ Grow(1);
+ m = size - 1;
+ while (m > n)
+ {
+ array[m] = array[m - 1];
+ m--;
+ }
+
+ array[n] = t;
+ }
+
+ return true;
+ }
+
+ bool Lookup(int n, T& t)
+ {
+ if (n >= 0 && n < size)
+ {
+ t = array[n];
+ return true;
+ }
+ else
+ return false;
+ }
+
+ bool Replace(int n, T t, T& old)
+ {
+ if (n >= 0 && n < size)
+ {
+ old = array[n];
+ array[n] = t;
+
+ return true;
+ }
+ else
+ return false;
+ }
+
+ bool Swap(int n, int m)
+ {
+ T t;
+
+ if (n >= 0 && n < size && m >= 0 && m < size)
+ {
+ t = array[n]; array[n] = array[m]; array[m] = t;
+
+ return true;
+ }
+ else
+ return false;
+ }
+
+ bool Remove(int n)
+ {
+ if (n >= 0 && n < size)
+ {
+ while (n < size - 1)
+ {
+ array[n] = array[n + 1];
+ n++;
+ }
+ size--;
+
+ return true;
+ }
+ else
+ return false;
+ }
+
+ int Find(T t)
+ {
+ int n;
+
+ n = size - 1;
+ while (n >= 0 && t != array[n])
+ n--;
+
+ return n;
+ }
+};
+
+template
+class GrowingArray
+{
+protected:
+ int size, range;
+ T* array;
+ T empty;
+
+ void Grow(int to, bool clear)
+ {
+ T* a2;
+ int i;
+
+ if (clear) size = 0;
+
+ if (to > range)
+ {
+ if (to > range * 2)
+ range = to;
+ else
+ range = range * 2;
+
+ a2 = new T[range];
+ for (i = 0; i < size; i++) a2[i] = array[i];
+ delete[] array;
+ array = a2;
+ }
+
+ for (i = size; i < to; i++) array[i] = empty;
+
+ size = to;
+ }
+
+public:
+ GrowingArray(T empty_)
+ : empty(empty_)
+ {
+ size = 0;
+ range = 4;
+ array = new T[range];
+ }
+
+ GrowingArray(const GrowingArray& a)
+ : empty(a.empty)
+ {
+ int i;
+ size = a.size;
+ range = a.range;
+ array = new T[range];
+ for (i = 0; i < size; i++) array[i] = a.array[i];
+ }
+
+ ~GrowingArray(void)
+ {
+ delete[] array;
+ }
+
+ __forceinline T& operator[](int n)
+ {
+ assert(n >= 0);
+ if (n >= size) Grow(n + 1, false);
+ return array[n];
+ }
+
+ __forceinline T operator[](int n) const
+ {
+ assert(n >= 0);
+ if (n >= size) return empty;
+ else return array[n];
+ }
+
+ __forceinline void Push(T t)
+ {
+ (*this)[size] = t;
+ }
+
+ __forceinline T Pop(void)
+ {
+ assert(size > 0);
+ return array[--size];
+ }
+
+ __forceinline T Top(void) const
+ {
+ return array[size - 1];
+ }
+
+ __forceinline bool IsEmpty(void) const { return size == 0; }
+
+ __forceinline int Size(void) const { return size; }
+
+ __forceinline void SetSize(int size, bool clear = false)
+ {
+ Grow(size, clear);
+ }
+
+ __forceinline void Clear(void)
+ {
+ Grow(size, true);
+ }
+};
diff --git a/oscar64/Assembler.cpp b/oscar64/Assembler.cpp
new file mode 100644
index 0000000..0642549
--- /dev/null
+++ b/oscar64/Assembler.cpp
@@ -0,0 +1,370 @@
+#pragma once
+
+#include "Assembler.h"
+#include
+
+
+AsmInsData DecInsData[256] = {
+ {ASMIT_BRK, ASMIM_IMPLIED},
+ {ASMIT_ORA, ASMIM_INDIRECT_X},
+ {ASMIT_INV},
+ {ASMIT_INV},
+ {ASMIT_INV},
+ {ASMIT_ORA, ASMIM_ZERO_PAGE},
+ {ASMIT_ASL, ASMIM_ZERO_PAGE},
+ {ASMIT_INV},
+ {ASMIT_PHP, ASMIM_IMPLIED},
+ {ASMIT_ORA, ASMIM_IMMEDIATE},
+ {ASMIT_ASL, ASMIM_IMPLIED},
+ {ASMIT_INV},
+ {ASMIT_INV},
+ {ASMIT_ORA, ASMIM_ABSOLUTE},
+ {ASMIT_ASL, ASMIM_ABSOLUTE},
+ {ASMIT_INV},
+
+ {ASMIT_BPL, ASMIM_RELATIVE },
+ {ASMIT_ORA, ASMIM_INDIRECT_Y},
+ {ASMIT_INV},
+ {ASMIT_INV},
+ {ASMIT_INV},
+ {ASMIT_ORA, ASMIM_ZERO_PAGE_X},
+ {ASMIT_ASL, ASMIM_ZERO_PAGE_X},
+ {ASMIT_INV},
+ {ASMIT_CLC, ASMIM_IMPLIED},
+ {ASMIT_ORA, ASMIM_ABSOLUTE_Y},
+ {ASMIT_INV},
+ {ASMIT_INV},
+ {ASMIT_INV},
+ {ASMIT_ORA, ASMIM_ABSOLUTE_X},
+ {ASMIT_ASL, ASMIM_ABSOLUTE_X},
+ {ASMIT_INV},
+
+
+ {ASMIT_JSR, ASMIM_ABSOLUTE},
+ {ASMIT_AND, ASMIM_INDIRECT_X},
+ {ASMIT_INV},
+ {ASMIT_INV},
+ {ASMIT_BIT, ASMIM_ZERO_PAGE},
+ {ASMIT_AND, ASMIM_ZERO_PAGE},
+ {ASMIT_ROL, ASMIM_ZERO_PAGE},
+ {ASMIT_INV},
+ {ASMIT_PLP, ASMIM_IMPLIED},
+ {ASMIT_AND, ASMIM_IMMEDIATE},
+ {ASMIT_ROL, ASMIM_IMPLIED},
+ {ASMIT_INV},
+ {ASMIT_BIT, ASMIM_ABSOLUTE},
+ {ASMIT_AND, ASMIM_ABSOLUTE},
+ {ASMIT_ROL, ASMIM_ABSOLUTE},
+ {ASMIT_INV},
+
+ {ASMIT_BMI, ASMIM_RELATIVE },
+ {ASMIT_AND, ASMIM_INDIRECT_Y},
+ {ASMIT_INV},
+ {ASMIT_INV},
+ {ASMIT_INV},
+ {ASMIT_AND, ASMIM_ZERO_PAGE_X},
+ {ASMIT_ROL, ASMIM_ZERO_PAGE_X},
+ {ASMIT_INV},
+ {ASMIT_SEC, ASMIM_IMPLIED},
+ {ASMIT_AND, ASMIM_ABSOLUTE_Y},
+ {ASMIT_INV},
+ {ASMIT_INV},
+ {ASMIT_INV},
+ {ASMIT_AND, ASMIM_ABSOLUTE_X},
+ {ASMIT_ROL, ASMIM_ABSOLUTE_X},
+ {ASMIT_INV},
+
+
+ {ASMIT_RTI, ASMIM_IMPLIED},
+ {ASMIT_EOR, ASMIM_INDIRECT_X},
+ {ASMIT_INV},
+ {ASMIT_INV},
+ {ASMIT_INV},
+ {ASMIT_EOR, ASMIM_ZERO_PAGE},
+ {ASMIT_LSR, ASMIM_ZERO_PAGE},
+ {ASMIT_INV},
+ {ASMIT_PHA, ASMIM_IMPLIED},
+ {ASMIT_EOR, ASMIM_IMMEDIATE},
+ {ASMIT_LSR, ASMIM_IMPLIED},
+ {ASMIT_INV},
+ {ASMIT_JMP, ASMIM_ABSOLUTE},
+ {ASMIT_EOR, ASMIM_ABSOLUTE},
+ {ASMIT_LSR, ASMIM_ABSOLUTE},
+ {ASMIT_INV},
+
+ {ASMIT_BVC, ASMIM_RELATIVE },
+ {ASMIT_EOR, ASMIM_INDIRECT_Y},
+ {ASMIT_INV},
+ {ASMIT_INV},
+ {ASMIT_INV},
+ {ASMIT_EOR, ASMIM_ZERO_PAGE_X},
+ {ASMIT_LSR, ASMIM_ZERO_PAGE_X},
+ {ASMIT_INV},
+ {ASMIT_CLI, ASMIM_IMPLIED},
+ {ASMIT_EOR, ASMIM_ABSOLUTE_Y},
+ {ASMIT_INV},
+ {ASMIT_INV},
+ {ASMIT_INV},
+ {ASMIT_EOR, ASMIM_ABSOLUTE_X},
+ {ASMIT_LSR, ASMIM_ABSOLUTE_X},
+ {ASMIT_INV},
+
+
+ { ASMIT_RTS, ASMIM_IMPLIED },
+ { ASMIT_ADC, ASMIM_INDIRECT_X },
+ { ASMIT_INV },
+ { ASMIT_INV },
+ { ASMIT_INV },
+ { ASMIT_ADC, ASMIM_ZERO_PAGE },
+ { ASMIT_ROR, ASMIM_ZERO_PAGE },
+ { ASMIT_INV },
+ { ASMIT_PLA, ASMIM_IMPLIED },
+ { ASMIT_ADC, ASMIM_IMMEDIATE },
+ { ASMIT_ROR, ASMIM_IMPLIED },
+ { ASMIT_INV },
+ { ASMIT_JMP, ASMIM_INDIRECT },
+ { ASMIT_ADC, ASMIM_ABSOLUTE },
+ { ASMIT_ROR, ASMIM_ABSOLUTE },
+ { ASMIT_INV },
+
+ { ASMIT_BVS, ASMIM_RELATIVE },
+ { ASMIT_ADC, ASMIM_INDIRECT_Y },
+ { ASMIT_INV },
+ { ASMIT_INV },
+ { ASMIT_INV },
+ { ASMIT_ADC, ASMIM_ZERO_PAGE_X },
+ { ASMIT_ROR, ASMIM_ZERO_PAGE_X },
+ { ASMIT_INV },
+ { ASMIT_SEI, ASMIM_IMPLIED },
+ { ASMIT_ADC, ASMIM_ABSOLUTE_Y },
+ { ASMIT_INV },
+ { ASMIT_INV },
+ { ASMIT_INV },
+ { ASMIT_ADC, ASMIM_ABSOLUTE_X },
+ { ASMIT_ROR, ASMIM_ABSOLUTE_X },
+ { ASMIT_INV },
+
+
+ { ASMIT_INV },
+ { ASMIT_STA, ASMIM_INDIRECT_X },
+ { ASMIT_INV },
+ { ASMIT_INV },
+ { ASMIT_STY, ASMIM_ZERO_PAGE },
+ { ASMIT_STA, ASMIM_ZERO_PAGE },
+ { ASMIT_STX, ASMIM_ZERO_PAGE },
+ { ASMIT_INV },
+ { ASMIT_DEY, ASMIM_IMPLIED },
+ { ASMIT_INV },
+ { ASMIT_TXA, ASMIM_IMPLIED },
+ { ASMIT_INV },
+ { ASMIT_STY, ASMIM_ABSOLUTE },
+ { ASMIT_STA, ASMIM_ABSOLUTE },
+ { ASMIT_STX, ASMIM_ABSOLUTE },
+ { ASMIT_INV },
+
+ { ASMIT_BCC, ASMIM_RELATIVE },
+ { ASMIT_STA, ASMIM_INDIRECT_Y },
+ { ASMIT_INV },
+ { ASMIT_INV },
+ { ASMIT_STY, ASMIM_ZERO_PAGE_X },
+ { ASMIT_STA, ASMIM_ZERO_PAGE_X },
+ { ASMIT_STX, ASMIM_ZERO_PAGE_Y },
+ { ASMIT_INV },
+ { ASMIT_TYA, ASMIM_IMPLIED },
+ { ASMIT_STA, ASMIM_ABSOLUTE_Y },
+ { ASMIT_TXS },
+ { ASMIT_INV },
+ { ASMIT_INV },
+ { ASMIT_STA, ASMIM_ABSOLUTE_X },
+ { ASMIT_INV },
+ { ASMIT_INV },
+
+
+ { ASMIT_LDY, ASMIM_IMMEDIATE },
+ { ASMIT_LDA, ASMIM_INDIRECT_X },
+ { ASMIT_LDX, ASMIM_IMMEDIATE },
+ { ASMIT_INV },
+ { ASMIT_LDY, ASMIM_ZERO_PAGE },
+ { ASMIT_LDA, ASMIM_ZERO_PAGE },
+ { ASMIT_LDX, ASMIM_ZERO_PAGE },
+ { ASMIT_INV },
+ { ASMIT_TAY, ASMIM_IMPLIED },
+ { ASMIT_LDA, ASMIM_IMMEDIATE },
+ { ASMIT_TAX, ASMIM_IMPLIED },
+ { ASMIT_INV },
+ { ASMIT_LDY, ASMIM_ABSOLUTE },
+ { ASMIT_LDA, ASMIM_ABSOLUTE },
+ { ASMIT_LDX, ASMIM_ABSOLUTE },
+ { ASMIT_INV },
+
+ { ASMIT_BCS, ASMIM_RELATIVE },
+ { ASMIT_LDA, ASMIM_INDIRECT_Y },
+ { ASMIT_INV },
+ { ASMIT_INV },
+ { ASMIT_LDY, ASMIM_ZERO_PAGE_X },
+ { ASMIT_LDA, ASMIM_ZERO_PAGE_X },
+ { ASMIT_LDX, ASMIM_ZERO_PAGE_Y },
+ { ASMIT_INV },
+ { ASMIT_CLV, ASMIM_IMPLIED },
+ { ASMIT_LDA, ASMIM_ABSOLUTE_Y },
+ { ASMIT_TSX, ASMIM_IMPLIED },
+ { ASMIT_INV },
+ { ASMIT_LDY, ASMIM_ABSOLUTE_X },
+ { ASMIT_LDA, ASMIM_ABSOLUTE_X },
+ { ASMIT_LDX, ASMIM_ABSOLUTE_Y },
+ { ASMIT_INV },
+
+
+ { ASMIT_CPY, ASMIM_IMMEDIATE },
+ { ASMIT_CMP, ASMIM_INDIRECT_X },
+ { ASMIT_INV },
+ { ASMIT_INV },
+ { ASMIT_CPY, ASMIM_ZERO_PAGE },
+ { ASMIT_CMP, ASMIM_ZERO_PAGE },
+ { ASMIT_DEC, ASMIM_ZERO_PAGE },
+ { ASMIT_INV },
+ { ASMIT_INY, ASMIM_IMPLIED },
+ { ASMIT_CMP, ASMIM_IMMEDIATE },
+ { ASMIT_DEX, ASMIM_IMPLIED },
+ { ASMIT_INV },
+ { ASMIT_CPY, ASMIM_ABSOLUTE },
+ { ASMIT_CMP, ASMIM_ABSOLUTE },
+ { ASMIT_DEC, ASMIM_ABSOLUTE },
+ { ASMIT_INV },
+
+ { ASMIT_BNE, ASMIM_RELATIVE },
+ { ASMIT_CMP, ASMIM_INDIRECT_Y },
+ { ASMIT_INV },
+ { ASMIT_INV },
+ { ASMIT_INV },
+ { ASMIT_CMP, ASMIM_ZERO_PAGE_X },
+ { ASMIT_DEC, ASMIM_ZERO_PAGE_X },
+ { ASMIT_INV },
+ { ASMIT_CLD, ASMIM_IMPLIED },
+ { ASMIT_CMP, ASMIM_ABSOLUTE_Y },
+ { ASMIT_INV },
+ { ASMIT_INV },
+ { ASMIT_INV },
+ { ASMIT_CMP, ASMIM_ABSOLUTE_X },
+ { ASMIT_DEC, ASMIM_ABSOLUTE_X },
+ { ASMIT_INV },
+
+ { ASMIT_CPX, ASMIM_IMMEDIATE },
+ { ASMIT_SBC, ASMIM_INDIRECT_X },
+ { ASMIT_INV },
+ { ASMIT_INV },
+ { ASMIT_CPX, ASMIM_ZERO_PAGE },
+ { ASMIT_SBC, ASMIM_ZERO_PAGE },
+ { ASMIT_INC, ASMIM_ZERO_PAGE },
+ { ASMIT_INV },
+ { ASMIT_INX, ASMIM_IMPLIED },
+ { ASMIT_SBC, ASMIM_IMMEDIATE },
+ { ASMIT_NOP, ASMIM_IMPLIED },
+ { ASMIT_INV },
+ { ASMIT_CPX, ASMIM_ABSOLUTE },
+ { ASMIT_SBC, ASMIM_ABSOLUTE },
+ { ASMIT_INC, ASMIM_ABSOLUTE },
+ { ASMIT_INV },
+
+ { ASMIT_BEQ, ASMIM_RELATIVE },
+ { ASMIT_SBC, ASMIM_INDIRECT_Y },
+ { ASMIT_INV },
+ { ASMIT_INV },
+ { ASMIT_INV },
+ { ASMIT_SBC, ASMIM_ZERO_PAGE_X },
+ { ASMIT_INC, ASMIM_ZERO_PAGE_X },
+ { ASMIT_INV },
+ { ASMIT_SED, ASMIM_IMPLIED },
+ { ASMIT_SBC, ASMIM_ABSOLUTE_Y },
+ { ASMIT_INV },
+ { ASMIT_INV },
+ { ASMIT_INV },
+ { ASMIT_SBC, ASMIM_ABSOLUTE_X },
+ { ASMIT_INC, ASMIM_ABSOLUTE_X },
+ { ASMIT_INV },
+};
+
+short AsmInsOpcodes[NUM_ASM_INS_TYPES][NUM_ASM_INS_MODES];
+
+const char* AsmInstructionNames[NUM_ASM_INS_TYPES] = {
+ "ADC", "AND", "ASL", "BCC", "BCS", "BEQ", "BIT", "BMI", "BNE", "BPL", "BRK", "BVC", "BVS", "CLC",
+ "CLD", "CLI", "CLV", "CMP", "CPX", "CPY", "DEC", "DEX", "DEY", "EOR", "INC", "INX", "INY", "JMP",
+ "JSR", "LDA", "LDX", "LDY", "LSR", "NOP", "ORA", "PHA", "PHP", "PLA", "PLP", "ROL", "ROR", "RTI",
+ "RTS", "SBC", "SEC", "SED", "SEI", "STA", "STX", "STY", "TAX", "TAY", "TSX", "TXA", "TXS", "TYA",
+ "INV", "BYT"
+};
+
+int AsmInsModeSize[NUM_ASM_INS_MODES] = {
+ 1,
+ 2,
+ 2,
+ 2,
+ 2,
+ 3,
+ 3,
+ 3,
+ 3,
+ 2,
+ 2,
+ 2,
+};
+
+void InitAssembler(void)
+{
+ for (int i = 0; i < NUM_ASM_INS_TYPES; i++)
+ {
+ for (int j = 0; j < NUM_ASM_INS_MODES; j++)
+ {
+ AsmInsOpcodes[i][j] = -1;
+ }
+ }
+
+ for (int i = 0; i < 256; i++)
+ {
+ const AsmInsData& di(DecInsData[i]);
+ if (di.mType != ASMIT_INV)
+ {
+ assert(AsmInsOpcodes[di.mType][di.mMode] == -1);
+ AsmInsOpcodes[di.mType][di.mMode] = i;
+ }
+ }
+
+ AsmInsOpcodes[ASMIT_BYTE][ASMIM_ZERO_PAGE] = 0;
+}
+
+int AsmInsSize(AsmInsType type, AsmInsMode mode)
+{
+ if (type < ASMIT_INV)
+ return AsmInsModeSize[mode];
+ else
+ return 1;
+}
+
+static inline char toupper(char ch)
+{
+ if (ch >= 'a' && ch <= 'z')
+ return ch - 'a' + 'A';
+ else
+ return ch;
+}
+AsmInsType FindAsmInstruction(const char* ins)
+{
+ if (!ins[3])
+ {
+ for (int i = 0; i < NUM_ASM_INS_TYPES; i++)
+ {
+ if (AsmInstructionNames[i][0] == toupper(ins[0]) &&
+ AsmInstructionNames[i][1] == toupper(ins[1]) &&
+ AsmInstructionNames[i][2] == toupper(ins[2]))
+ return AsmInsType(i);
+ }
+ }
+
+ return ASMIT_INV;
+}
+
+bool HasAsmInstructionMode(AsmInsType type, AsmInsMode mode)
+{
+ return AsmInsOpcodes[type][mode] != -1;
+}
+
diff --git a/oscar64/Assembler.h b/oscar64/Assembler.h
new file mode 100644
index 0000000..d51d4bc
--- /dev/null
+++ b/oscar64/Assembler.h
@@ -0,0 +1,54 @@
+#pragma once
+
+#include "Ident.h"
+
+enum AsmInsType
+{
+ ASMIT_ADC, ASMIT_AND, ASMIT_ASL, ASMIT_BCC, ASMIT_BCS, ASMIT_BEQ, ASMIT_BIT, ASMIT_BMI, ASMIT_BNE, ASMIT_BPL, ASMIT_BRK, ASMIT_BVC, ASMIT_BVS, ASMIT_CLC,
+ ASMIT_CLD, ASMIT_CLI, ASMIT_CLV, ASMIT_CMP, ASMIT_CPX, ASMIT_CPY, ASMIT_DEC, ASMIT_DEX, ASMIT_DEY, ASMIT_EOR, ASMIT_INC, ASMIT_INX, ASMIT_INY, ASMIT_JMP,
+ ASMIT_JSR, ASMIT_LDA, ASMIT_LDX, ASMIT_LDY, ASMIT_LSR, ASMIT_NOP, ASMIT_ORA, ASMIT_PHA, ASMIT_PHP, ASMIT_PLA, ASMIT_PLP, ASMIT_ROL, ASMIT_ROR, ASMIT_RTI,
+ ASMIT_RTS, ASMIT_SBC, ASMIT_SEC, ASMIT_SED, ASMIT_SEI, ASMIT_STA, ASMIT_STX, ASMIT_STY, ASMIT_TAX, ASMIT_TAY, ASMIT_TSX, ASMIT_TXA, ASMIT_TXS, ASMIT_TYA,
+ ASMIT_INV, ASMIT_BYTE,
+
+ NUM_ASM_INS_TYPES
+};
+
+
+enum AsmInsMode
+{
+ ASMIM_IMPLIED,
+ ASMIM_IMMEDIATE,
+ ASMIM_ZERO_PAGE,
+ ASMIM_ZERO_PAGE_X,
+ ASMIM_ZERO_PAGE_Y,
+ ASMIM_ABSOLUTE,
+ ASMIM_ABSOLUTE_X,
+ ASMIM_ABSOLUTE_Y,
+ ASMIM_INDIRECT,
+ ASMIM_INDIRECT_X,
+ ASMIM_INDIRECT_Y,
+ ASMIM_RELATIVE,
+
+ NUM_ASM_INS_MODES
+};
+
+struct AsmInsData
+{
+ AsmInsType mType;
+ AsmInsMode mMode;
+};
+
+
+extern AsmInsData DecInsData[256];
+
+extern short AsmInsOpcodes[NUM_ASM_INS_TYPES][NUM_ASM_INS_MODES];
+
+extern const char* AsmInstructionNames[NUM_ASM_INS_TYPES];
+
+AsmInsType FindAsmInstruction(const char * ins);
+
+bool HasAsmInstructionMode(AsmInsType type, AsmInsMode mode);
+
+int AsmInsSize(AsmInsType type, AsmInsMode mode);
+
+void InitAssembler(void);
diff --git a/oscar64/BitVector.h b/oscar64/BitVector.h
new file mode 100644
index 0000000..8e0bd13
--- /dev/null
+++ b/oscar64/BitVector.h
@@ -0,0 +1,334 @@
+#pragma once
+
+#include
+#include
+#include
+
+class BitVector
+{
+protected:
+ unsigned* bits;
+ unsigned mask;
+ int size, dwsize;
+public:
+ BitVector(void);
+ BitVector(const BitVector& v);
+ BitVector(int size, bool set = false);
+ BitVector(int size, unsigned char * data);
+ BitVector& operator=(const BitVector& v);
+
+ ~BitVector(void);
+
+ BitVector operator+(const BitVector v) const;
+ BitVector operator*(const int n) const;
+ BitVector operator|(const BitVector v) const;
+ BitVector operator&(const BitVector v) const;
+ BitVector operator~(void) const;
+
+ void Set(int n, bool b);
+ bool Get(int n) const;
+ int Size(void) const;
+ int DWSize(void) const;
+
+ void Copy(unsigned* bits) const;
+};
+
+inline BitVector::BitVector(void)
+{
+ size = 0;
+ dwsize = 0;
+ bits = nullptr;
+ mask = 0;
+}
+
+inline BitVector::BitVector(const BitVector& v)
+{
+ int i;
+
+ size = v.size;
+ dwsize = v.dwsize;
+ mask = v.mask;
+
+ if (dwsize)
+ bits = new unsigned[dwsize];
+ else
+ bits = nullptr;
+
+ for (i = 0; i < dwsize; i++) bits[i] = v.bits[i];
+}
+
+inline BitVector::BitVector(int size, unsigned char * data)
+{
+ this->size = size;
+ dwsize = ((size + 31) >> 5);
+ if ((size & 31) == 0)
+ mask = 0xffffffff;
+ else
+ mask = (1 << (size & 31)) - 1;
+
+ if (dwsize)
+ bits = new unsigned[dwsize];
+ else
+ bits = nullptr;
+
+ if (size)
+ {
+ memcpy(bits, data, (size + 7) / 8);
+ }
+}
+
+inline BitVector::BitVector(int size, bool set)
+{
+ int i;
+
+ this->size = size;
+ dwsize = ((size + 31) >> 5);
+ if ((size & 31) == 0)
+ mask = 0xffffffff;
+ else
+ mask = (1 << (size & 31)) - 1;
+
+ if (dwsize)
+ bits = new unsigned[dwsize];
+ else
+ bits = NULL;
+
+ if (size)
+ {
+ if (set)
+ {
+ for (i = 0; i < dwsize - 1; i++) bits[i] = ~0;
+ bits[dwsize - 1] = mask;
+ }
+ else
+ for (i = 0; i < dwsize; i++) bits[i] = 0;
+ }
+}
+
+inline BitVector& BitVector::operator=(const BitVector& v)
+{
+ int i;
+
+ delete[] bits;
+
+ size = v.size;
+ dwsize = v.dwsize;
+ mask = v.mask;
+
+ if (dwsize)
+ bits = new unsigned[dwsize];
+ else
+ bits = NULL;
+
+ for (i = 0; i < dwsize; i++) bits[i] = v.bits[i];
+
+ return *this;
+}
+
+
+inline BitVector::~BitVector(void)
+{
+ delete[] bits;
+}
+
+inline BitVector BitVector::operator+(const BitVector v) const
+{
+ int i;
+ int s;
+ unsigned merge;
+
+ BitVector vv(size + v.size);
+
+ if (dwsize == 0)
+ {
+ for (i = 0; i < v.dwsize; i++)
+ vv.bits[i] = v.bits[i];
+ }
+ else if (v.dwsize == 0)
+ {
+ for (i = 0; i < dwsize; i++)
+ vv.bits[i] = bits[i];
+ }
+ else
+ {
+ s = size & 31;
+
+ if (s == 0)
+ {
+ for (i = 0; i < dwsize; i++)
+ vv.bits[i] = bits[i];
+ for (i = 0; i < v.dwsize; i++)
+ vv.bits[i + dwsize] = v.bits[i];
+ }
+ else
+ {
+ for (i = 0; i < dwsize - 1; i++)
+ vv.bits[i] = bits[i];
+
+ merge = bits[dwsize - 1] & mask;
+
+ for (i = 0; i < v.dwsize; i++)
+ {
+ vv.bits[i + dwsize - 1] = merge | (v.bits[i] << s);
+ merge = v.bits[i] >> (32 - s);
+ }
+
+ if (dwsize - 1 + v.dwsize < vv.dwsize)
+ vv.bits[dwsize - 1 + v.dwsize] = merge;
+ }
+ }
+
+ return vv;
+}
+
+inline BitVector BitVector::operator*(const int n) const
+{
+ int i, j;
+ int s, dw;
+ unsigned merge;
+
+ BitVector vv(size * n);
+
+ if (n > 0)
+ {
+ dw = 0;
+
+ for (i = 0; i < dwsize - 1; i++)
+ vv.bits[dw++] = bits[i];
+
+ merge = bits[dwsize - 1] & mask;
+
+ for (j = 1; j < n; j++)
+ {
+ s = (size * j) & 31;
+
+ if (s == 0)
+ {
+ vv.bits[dw++] = merge;
+ for (i = 0; i < dwsize - 1; i++)
+ vv.bits[dw++] = bits[i];
+
+ merge = bits[dwsize - 1] & mask;
+ }
+ else
+ {
+ for (i = 0; i < dwsize - 1; i++)
+ {
+ vv.bits[dw++] = merge | (bits[i] << s);
+ merge = bits[i] >> (32 - s);
+ }
+ if (mask >> (32 - s))
+ {
+ vv.bits[dw++] = merge | (bits[i] << s);
+ merge = (bits[i] & mask) >> (32 - s);
+ }
+ else
+ {
+ merge |= (bits[i] & mask) << s;
+ }
+ }
+ }
+
+ if (dw < vv.dwsize)
+ vv.bits[dw++] = merge;
+
+ if (dw > vv.dwsize)
+ __asm int 3
+ }
+
+ return vv;
+}
+
+inline BitVector BitVector::operator|(const BitVector v) const
+{
+ int i;
+
+ if (dwsize < v.dwsize)
+ {
+ BitVector vv(v.size);
+
+ for (i = 0; i < dwsize; i++) vv.bits[i] = bits[i] | v.bits[i];
+ for (i = dwsize; i < v.dwsize; i++) vv.bits[i] = v.bits[i];
+
+ return vv;
+ }
+ else
+ {
+ BitVector vv(size);
+
+ for (i = 0; i < v.dwsize; i++) vv.bits[i] = bits[i] | v.bits[i];
+ for (i = v.dwsize; i < dwsize; i++) vv.bits[i] = bits[i];
+
+ return vv;
+ }
+}
+
+inline BitVector BitVector::operator&(const BitVector v) const
+{
+ int i;
+
+ if (dwsize < v.dwsize)
+ {
+ BitVector vv(v.size);
+
+ for (i = 0; i < dwsize; i++) vv.bits[i] = bits[i] & v.bits[i];
+
+ return vv;
+ }
+ else
+ {
+ BitVector vv(size);
+
+ for (i = 0; i < v.dwsize; i++) vv.bits[i] = bits[i] & v.bits[i];
+
+ return vv;
+ }
+}
+
+inline BitVector BitVector::operator~(void) const
+{
+ int i;
+
+ BitVector vv(size);
+
+ for (i = 0; i < dwsize - 1; i++) vv.bits[i] = ~bits[i];
+ vv.bits[dwsize - 1] = ~bits[dwsize - 1] & mask;
+
+ return vv;
+}
+
+inline void BitVector::Set(int n, bool b)
+{
+ if (b)
+ bits[n >> 5] |= (1 << (n & 31));
+ else
+ bits[n >> 5] &= ~(1 << (n & 31));
+}
+
+inline bool BitVector::Get(int n) const
+{
+ return (bits[n >> 5] & (1 << (n & 31))) != 0;
+}
+
+inline int BitVector::Size(void) const
+{
+ return size;
+}
+
+inline int BitVector::DWSize(void) const
+{
+ return dwsize;
+}
+
+inline void BitVector::Copy(unsigned* bits) const
+{
+ int i;
+
+ if (dwsize > 0 && (size & 31))
+ this->bits[dwsize - 1] &= (1 << (size & 31)) - 1;
+
+ for (i = 0; i < dwsize; i++)
+ {
+ bits[i] = this->bits[i];
+ }
+}
diff --git a/oscar64/ByteCodeGenerator.cpp b/oscar64/ByteCodeGenerator.cpp
new file mode 100644
index 0000000..0b55a90
--- /dev/null
+++ b/oscar64/ByteCodeGenerator.cpp
@@ -0,0 +1,3569 @@
+#include "ByteCodeGenerator.h"
+#include "Assembler.h"
+
+static ByteCode InvertBranchCondition(ByteCode code)
+{
+ switch (code)
+ {
+ case BC_BRANCHS_EQ: return BC_BRANCHS_NE;
+ case BC_BRANCHS_NE: return BC_BRANCHS_EQ;
+ case BC_BRANCHS_GT: return BC_BRANCHS_LE;
+ case BC_BRANCHS_GE: return BC_BRANCHS_LT;
+ case BC_BRANCHS_LT: return BC_BRANCHS_GE;
+ case BC_BRANCHS_LE: return BC_BRANCHS_GT;
+ default:
+ return code;
+ }
+}
+
+static ByteCode TransposeBranchCondition(ByteCode code)
+{
+ switch (code)
+ {
+ case BC_BRANCHS_EQ: return BC_BRANCHS_EQ;
+ case BC_BRANCHS_NE: return BC_BRANCHS_NE;
+ case BC_BRANCHS_GT: return BC_BRANCHS_LT;
+ case BC_BRANCHS_GE: return BC_BRANCHS_LE;
+ case BC_BRANCHS_LT: return BC_BRANCHS_GT;
+ case BC_BRANCHS_LE: return BC_BRANCHS_GE;
+ default:
+ return code;
+ }
+}
+
+ByteCodeInstruction::ByteCodeInstruction(ByteCode code)
+ : mCode(code), mRelocate(false), mFunction(false), mRegisterFinal(false), mVIndex(-1), mValue(0), mRegister(0)
+{
+}
+
+bool ByteCodeInstruction::IsStore(void) const
+{
+ return
+ mCode == BC_STORE_ABS_8 ||
+ mCode == BC_STORE_ABS_16 ||
+ mCode == BC_STORE_ABS_32 ||
+ mCode == BC_STORE_LOCAL_8 ||
+ mCode == BC_STORE_LOCAL_16 ||
+ mCode == BC_STORE_LOCAL_32 ||
+ mCode == BC_STORE_FRAME_8 ||
+ mCode == BC_STORE_FRAME_16 ||
+ mCode == BC_STORE_FRAME_32 ||
+ mCode == BC_STORE_ADDR_8 ||
+ mCode == BC_STORE_ADDR_16 ||
+ mCode == BC_STORE_ADDR_32;
+}
+
+bool ByteCodeInstruction::ChangesAccu(void) const
+{
+ if (mCode == BC_LOAD_REG_16 || mCode == BC_LOAD_REG_32)
+ return true;
+ if (mCode >= BC_BINOP_ADDR_16 && mCode <= BC_BINOP_SHRR_I16)
+ return true;
+ if (mCode >= BC_BINOP_CMPUR_16 && mCode <= BC_BINOP_CMPSI_16)
+ return true;
+ if (mCode >= BC_OP_NEGATE_16 && mCode <= BC_OP_INVERT_16)
+ return true;
+ if (mCode >= BC_BINOP_ADD_F32 && mCode <= BC_OP_CEIL_F32)
+ return true;
+ if (mCode >= BC_CONV_U16_F32 && mCode <= BC_CONV_F32_I16)
+ return true;
+ if (mCode >= BC_BINOP_SHLI_16 && mCode <= BC_BINOP_SHRI_U16)
+ return true;
+ if (mCode >= BC_SET_EQ && mCode <= BC_SET_LE)
+ return true;
+ if (mCode == BC_JSR || mCode == BC_CALL)
+ return true;
+
+ return ChangesRegister(BC_REG_ACCU);
+
+}
+
+bool ByteCodeInstruction::ChangesAddr(void) const
+{
+ if (mCode == BC_ADDR_REG)
+ return true;
+ if (mCode >= BC_LOAD_ABS_U8 && mCode <= BC_STORE_ABS_32)
+ return true;
+ if (mCode == BC_JSR || mCode == BC_CALL)
+ return true;
+
+ return ChangesRegister(BC_REG_ADDR);
+}
+
+bool ByteCodeInstruction::LoadsRegister(uint32 reg) const
+{
+ if (mRegister == reg)
+ {
+ if (mCode >= BC_LOAD_ABS_U8 && mCode <= BC_LOAD_ABS_32)
+ return true;
+ if (mCode >= BC_LOAD_LOCAL_U8 && mCode <= BC_LOAD_LOCAL_32)
+ return true;
+ if (mCode >= BC_LOAD_ADDR_U8 && mCode <= BC_LOAD_ADDR_32)
+ return true;
+ if (mCode >= BC_CONST_P8 && mCode <= BC_CONST_32)
+ return true;
+ if (mCode == BC_LEA_ABS || mCode == BC_LEA_LOCAL)
+ return true;
+ }
+
+ return false;
+}
+
+bool ByteCodeInstruction::IsCommutative(void) const
+{
+ if (mCode == BC_BINOP_ADDR_16 || mCode == BC_BINOP_ANDR_16 || mCode == BC_BINOP_ORR_16 || mCode == BC_BINOP_XORR_16 || mCode == BC_BINOP_MULR_16)
+ return true;
+
+ if (mCode == BC_BINOP_ADD_F32 || mCode == BC_BINOP_MUL_F32)
+ return true;
+
+ return false;
+}
+
+bool ByteCodeInstruction::StoresRegister(uint32 reg) const
+{
+ if (mRegister == reg)
+ {
+ if (mCode >= BC_STORE_ABS_8 && mCode <= BC_STORE_ABS_32)
+ return true;
+ if (mCode >= BC_STORE_LOCAL_8 && mCode <= BC_STORE_LOCAL_32)
+ return true;
+ if (mCode >= BC_STORE_FRAME_8 && mCode <= BC_STORE_FRAME_32)
+ return true;
+ if (mCode >= BC_STORE_ADDR_8 && mCode <= BC_STORE_ADDR_32)
+ return true;
+ }
+
+ return false;
+
+}
+
+bool ByteCodeInstruction::ChangesRegister(uint32 reg) const
+{
+ if (mRegister == reg)
+ {
+ if (mCode == BC_STORE_REG_16 || mCode == BC_STORE_REG_32)
+ return true;
+ if (mCode >= BC_LOAD_ABS_U8 && mCode <= BC_LOAD_ABS_32)
+ return true;
+ if (mCode >= BC_LOAD_LOCAL_U8 && mCode <= BC_LOAD_LOCAL_32)
+ return true;
+ if (mCode >= BC_LOAD_ADDR_U8 && mCode <= BC_LOAD_ADDR_32)
+ return true;
+ if (mCode >= BC_CONST_P8 && mCode <= BC_CONST_32)
+ return true;
+ if (mCode == BC_LEA_ABS || mCode == BC_LEA_LOCAL)
+ return true;
+ if (mCode >= BC_BINOP_ADDI_16 && mCode <= BC_BINOP_MULI8_16)
+ return true;
+ if (mCode == BC_CALL)
+ return true;
+ }
+
+ return false;
+}
+
+void ByteCodeInstruction::Assemble(ByteCodeGenerator* generator, ByteCodeBasicBlock* block)
+{
+ switch (mCode)
+ {
+ case BC_NOP:
+ break;
+ case BC_EXIT:
+ block->PutCode(generator, mCode);
+ break;
+
+ case BC_CONST_P8:
+ case BC_CONST_N8:
+ case BC_CONST_16:
+ if (mRelocate)
+ {
+ block->PutCode(generator, mCode);
+ block->PutByte(mRegister);
+ ByteCodeRelocation rl;
+ rl.mAddr = block->code.Size();
+ rl.mFunction = mFunction;
+ rl.mLower = true;
+ rl.mUpper = true;
+ rl.mIndex = mVIndex;
+ rl.mOffset = mValue;
+ block->mRelocations.Push(rl);
+ block->PutWord(0);
+ }
+ else if (mValue >= 0 && mValue < 255)
+ {
+ block->PutCode(generator, BC_CONST_P8); block->PutByte(mRegister); block->PutByte(uint8(mValue));
+ }
+ else if (mValue < 0 && mValue >= -256)
+ {
+ block->PutCode(generator, BC_CONST_N8); block->PutByte(mRegister); block->PutByte(uint8(mValue));
+ }
+ else
+ {
+ block->PutCode(generator, BC_CONST_16); block->PutByte(mRegister); block->PutWord(uint16(mValue));
+ }
+ break;
+ case BC_CONST_32:
+ block->PutCode(generator, BC_CONST_32); block->PutByte(mRegister); block->PutDWord(uint32(mValue));
+ break;
+
+
+ case BC_LOAD_REG_16:
+ case BC_STORE_REG_16:
+ case BC_LOAD_REG_32:
+ case BC_STORE_REG_32:
+ case BC_ADDR_REG:
+ block->PutCode(generator, mCode); block->PutByte(mRegister);
+ break;
+
+ case BC_LOAD_ABS_U8:
+ case BC_LOAD_ABS_I8:
+ case BC_LOAD_ABS_16:
+ case BC_LOAD_ABS_32:
+ case BC_STORE_ABS_8:
+ case BC_STORE_ABS_16:
+ case BC_STORE_ABS_32:
+ block->PutCode(generator, mCode);
+ if (mRelocate)
+ {
+ ByteCodeRelocation rl;
+ rl.mAddr = block->code.Size();
+ rl.mFunction = mFunction;
+ rl.mLower = true;
+ rl.mUpper = true;
+ rl.mIndex = mVIndex;
+ rl.mOffset = mValue;
+ block->mRelocations.Push(rl);
+ block->PutWord(0);
+ }
+ else
+ block->PutWord(mValue);
+
+ block->PutByte(mRegister);
+ break;
+
+ case BC_LEA_ABS:
+ block->PutCode(generator, mCode); block->PutByte(mRegister);
+ if (mRelocate)
+ {
+ ByteCodeRelocation rl;
+ rl.mAddr = block->code.Size();
+ rl.mFunction = mFunction;
+ rl.mLower = true;
+ rl.mUpper = true;
+ rl.mIndex = mVIndex;
+ rl.mOffset = mValue;
+ block->mRelocations.Push(rl);
+ block->PutWord(0);
+ }
+ else
+ block->PutWord(uint16(mValue));
+ break;
+
+ case BC_LOAD_LOCAL_U8:
+ case BC_LOAD_LOCAL_I8:
+ case BC_LOAD_LOCAL_16:
+ case BC_LOAD_LOCAL_32:
+ case BC_STORE_LOCAL_8:
+ case BC_STORE_LOCAL_16:
+ case BC_STORE_LOCAL_32:
+ case BC_STORE_FRAME_8:
+ case BC_STORE_FRAME_16:
+ case BC_STORE_FRAME_32:
+ block->PutCode(generator, mCode);
+ block->PutByte(mRegister);
+ block->PutByte(uint8(mValue));
+ break;
+
+ case BC_LEA_LOCAL:
+ block->PutCode(generator, mCode);
+ block->PutByte(mRegister);
+ block->PutWord(uint16(mValue));
+ break;
+
+ case BC_BINOP_ADDR_16:
+ case BC_BINOP_SUBR_16:
+ case BC_BINOP_ANDR_16:
+ case BC_BINOP_ORR_16:
+ case BC_BINOP_XORR_16:
+ case BC_BINOP_MULR_16:
+ case BC_BINOP_DIVR_U16:
+ case BC_BINOP_MODR_U16:
+ case BC_BINOP_DIVR_I16:
+ case BC_BINOP_MODR_I16:
+ case BC_BINOP_SHLR_16:
+ case BC_BINOP_SHRR_U16:
+ case BC_BINOP_SHRR_I16:
+ block->PutCode(generator, mCode);
+ block->PutByte(mRegister);
+ break;
+
+ case BC_BINOP_ADDI_16:
+ case BC_BINOP_SUBI_16:
+ case BC_BINOP_ANDI_16:
+ case BC_BINOP_ORI_16:
+ block->PutCode(generator, mCode);
+ block->PutByte(mRegister);
+ block->PutWord(uint16(mValue));
+ break;
+ case BC_BINOP_MULI8_16:
+ block->PutCode(generator, mCode);
+ block->PutByte(mRegister);
+ block->PutByte(mValue);
+ break;
+ case BC_BINOP_SHLI_16:
+ case BC_BINOP_SHRI_U16:
+ case BC_BINOP_SHRI_I16:
+ block->PutCode(generator, mCode);
+ block->PutByte(uint8(mValue));
+ break;
+
+ case BC_BINOP_CMPUR_16:
+ case BC_BINOP_CMPSR_16:
+ block->PutCode(generator, mCode);
+ block->PutByte(mRegister);
+ break;
+
+ case BC_BINOP_CMPUI_16:
+ case BC_BINOP_CMPSI_16:
+ block->PutCode(generator, mCode);
+ block->PutWord(uint16(mValue));
+ break;
+
+ case BC_OP_NEGATE_16:
+ case BC_OP_INVERT_16:
+ block->PutCode(generator, mCode);
+ break;
+
+ case BC_BINOP_ADD_F32:
+ case BC_BINOP_SUB_F32:
+ case BC_BINOP_MUL_F32:
+ case BC_BINOP_DIV_F32:
+ case BC_BINOP_CMP_F32:
+ block->PutCode(generator, mCode);
+ block->PutByte(mRegister);
+ break;
+
+ case BC_OP_NEGATE_F32:
+ case BC_OP_ABS_F32:
+ case BC_OP_FLOOR_F32:
+ case BC_OP_CEIL_F32:
+ case BC_CONV_U16_F32:
+ case BC_CONV_I16_F32:
+ case BC_CONV_F32_U16:
+ case BC_CONV_F32_I16:
+ block->PutCode(generator, mCode);
+ break;
+
+ case BC_JUMPS:
+ case BC_BRANCHS_EQ:
+ case BC_BRANCHS_NE:
+ case BC_BRANCHS_GT:
+ case BC_BRANCHS_GE:
+ case BC_BRANCHS_LT:
+ case BC_BRANCHS_LE:
+ assert(false);
+ break;
+
+ case BC_JUMPF:
+ case BC_BRANCHF_EQ:
+ case BC_BRANCHF_NE:
+ case BC_BRANCHF_GT:
+ case BC_BRANCHF_GE:
+ case BC_BRANCHF_LT:
+ case BC_BRANCHF_LE:
+ assert(false);
+ break;
+
+ case BC_SET_EQ:
+ case BC_SET_NE:
+ case BC_SET_GT:
+ case BC_SET_GE:
+ case BC_SET_LT:
+ case BC_SET_LE:
+ block->PutCode(generator, mCode);
+ break;
+
+ case BC_ENTER:
+ case BC_RETURN:
+ assert(false);
+ break;
+
+ case BC_CALL:
+ block->PutCode(generator, mCode);
+ break;
+
+ case BC_PUSH_FRAME:
+ case BC_POP_FRAME:
+ block->PutCode(generator, mCode);
+ block->PutWord(uint16(mValue + 2));
+ break;
+
+ case BC_JSR:
+ {
+ block->PutCode(generator, mCode);
+
+ ByteCodeRelocation rl;
+ rl.mAddr = block->code.Size();
+ rl.mFunction = false;
+ rl.mLower = true;
+ rl.mUpper = true;
+ rl.mIndex = mVIndex;
+ rl.mOffset = 0;
+ block->mRelocations.Push(rl);
+
+ block->PutWord(0);
+ } break;
+
+ case BC_LOAD_ADDR_U8:
+ case BC_LOAD_ADDR_I8:
+ case BC_LOAD_ADDR_16:
+ case BC_LOAD_ADDR_32:
+ case BC_STORE_ADDR_8:
+ case BC_STORE_ADDR_16:
+ case BC_STORE_ADDR_32:
+ block->PutCode(generator, mCode);
+ block->PutByte(mRegister);
+ break;
+
+ case BC_COPY:
+ case BC_COPY_LONG:
+ if (mValue < 256)
+ {
+ block->PutCode(generator, BC_COPY);
+ block->PutByte(uint8(mValue));
+ }
+ else
+ {
+ block->PutCode(generator, BC_COPY_LONG);
+ block->PutByte(uint8(mValue));
+ }
+ break;
+
+ default:
+ assert(false);
+ }
+}
+
+
+void ByteCodeBasicBlock::PutByte(uint8 code)
+{
+ this->code.Insert(code);
+}
+
+void ByteCodeBasicBlock::PutWord(uint16 code)
+{
+ this->code.Insert((uint8)(code & 0xff));
+ this->code.Insert((uint8)(code >> 8));
+}
+
+void ByteCodeBasicBlock::PutDWord(uint32 code)
+{
+ this->code.Insert((uint8)(code & 0xff));
+ this->code.Insert((uint8)((code >> 8) & 0xff));
+ this->code.Insert((uint8)((code >> 16) & 0xff));
+ this->code.Insert((uint8)((code >> 24) & 0xff));
+}
+
+void ByteCodeBasicBlock::PutBytes(const uint8* code, int num)
+{
+ while (num--)
+ {
+ this->code.Insert(*code++);
+ }
+}
+
+void ByteCodeBasicBlock::PutCode(ByteCodeGenerator* generator, ByteCode code)
+{
+ PutByte(uint8(code) * 2);
+ generator->mByteCodeUsed[code] = true;
+}
+
+int ByteCodeBasicBlock::PutBranch(ByteCodeGenerator* generator, ByteCode code, int offset)
+{
+ if (offset >= -126 && offset <= 129)
+ {
+ PutCode(generator, code);
+ PutByte(offset - 2);
+ return 2;
+ }
+ else
+ {
+ PutCode(generator, ByteCode(code + (BC_JUMPF - BC_JUMPS)));
+ PutWord(offset - 3);
+ return 3;
+ }
+}
+
+ByteCodeBasicBlock::ByteCodeBasicBlock(void)
+ : mRelocations({ 0 }), mIns(ByteCodeInstruction(BC_NOP))
+{
+ trueJump = falseJump = NULL;
+ trueLink = falseLink = NULL;
+ mOffset = 0x7fffffff;
+ copied = false;
+ knownShortBranch = false;
+ killed = false;
+ bypassed = false;
+}
+
+void ByteCodeBasicBlock::IntConstToAccu(__int64 val)
+{
+ ByteCodeInstruction ins(BC_CONST_16);
+ ins.mRegister = BC_REG_ACCU;
+ ins.mValue = int(val);
+ mIns.Push(ins);
+}
+
+void ByteCodeBasicBlock::FloatConstToAccu(double val)
+{
+ union { float f; int v; } cc;
+ cc.f = val;
+ ByteCodeInstruction bins(BC_CONST_32);
+ bins.mRegister = BC_REG_ACCU;
+ bins.mValue = cc.v;
+ mIns.Push(bins);
+}
+
+
+void ByteCodeBasicBlock::IntConstToAddr(__int64 val)
+{
+ ByteCodeInstruction ins(BC_CONST_16);
+ ins.mRegister = BC_REG_ADDR;
+ ins.mValue = int(val);
+ mIns.Push(ins);
+}
+
+void ByteCodeBasicBlock::LoadConstant(InterCodeProcedure* proc, const InterInstruction& ins)
+{
+ if (ins.ttype == IT_FLOAT)
+ {
+ union { float f; int v; } cc;
+ cc.f = ins.fvalue;
+ ByteCodeInstruction bins(BC_CONST_32);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ bins.mValue = cc.v;
+ mIns.Push(bins);
+ }
+ else if (ins.ttype == IT_POINTER)
+ {
+ if (ins.mem == IM_GLOBAL)
+ {
+ ByteCodeInstruction bins(BC_LEA_ABS);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ bins.mVIndex = ins.vindex;
+ bins.mValue = ins.ivalue;
+ bins.mRelocate = true;
+ bins.mFunction = false;
+ mIns.Push(bins);
+ }
+ else if (ins.mem == IM_ABSOLUTE)
+ {
+ ByteCodeInstruction bins(BC_LEA_ABS);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ bins.mValue = ins.ivalue;
+ mIns.Push(bins);
+ }
+ else if (ins.mem == IM_LOCAL)
+ {
+ ByteCodeInstruction bins(BC_LEA_LOCAL);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ bins.mValue = ins.ivalue + proc->mLocalVars[ins.vindex].mOffset;
+ mIns.Push(bins);
+ }
+ else if (ins.mem == IM_PARAM)
+ {
+ ByteCodeInstruction bins(BC_LEA_LOCAL);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ bins.mValue = ins.ivalue + ins.vindex + proc->mLocalSize + 2;
+ mIns.Push(bins);
+ }
+ else if (ins.mem == IM_PROCEDURE)
+ {
+ ByteCodeInstruction bins(BC_CONST_16);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ bins.mVIndex = ins.vindex;
+ bins.mValue = 0;
+ bins.mRelocate = true;
+ bins.mFunction = true;
+ mIns.Push(bins);
+ }
+ }
+ else
+ {
+ ByteCodeInstruction bins(BC_CONST_16);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ bins.mValue = ins.ivalue;
+ mIns.Push(bins);
+ }
+
+}
+
+void ByteCodeBasicBlock::CopyValue(InterCodeProcedure* proc, const InterInstruction& ins)
+{
+ ByteCodeInstruction sins(BC_ADDR_REG);
+ sins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[1]];
+ sins.mRegisterFinal = ins.sfinal[1];
+ mIns.Push(sins);
+ ByteCodeInstruction dins(BC_LOAD_REG_16);
+ dins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ dins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(dins);
+ ByteCodeInstruction cins(BC_COPY);
+ cins.mValue = ins.opsize;
+ mIns.Push(cins);
+}
+
+void ByteCodeBasicBlock::StoreDirectValue(InterCodeProcedure* proc, const InterInstruction& ins)
+{
+ if (ins.stype[0] == IT_FLOAT)
+ {
+ if (ins.stemp[1] < 0)
+ {
+ if (ins.stemp[0] < 0)
+ {
+ FloatConstToAccu(ins.sfconst[0]);
+
+ if (ins.mem == IM_GLOBAL)
+ {
+ ByteCodeInstruction bins(BC_STORE_ABS_32);
+ bins.mRelocate = true;
+ bins.mVIndex = ins.vindex;
+ bins.mValue = ins.siconst[1];
+ bins.mRegister = BC_REG_ACCU;
+ mIns.Push(bins);
+ }
+ else if (ins.mem == IM_ABSOLUTE)
+ {
+ ByteCodeInstruction bins(BC_STORE_ABS_32);
+ bins.mValue = ins.siconst[1];
+ bins.mRegister = BC_REG_ACCU;
+ mIns.Push(bins);
+ }
+ else if (ins.mem == IM_LOCAL || ins.mem == IM_PARAM)
+ {
+ int index = ins.siconst[1];
+ if (ins.mem == IM_LOCAL)
+ index += proc->mLocalVars[ins.vindex].mOffset;
+ else
+ index += ins.vindex + proc->mLocalSize + 2;
+
+ if (index <= 252)
+ {
+ ByteCodeInstruction bins(BC_STORE_LOCAL_32);
+ bins.mRegister = BC_REG_ACCU;
+ bins.mValue = index;
+ mIns.Push(bins);
+ }
+ else
+ {
+ ByteCodeInstruction lins(BC_LEA_LOCAL);
+ lins.mRegister = BC_REG_ADDR;
+ lins.mValue = index;
+ mIns.Push(lins);
+ ByteCodeInstruction bins(BC_STORE_ADDR_32);
+ bins.mRegister = BC_REG_ACCU;
+ mIns.Push(bins);
+ }
+ }
+ else if (ins.mem == IM_FRAME)
+ {
+ ByteCodeInstruction bins(BC_STORE_FRAME_32);
+ bins.mRegister = BC_REG_ACCU;
+ bins.mValue = ins.vindex + ins.siconst[1] + 2;
+ mIns.Push(bins);
+ }
+ }
+ else
+ {
+ if (ins.mem == IM_GLOBAL)
+ {
+ ByteCodeInstruction bins(BC_STORE_ABS_32);
+ bins.mRelocate = true;
+ bins.mVIndex = ins.vindex;
+ bins.mValue = ins.siconst[1];
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ mIns.Push(bins);
+ }
+ else if (ins.mem == IM_ABSOLUTE)
+ {
+ ByteCodeInstruction bins(BC_STORE_ABS_32);
+ bins.mValue = ins.siconst[1];
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ mIns.Push(bins);
+ }
+ else if (ins.mem == IM_LOCAL || ins.mem == IM_PARAM)
+ {
+ int index = ins.siconst[1];
+ if (ins.mem == IM_LOCAL)
+ index += proc->mLocalVars[ins.vindex].mOffset;
+ else
+ index += ins.vindex + proc->mLocalSize + 2;
+
+ if (index <= 252)
+ {
+ ByteCodeInstruction bins(BC_STORE_LOCAL_32);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ bins.mValue = index;
+ mIns.Push(bins);
+ }
+ else
+ {
+ ByteCodeInstruction lins(BC_LEA_LOCAL);
+ lins.mRegister = BC_REG_ADDR;
+ lins.mValue = index;
+ mIns.Push(lins);
+ ByteCodeInstruction bins(BC_STORE_ADDR_32);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(bins);
+ }
+ }
+ else if (ins.mem == IM_FRAME)
+ {
+ ByteCodeInstruction bins(BC_STORE_FRAME_32);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ bins.mValue = ins.vindex + ins.siconst[1] + 2;
+ mIns.Push(bins);
+ }
+ }
+ }
+ else
+ {
+ if (ins.stemp[0] < 0)
+ {
+ IntConstToAccu(ins.siconst[0]);
+
+ if (ins.mem == IM_INDIRECT)
+ {
+ ByteCodeInstruction lins(BC_ADDR_REG);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[1]];
+ lins.mRegisterFinal = ins.sfinal[1];
+ mIns.Push(lins);
+ ByteCodeInstruction bins(BC_STORE_ADDR_32);
+ bins.mRegister = BC_REG_ACCU;
+ mIns.Push(bins);
+ }
+ }
+ else
+ {
+ if (ins.mem == IM_INDIRECT)
+ {
+ ByteCodeInstruction lins(BC_ADDR_REG);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[1]];
+ lins.mRegisterFinal = ins.sfinal[1];
+ mIns.Push(lins);
+ ByteCodeInstruction bins(BC_STORE_ADDR_32);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(bins);
+ }
+ }
+ }
+ }
+ else if (ins.stype[0] == IT_POINTER)
+ {
+ if (ins.stemp[1] < 0)
+ {
+ if (ins.stemp[0] < 0)
+ {
+ IntConstToAccu(ins.siconst[0]);
+
+ if (ins.mem == IM_GLOBAL)
+ {
+ ByteCodeInstruction bins(BC_STORE_ABS_16);
+ bins.mRelocate = true;
+ bins.mVIndex = ins.vindex;
+ bins.mValue = ins.siconst[1];
+ bins.mRegister = BC_REG_ACCU;
+ mIns.Push(bins);
+ }
+ else if (ins.mem == IM_ABSOLUTE)
+ {
+ ByteCodeInstruction bins(BC_STORE_ABS_16);
+ bins.mValue = ins.siconst[1];
+ bins.mRegister = BC_REG_ACCU;
+ mIns.Push(bins);
+ }
+ else if (ins.mem == IM_LOCAL || ins.mem == IM_PARAM)
+ {
+ int index = ins.siconst[1];
+ if (ins.mem == IM_LOCAL)
+ index += proc->mLocalVars[ins.vindex].mOffset;
+ else
+ index += ins.vindex + proc->mLocalSize + 2;
+
+ if (index <= 254)
+ {
+ ByteCodeInstruction bins(BC_STORE_LOCAL_16);
+ bins.mRegister = BC_REG_ACCU;
+ bins.mValue = index;
+ mIns.Push(bins);
+ }
+ else
+ {
+ ByteCodeInstruction lins(BC_LEA_LOCAL);
+ lins.mRegister = BC_REG_ADDR;
+ lins.mValue = index;
+ mIns.Push(lins);
+ ByteCodeInstruction bins(BC_STORE_ADDR_16);
+ bins.mRegister = BC_REG_ACCU;
+ mIns.Push(bins);
+ }
+ }
+ else if (ins.mem == IM_FRAME)
+ {
+ ByteCodeInstruction bins(BC_STORE_FRAME_16);
+ bins.mRegister = BC_REG_ACCU;
+ bins.mValue = ins.vindex + ins.siconst[1] + 2;
+ mIns.Push(bins);
+ }
+ }
+ else
+ {
+ if (ins.mem == IM_GLOBAL)
+ {
+ ByteCodeInstruction bins(BC_STORE_ABS_16);
+ bins.mRelocate = true;
+ bins.mVIndex = ins.vindex;
+ bins.mValue = ins.siconst[1];
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ mIns.Push(bins);
+ }
+ else if (ins.mem == IM_ABSOLUTE)
+ {
+ ByteCodeInstruction bins(BC_STORE_ABS_16);
+ bins.mValue = ins.siconst[1];
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(bins);
+ }
+ else if (ins.mem == IM_LOCAL || ins.mem == IM_PARAM)
+ {
+ int index = ins.siconst[1];
+ if (ins.mem == IM_LOCAL)
+ index += proc->mLocalVars[ins.vindex].mOffset;
+ else
+ index += ins.vindex + proc->mLocalSize + 2;
+
+ if (index <= 254)
+ {
+ ByteCodeInstruction bins(BC_STORE_LOCAL_16);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ bins.mValue = index;
+ mIns.Push(bins);
+ }
+ else
+ {
+ ByteCodeInstruction lins(BC_LEA_LOCAL);
+ lins.mRegister = BC_REG_ADDR;
+ lins.mValue = index;
+ mIns.Push(lins);
+ ByteCodeInstruction bins(BC_STORE_ADDR_16);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(bins);
+ }
+ }
+ else if (ins.mem == IM_FRAME)
+ {
+ ByteCodeInstruction bins(BC_STORE_FRAME_16);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ bins.mValue = ins.vindex + ins.siconst[1] + 2;
+ mIns.Push(bins);
+ }
+ }
+ }
+ else
+ {
+ if (ins.stemp[0] < 0)
+ {
+ IntConstToAccu(ins.siconst[0]);
+
+ if (ins.mem == IM_INDIRECT)
+ {
+ ByteCodeInstruction lins(BC_ADDR_REG);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[1]];
+ lins.mRegisterFinal = ins.sfinal[1];
+ mIns.Push(lins);
+ ByteCodeInstruction bins(BC_STORE_ADDR_16);
+ bins.mRegister = BC_REG_ACCU;
+ mIns.Push(bins);
+ }
+ }
+ else
+ {
+ if (ins.mem == IM_INDIRECT)
+ {
+ ByteCodeInstruction lins(BC_ADDR_REG);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[1]];
+ lins.mRegisterFinal = ins.sfinal[1];
+ mIns.Push(lins);
+ ByteCodeInstruction bins(BC_STORE_ADDR_16);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(bins);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (ins.stemp[1] < 0)
+ {
+ if (ins.stemp[0] < 0)
+ {
+ IntConstToAccu(ins.siconst[0]);
+
+ if (ins.opsize == 1)
+ {
+ if (ins.mem == IM_GLOBAL)
+ {
+ ByteCodeInstruction bins(BC_STORE_ABS_8);
+ bins.mRelocate = true;
+ bins.mVIndex = ins.vindex;
+ bins.mValue = ins.siconst[1];
+ bins.mRegister = BC_REG_ACCU;
+ mIns.Push(bins);
+ }
+ else if (ins.mem == IM_ABSOLUTE)
+ {
+ ByteCodeInstruction bins(BC_STORE_ABS_8);
+ bins.mValue = ins.siconst[1];
+ bins.mRegister = BC_REG_ACCU;
+ mIns.Push(bins);
+ }
+ else if (ins.mem == IM_LOCAL || ins.mem == IM_PARAM)
+ {
+ int index = ins.siconst[1];
+ if (ins.mem == IM_LOCAL)
+ index += proc->mLocalVars[ins.vindex].mOffset;
+ else
+ index += ins.vindex + proc->mLocalSize + 2;
+
+ if (index <= 255)
+ {
+ ByteCodeInstruction bins(BC_STORE_LOCAL_8);
+ bins.mRegister = BC_REG_ACCU;
+ bins.mValue = index;
+ mIns.Push(bins);
+ }
+ else
+ {
+ ByteCodeInstruction lins(BC_LEA_LOCAL);
+ lins.mRegister = BC_REG_ADDR;
+ lins.mValue = index;
+ mIns.Push(lins);
+ ByteCodeInstruction bins(BC_STORE_ADDR_8);
+ bins.mRegister = BC_REG_ACCU;
+ mIns.Push(bins);
+ }
+ }
+ else if (ins.mem == IM_FRAME)
+ {
+ ByteCodeInstruction bins(BC_STORE_FRAME_8);
+ bins.mRegister = BC_REG_ACCU;
+ bins.mValue = ins.vindex + ins.siconst[1] + 2;
+ mIns.Push(bins);
+ }
+ }
+ else if (ins.opsize == 2)
+ {
+ if (ins.mem == IM_GLOBAL)
+ {
+ ByteCodeInstruction bins(BC_STORE_ABS_16);
+ bins.mRelocate = true;
+ bins.mVIndex = ins.vindex;
+ bins.mValue = ins.siconst[1];
+ bins.mRegister = BC_REG_ACCU;
+ mIns.Push(bins);
+ }
+ else if (ins.mem == IM_ABSOLUTE)
+ {
+ ByteCodeInstruction bins(BC_STORE_ABS_16);
+ bins.mValue = ins.siconst[1];
+ bins.mRegister = BC_REG_ACCU;
+ mIns.Push(bins);
+ }
+ else if (ins.mem == IM_LOCAL || ins.mem == IM_PARAM)
+ {
+ int index = ins.siconst[1];
+ if (ins.mem == IM_LOCAL)
+ index += proc->mLocalVars[ins.vindex].mOffset;
+ else
+ index += ins.vindex + proc->mLocalSize + 2;
+
+ if (index <= 254)
+ {
+ ByteCodeInstruction bins(BC_STORE_LOCAL_16);
+ bins.mRegister = BC_REG_ACCU;
+ bins.mValue = index;
+ mIns.Push(bins);
+ }
+ else
+ {
+ ByteCodeInstruction lins(BC_LEA_LOCAL);
+ lins.mRegister = BC_REG_ADDR;
+ lins.mValue = index;
+ mIns.Push(lins);
+ ByteCodeInstruction bins(BC_STORE_ADDR_16);
+ bins.mRegister = BC_REG_ACCU;
+ mIns.Push(bins);
+ }
+ }
+ else if (ins.mem == IM_FRAME)
+ {
+ ByteCodeInstruction bins(BC_STORE_FRAME_16);
+ bins.mRegister = BC_REG_ACCU;
+ bins.mValue = ins.vindex + ins.siconst[1] + 2;
+ mIns.Push(bins);
+ }
+ }
+ }
+ else
+ {
+ if (ins.opsize == 1)
+ {
+ if (ins.mem == IM_GLOBAL)
+ {
+ ByteCodeInstruction bins(BC_STORE_ABS_8);
+ bins.mRelocate = true;
+ bins.mVIndex = ins.vindex;
+ bins.mValue = ins.siconst[1];
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(bins);
+ }
+ else if (ins.mem == IM_ABSOLUTE)
+ {
+ ByteCodeInstruction bins(BC_STORE_ABS_8);
+ bins.mValue = ins.siconst[1];
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(bins);
+ }
+ else if (ins.mem == IM_LOCAL || ins.mem == IM_PARAM)
+ {
+ int index = ins.siconst[1];
+ if (ins.mem == IM_LOCAL)
+ index += proc->mLocalVars[ins.vindex].mOffset;
+ else
+ index += ins.vindex + proc->mLocalSize + 2;
+
+ if (index <= 255)
+ {
+ ByteCodeInstruction bins(BC_STORE_LOCAL_8);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ bins.mValue = index;
+ mIns.Push(bins);
+ }
+ else
+ {
+ ByteCodeInstruction lins(BC_LEA_LOCAL);
+ lins.mRegister = BC_REG_ADDR;
+ lins.mValue = index;
+ mIns.Push(lins);
+ ByteCodeInstruction bins(BC_STORE_ADDR_8);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(bins);
+ }
+ }
+ else if (ins.mem == IM_FRAME)
+ {
+ ByteCodeInstruction bins(BC_STORE_FRAME_8);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ bins.mValue = ins.vindex + ins.siconst[1] + 2;
+ mIns.Push(bins);
+ }
+ }
+ else if (ins.opsize == 2)
+ {
+ if (ins.mem == IM_GLOBAL)
+ {
+ ByteCodeInstruction bins(BC_STORE_ABS_16);
+ bins.mRelocate = true;
+ bins.mVIndex = ins.vindex;
+ bins.mValue = ins.siconst[1];
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(bins);
+ }
+ else if (ins.mem == IM_ABSOLUTE)
+ {
+ ByteCodeInstruction bins(BC_STORE_ABS_16);
+ bins.mValue = ins.siconst[1];
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(bins);
+ }
+ else if (ins.mem == IM_LOCAL || ins.mem == IM_PARAM)
+ {
+ int index = ins.siconst[1];
+ if (ins.mem == IM_LOCAL)
+ index += proc->mLocalVars[ins.vindex].mOffset;
+ else
+ index += ins.vindex + proc->mLocalSize + 2;
+
+ if (index <= 254)
+ {
+ ByteCodeInstruction bins(BC_STORE_LOCAL_16);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ bins.mValue = index;
+ mIns.Push(bins);
+ }
+ else
+ {
+ ByteCodeInstruction lins(BC_LEA_LOCAL);
+ lins.mRegister = BC_REG_ADDR;
+ lins.mValue = index;
+ mIns.Push(lins);
+ ByteCodeInstruction bins(BC_STORE_ADDR_16);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(bins);
+ }
+ }
+ else if (ins.mem == IM_FRAME)
+ {
+ ByteCodeInstruction bins(BC_STORE_FRAME_16);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ bins.mValue = ins.vindex + ins.siconst[1] + 2;
+ mIns.Push(bins);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (ins.stemp[0] < 0)
+ {
+ IntConstToAccu(ins.siconst[0]);
+
+ if (ins.mem == IM_INDIRECT)
+ {
+ ByteCodeInstruction lins(BC_ADDR_REG);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[1]];
+ lins.mRegisterFinal = ins.sfinal[1];
+ mIns.Push(lins);
+ if (ins.opsize == 1)
+ {
+ ByteCodeInstruction bins(BC_STORE_ADDR_8);
+ bins.mRegister = BC_REG_ACCU;
+ mIns.Push(bins);
+ }
+ else if (ins.opsize == 2)
+ {
+ ByteCodeInstruction bins(BC_STORE_ADDR_16);
+ bins.mRegister = BC_REG_ACCU;
+ mIns.Push(bins);
+ }
+ }
+ }
+ else
+ {
+ if (ins.mem == IM_INDIRECT)
+ {
+ ByteCodeInstruction lins(BC_ADDR_REG);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[1]];
+ lins.mRegisterFinal = ins.sfinal[1];
+ mIns.Push(lins);
+ if (ins.opsize == 1)
+ {
+ ByteCodeInstruction bins(BC_STORE_ADDR_8);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(bins);
+ }
+ else if (ins.opsize == 2)
+ {
+ ByteCodeInstruction bins(BC_STORE_ADDR_16);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(bins);
+ }
+ }
+ }
+ }
+ }
+}
+
+void ByteCodeBasicBlock::LoadDirectValue(InterCodeProcedure* proc, const InterInstruction& ins)
+{
+ if (ins.ttype == IT_FLOAT)
+ {
+ if (ins.stemp[0] < 0)
+ {
+ if (ins.mem == IM_GLOBAL)
+ {
+ ByteCodeInstruction bins(BC_LOAD_ABS_32);
+ bins.mRelocate = true;
+ bins.mVIndex = ins.vindex;
+ bins.mValue = ins.siconst[0];
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ mIns.Push(bins);
+ }
+ else if (ins.mem == IM_ABSOLUTE)
+ {
+ ByteCodeInstruction bins(BC_LOAD_ABS_32);
+ bins.mValue = ins.siconst[0];
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ mIns.Push(bins);
+ }
+ else if (ins.mem == IM_LOCAL || ins.mem == IM_PARAM)
+ {
+ int index = ins.siconst[0];
+ if (ins.mem == IM_LOCAL)
+ index += proc->mLocalVars[ins.vindex].mOffset;
+ else
+ index += ins.vindex + proc->mLocalSize + 2;
+
+ if (index <= 254)
+ {
+ ByteCodeInstruction bins(BC_LOAD_LOCAL_32);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ bins.mValue = index;
+ mIns.Push(bins);
+ }
+ else
+ {
+ ByteCodeInstruction lins(BC_LEA_LOCAL);
+ lins.mRegister = BC_REG_ADDR;
+ lins.mValue = index;
+ mIns.Push(lins);
+ ByteCodeInstruction bins(BC_LOAD_ADDR_32);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ mIns.Push(bins);
+ }
+ }
+ }
+ else
+ {
+ if (ins.mem == IM_INDIRECT)
+ {
+ ByteCodeInstruction lins(BC_ADDR_REG);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ lins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(lins);
+ ByteCodeInstruction bins(BC_LOAD_ADDR_32);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ mIns.Push(bins);
+ }
+ }
+ }
+ else if (ins.ttype == IT_POINTER)
+ {
+ if (ins.stemp[0] < 0)
+ {
+ if (ins.mem == IM_GLOBAL)
+ {
+ ByteCodeInstruction bins(BC_LOAD_ABS_16);
+ bins.mRelocate = true;
+ bins.mVIndex = ins.vindex;
+ bins.mValue = ins.siconst[0];
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ mIns.Push(bins);
+ }
+ else if (ins.mem == IM_ABSOLUTE)
+ {
+ ByteCodeInstruction bins(BC_LOAD_ABS_16);
+ bins.mValue = ins.siconst[0];
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ mIns.Push(bins);
+ }
+ else if (ins.mem == IM_LOCAL || ins.mem == IM_PARAM)
+ {
+ int index = ins.siconst[0];
+ if (ins.mem == IM_LOCAL)
+ index += proc->mLocalVars[ins.vindex].mOffset;
+ else
+ index += ins.vindex + proc->mLocalSize + 2;
+
+ if (index <= 254)
+ {
+ ByteCodeInstruction bins(BC_LOAD_LOCAL_16);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ bins.mValue = index;
+ mIns.Push(bins);
+ }
+ else
+ {
+ ByteCodeInstruction lins(BC_LEA_LOCAL);
+ lins.mRegister = BC_REG_ADDR;
+ lins.mValue = index;
+ mIns.Push(lins);
+ ByteCodeInstruction bins(BC_LOAD_ADDR_16);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ mIns.Push(bins);
+ }
+ }
+ }
+ else
+ {
+ if (ins.mem == IM_INDIRECT)
+ {
+ ByteCodeInstruction lins(BC_ADDR_REG);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ lins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(lins);
+ ByteCodeInstruction bins(BC_LOAD_ADDR_16);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ mIns.Push(bins);
+ }
+ }
+ }
+ else
+ {
+ if (ins.stemp[0] < 0)
+ {
+ if (ins.opsize == 1)
+ {
+ if (ins.mem == IM_GLOBAL)
+ {
+ ByteCodeInstruction bins(ins.ttype == IT_SIGNED ? BC_LOAD_ABS_I8 : BC_LOAD_ABS_U8);
+ bins.mRelocate = true;
+ bins.mVIndex = ins.vindex;
+ bins.mValue = ins.siconst[0];
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ mIns.Push(bins);
+ }
+ else if (ins.mem == IM_ABSOLUTE)
+ {
+ ByteCodeInstruction bins(ins.ttype == IT_SIGNED ? BC_LOAD_ABS_I8 : BC_LOAD_ABS_U8);
+ bins.mValue = ins.siconst[0];
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ mIns.Push(bins);
+ }
+ else if (ins.mem == IM_LOCAL || ins.mem == IM_PARAM)
+ {
+ int index = ins.siconst[0];
+ if (ins.mem == IM_LOCAL)
+ index += proc->mLocalVars[ins.vindex].mOffset;
+ else
+ index += ins.vindex + proc->mLocalSize + 2;
+
+ if (index <= 255)
+ {
+ ByteCodeInstruction bins(ins.ttype == IT_SIGNED ? BC_LOAD_LOCAL_I8 : BC_LOAD_LOCAL_U8);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ bins.mValue = index;
+ mIns.Push(bins);
+ }
+ else
+ {
+ ByteCodeInstruction lins(BC_LEA_LOCAL);
+ lins.mRegister = BC_REG_ADDR;
+ lins.mValue = index;
+ mIns.Push(lins);
+ ByteCodeInstruction bins(ins.ttype == IT_SIGNED ? BC_LOAD_ADDR_I8 : BC_LOAD_ADDR_U8);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ mIns.Push(bins);
+ }
+ }
+ }
+ else if (ins.opsize == 2)
+ {
+ if (ins.mem == IM_GLOBAL)
+ {
+ ByteCodeInstruction bins(BC_LOAD_ABS_16);
+ bins.mRelocate = true;
+ bins.mVIndex = ins.vindex;
+ bins.mValue = ins.siconst[0];
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ mIns.Push(bins);
+ }
+ else if (ins.mem == IM_ABSOLUTE)
+ {
+ ByteCodeInstruction bins(BC_LOAD_ABS_16);
+ bins.mValue = ins.siconst[0];
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ mIns.Push(bins);
+ }
+ else if (ins.mem == IM_LOCAL || ins.mem == IM_PARAM)
+ {
+ int index = ins.siconst[0];
+ if (ins.mem == IM_LOCAL)
+ index += proc->mLocalVars[ins.vindex].mOffset;
+ else
+ index += ins.vindex + proc->mLocalSize + 2;
+
+ if (index <= 254)
+ {
+ ByteCodeInstruction bins(BC_LOAD_LOCAL_16);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ bins.mValue = index;
+ mIns.Push(bins);
+ }
+ else
+ {
+ ByteCodeInstruction lins(BC_LEA_LOCAL);
+ lins.mRegister = BC_REG_ADDR;
+ lins.mValue = index;
+ mIns.Push(lins);
+ ByteCodeInstruction bins(BC_LOAD_ADDR_16);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ mIns.Push(bins);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (ins.mem == IM_INDIRECT)
+ {
+ ByteCodeInstruction lins(BC_ADDR_REG);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ lins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(lins);
+
+ if (ins.opsize == 1)
+ {
+ if (ins.ttype == IT_SIGNED)
+ {
+ ByteCodeInstruction bins(BC_LOAD_ADDR_I8);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ mIns.Push(bins);
+ }
+ else
+ {
+ ByteCodeInstruction bins(BC_LOAD_ADDR_U8);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ mIns.Push(bins);
+ }
+ }
+ else if (ins.opsize == 2)
+ {
+ ByteCodeInstruction bins(BC_LOAD_ADDR_16);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ mIns.Push(bins);
+ }
+ }
+ }
+ }
+}
+
+void ByteCodeBasicBlock::LoadEffectiveAddress(InterCodeProcedure* proc, const InterInstruction& ins)
+{
+ if (ins.stemp[0] < 0)
+ {
+ if (ins.stemp[1] == ins.ttemp)
+ {
+ ByteCodeInstruction bins(BC_BINOP_ADDI_16);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ bins.mValue = ins.siconst[0];
+ mIns.Push(bins);
+ }
+ else
+ {
+ ByteCodeInstruction lins(BC_LOAD_REG_16);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[1]];
+ lins.mRegisterFinal = ins.sfinal[1];
+ mIns.Push(lins);
+ ByteCodeInstruction ains(BC_BINOP_ADDI_16);
+ ains.mRegister = BC_REG_ACCU;
+ ains.mValue = ins.siconst[0];
+ mIns.Push(ains);
+ ByteCodeInstruction sins(BC_STORE_REG_16);
+ sins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ mIns.Push(sins);
+ }
+ }
+ else
+ {
+ ByteCodeInstruction lins(BC_LOAD_REG_16);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[1]];
+ lins.mRegisterFinal = ins.sfinal[1];
+ mIns.Push(lins);
+ ByteCodeInstruction ains(BC_BINOP_ADDR_16);
+ ains.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ ains.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(ains);
+ ByteCodeInstruction sins(BC_STORE_REG_16);
+ sins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ mIns.Push(sins);
+ }
+}
+
+void ByteCodeBasicBlock::CallFunction(InterCodeProcedure* proc, const InterInstruction& ins)
+{
+ if (ins.stemp[0] < 0)
+ {
+ ByteCodeInstruction bins(BC_LEA_ABS);
+ bins.mRelocate = true;
+ bins.mFunction = true;
+ bins.mVIndex = ins.vindex;
+ bins.mValue = 0;
+ bins.mRegister = BC_REG_ADDR;
+ mIns.Push(bins);
+ }
+ else
+ {
+ ByteCodeInstruction bins(BC_ADDR_REG);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(bins);
+ }
+
+ ByteCodeInstruction cins(BC_CALL);
+ mIns.Push(cins);
+
+ if (ins.ttemp >= 0)
+ {
+ if (ins.ttype == IT_FLOAT)
+ {
+ ByteCodeInstruction bins(BC_STORE_REG_32);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ mIns.Push(bins);
+ }
+ else
+ {
+ ByteCodeInstruction bins(BC_STORE_REG_16);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ mIns.Push(bins);
+ }
+ }
+}
+
+void ByteCodeBasicBlock::CallAssembler(InterCodeProcedure* proc, const InterInstruction& ins)
+{
+ if (ins.stemp[0] < 0)
+ {
+ ByteCodeInstruction bins(BC_JSR);
+ bins.mRelocate = true;
+ bins.mVIndex = ins.vindex;
+ mIns.Push(bins);
+ }
+}
+
+ByteCode ByteCodeBasicBlock::RelationalOperator(InterCodeProcedure* proc, const InterInstruction& ins)
+{
+ ByteCode code;
+ bool csigned = false;
+
+ switch (ins.oper)
+ {
+ default:
+ case IA_CMPEQ:
+ code = BC_BRANCHS_EQ;
+ break;
+ case IA_CMPNE:
+ code = BC_BRANCHS_NE;
+ break;
+
+ case IA_CMPGES:
+ csigned = true;
+ code = BC_BRANCHS_GE;
+ break;
+ case IA_CMPGEU:
+ code = BC_BRANCHS_GE;
+ break;
+ case IA_CMPGS:
+ csigned = true;
+ code = BC_BRANCHS_GT;
+ break;
+ case IA_CMPGU:
+ code = BC_BRANCHS_GT;
+ break;
+ case IA_CMPLES:
+ csigned = true;
+ code = BC_BRANCHS_LE;
+ break;
+ case IA_CMPLEU:
+ code = BC_BRANCHS_LE;
+ break;
+ case IA_CMPLS:
+ csigned = true;
+ code = BC_BRANCHS_LT;
+ break;
+ case IA_CMPLU:
+ code = BC_BRANCHS_LT;
+ break;
+ }
+
+ if (ins.stype[0] == IT_FLOAT)
+ {
+ ByteCodeInstruction lins(BC_LOAD_REG_32);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ lins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(lins);
+ ByteCodeInstruction cins(BC_BINOP_CMP_F32);
+ cins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[1]];
+ cins.mRegisterFinal = ins.sfinal[1];
+ mIns.Push(cins);
+ }
+ else
+ {
+ if (ins.stemp[1] < 0)
+ {
+ ByteCodeInstruction lins(BC_LOAD_REG_16);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ lins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(lins);
+ if (csigned)
+ {
+ ByteCodeInstruction cins(BC_BINOP_CMPSI_16);
+ cins.mValue = ins.siconst[1];
+ mIns.Push(cins);
+ }
+ else
+ {
+ ByteCodeInstruction cins(BC_BINOP_CMPUI_16);
+ cins.mValue = ins.siconst[1];
+ mIns.Push(cins);
+ }
+ }
+ else if (ins.stemp[0] < 0)
+ {
+ ByteCodeInstruction lins(BC_LOAD_REG_16);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[1]];
+ lins.mRegisterFinal = ins.sfinal[1];
+ mIns.Push(lins);
+ if (csigned)
+ {
+ ByteCodeInstruction cins(BC_BINOP_CMPSI_16);
+ cins.mValue = ins.siconst[0];
+ mIns.Push(cins);
+ }
+ else
+ {
+ ByteCodeInstruction cins(BC_BINOP_CMPUI_16);
+ cins.mValue = ins.siconst[0];
+ mIns.Push(cins);
+ }
+ code = TransposeBranchCondition(code);
+ }
+ else
+ {
+ ByteCodeInstruction lins(BC_LOAD_REG_16);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ lins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(lins);
+ if (csigned)
+ {
+ ByteCodeInstruction cins(BC_BINOP_CMPSR_16);
+ cins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[1]];
+ cins.mRegisterFinal = ins.sfinal[1];
+ mIns.Push(cins);
+ }
+ else
+ {
+ ByteCodeInstruction cins(BC_BINOP_CMPUR_16);
+ cins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[1]];
+ cins.mRegisterFinal = ins.sfinal[1];
+ mIns.Push(cins);
+ }
+ }
+ }
+
+ return code;
+}
+
+static ByteCode ByteCodeBinRegOperator(const InterInstruction& ins)
+{
+ if (ins.ttype == IT_FLOAT)
+ {
+ switch (ins.oper)
+ {
+ case IA_ADD: return BC_BINOP_ADD_F32;
+ case IA_SUB: return BC_BINOP_SUB_F32;
+ case IA_MUL: return BC_BINOP_MUL_F32;
+ case IA_DIVU: return BC_BINOP_DIV_F32;
+ case IA_DIVS: return BC_BINOP_DIV_F32;
+
+ default:
+ return BC_EXIT;
+ }
+ }
+ else
+ {
+ switch (ins.oper)
+ {
+ case IA_ADD: return BC_BINOP_ADDR_16;
+ case IA_SUB: return BC_BINOP_SUBR_16;
+ case IA_MUL: return BC_BINOP_MULR_16;
+ case IA_DIVU: return BC_BINOP_DIVR_U16;
+ case IA_MODU: return BC_BINOP_MODR_U16;
+ case IA_DIVS: return BC_BINOP_DIVR_I16;
+ case IA_MODS: return BC_BINOP_MODR_I16;
+ case IA_AND: return BC_BINOP_ANDR_16;
+ case IA_OR: return BC_BINOP_ORR_16;
+ case IA_XOR: return BC_BINOP_XORR_16;
+
+ case IA_SHL: return BC_BINOP_SHLR_16;
+ case IA_SHR: return BC_BINOP_SHRR_U16;
+ case IA_SAR: return BC_BINOP_SHRR_I16;
+
+ default:
+ return BC_EXIT;
+ }
+ }
+}
+
+static ByteCode ByteCodeBinImmOperator(const InterInstruction& ins)
+{
+ switch (ins.oper)
+ {
+ case IA_ADD: return BC_BINOP_ADDI_16;
+ case IA_SUB: return BC_BINOP_SUBI_16;
+ case IA_AND: return BC_BINOP_ANDI_16;
+ case IA_OR: return BC_BINOP_ORI_16;
+ case IA_SHL: return BC_BINOP_SHLI_16;
+ case IA_SHR: return BC_BINOP_SHRI_U16;
+ case IA_SAR: return BC_BINOP_SHRI_I16;
+ case IA_MUL: return BC_BINOP_MULI8_16;
+
+ default:
+ return BC_EXIT;
+ }
+}
+
+void ByteCodeBasicBlock::NumericConversion(InterCodeProcedure* proc, const InterInstruction& ins)
+{
+ switch (ins.oper)
+ {
+ case IA_FLOAT2INT:
+ {
+ ByteCodeInstruction lins(BC_LOAD_REG_32);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ lins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(lins);
+
+ ByteCodeInstruction bins(ins.ttype == IT_SIGNED ? BC_CONV_F32_I16 : BC_CONV_F32_U16);
+ mIns.Push(bins);
+
+ ByteCodeInstruction sins(BC_STORE_REG_16);
+ sins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ mIns.Push(sins);
+
+ } break;
+ case IA_INT2FLOAT:
+ {
+ ByteCodeInstruction lins(BC_LOAD_REG_16);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ lins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(lins);
+
+ ByteCodeInstruction bins(ins.stype[0] == IT_SIGNED ? BC_CONV_I16_F32 : BC_CONV_U16_F32);
+ mIns.Push(bins);
+
+ ByteCodeInstruction sins(BC_STORE_REG_32);
+ sins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ mIns.Push(sins);
+
+ } break;
+ }
+}
+
+void ByteCodeBasicBlock::UnaryOperator(InterCodeProcedure* proc, const InterInstruction& ins)
+{
+ if (ins.ttype == IT_FLOAT)
+ {
+ ByteCodeInstruction lins(BC_LOAD_REG_32);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ lins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(lins);
+
+ switch (ins.oper)
+ {
+ case IA_NEG:
+ {
+ ByteCodeInstruction oins(BC_OP_NEGATE_F32);
+ mIns.Push(oins);
+ } break;
+ case IA_ABS:
+ {
+ ByteCodeInstruction oins(BC_OP_ABS_F32);
+ mIns.Push(oins);
+ } break;
+ case IA_FLOOR:
+ {
+ ByteCodeInstruction oins(BC_OP_FLOOR_F32);
+ mIns.Push(oins);
+ } break;
+ case IA_CEIL:
+ {
+ ByteCodeInstruction oins(BC_OP_CEIL_F32);
+ mIns.Push(oins);
+ } break;
+ }
+
+ ByteCodeInstruction sins(BC_STORE_REG_32);
+ sins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ mIns.Push(sins);
+ }
+ else
+ {
+ ByteCodeInstruction lins(BC_LOAD_REG_16);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ lins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(lins);
+
+ switch (ins.oper)
+ {
+ case IA_NEG:
+ {
+ ByteCodeInstruction oins(BC_OP_NEGATE_16);
+ mIns.Push(oins);
+ } break;
+
+ case IA_NOT:
+ {
+ ByteCodeInstruction oins(BC_OP_INVERT_16);
+ mIns.Push(oins);
+ } break;
+ }
+
+ ByteCodeInstruction sins(BC_STORE_REG_16);
+ sins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ mIns.Push(sins);
+ }
+}
+
+void ByteCodeBasicBlock::BinaryOperator(InterCodeProcedure* proc, const InterInstruction& ins)
+{
+ if (ins.ttype == IT_FLOAT)
+ {
+ ByteCode bc = ByteCodeBinRegOperator(ins);
+
+ ByteCodeInstruction lins(BC_LOAD_REG_32);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[1]];
+ lins.mRegisterFinal = ins.sfinal[1];
+ mIns.Push(lins);
+
+ ByteCodeInstruction bins(bc);
+ if (ins.stemp[1] == ins.stemp[0])
+ bins.mRegister = BC_REG_ACCU;
+ else
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(bins);
+
+ ByteCodeInstruction sins(BC_STORE_REG_32);
+ sins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ mIns.Push(sins);
+ }
+ else
+ {
+ switch (ins.oper)
+ {
+ case IA_ADD:
+ case IA_OR:
+ case IA_AND:
+ {
+ ByteCode bc = ByteCodeBinRegOperator(ins);
+ ByteCode bci = ByteCodeBinImmOperator(ins);
+
+ if (ins.stemp[1] < 0)
+ {
+ if (ins.stemp[0] == ins.ttemp)
+ {
+ ByteCodeInstruction bins(bci);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ bins.mValue = ins.siconst[1];
+ mIns.Push(bins);
+ return;
+ }
+
+ ByteCodeInstruction lins(BC_LOAD_REG_16);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ lins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(lins);
+
+ ByteCodeInstruction bins(bci);
+ bins.mRegister = BC_REG_ACCU;
+ bins.mValue = ins.siconst[1];
+ mIns.Push(bins);
+ }
+ else if (ins.stemp[0] < 0)
+ {
+ if (ins.stemp[1] == ins.ttemp)
+ {
+ ByteCodeInstruction bins(bci);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ bins.mValue = ins.siconst[0];
+ mIns.Push(bins);
+ return;
+ }
+
+ ByteCodeInstruction lins(BC_LOAD_REG_16);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[1]];
+ lins.mRegisterFinal = ins.sfinal[1];
+ mIns.Push(lins);
+
+ ByteCodeInstruction bins(bci);
+ bins.mRegister = BC_REG_ACCU;
+ bins.mValue = ins.siconst[0];
+ mIns.Push(bins);
+ }
+ else
+ {
+ ByteCodeInstruction lins(BC_LOAD_REG_16);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[1]];
+ lins.mRegisterFinal = ins.sfinal[1];
+ mIns.Push(lins);
+
+ ByteCodeInstruction bins(bc);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(bins);
+ }
+ }
+ break;
+ case IA_SUB:
+ if (ins.stemp[1] < 0)
+ {
+ if (ins.stemp[0] == ins.ttemp)
+ {
+ ByteCodeInstruction bins(BC_BINOP_SUBI_16);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ bins.mValue = ins.siconst[1];
+ mIns.Push(bins);
+ return;
+ }
+ ByteCodeInstruction lins(BC_LOAD_REG_16);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ lins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(lins);
+
+ ByteCodeInstruction bins(BC_BINOP_SUBI_16);
+ bins.mRegister = BC_REG_ACCU;
+ bins.mValue = ins.siconst[1];
+ mIns.Push(bins);
+ }
+ else if (ins.stemp[0] < 0)
+ {
+ if (ins.stemp[1] == ins.ttemp)
+ {
+ ByteCodeInstruction bins(BC_BINOP_ADDI_16);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ bins.mValue = - ins.siconst[0];
+ mIns.Push(bins);
+ return;
+ }
+ ByteCodeInstruction lins(BC_LOAD_REG_16);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[1]];
+ lins.mRegisterFinal = ins.sfinal[1];
+ mIns.Push(lins);
+
+ ByteCodeInstruction bins(BC_BINOP_ADDI_16);
+ bins.mRegister = BC_REG_ACCU;
+ bins.mValue = - ins.siconst[0];
+ mIns.Push(bins);
+ }
+ else
+ {
+ ByteCodeInstruction lins(BC_LOAD_REG_16);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[1]];
+ lins.mRegisterFinal = ins.sfinal[1];
+ mIns.Push(lins);
+
+ ByteCodeInstruction bins(BC_BINOP_SUBR_16);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(bins);
+ }
+ break;
+ case IA_MUL:
+ {
+ ByteCode bc = ByteCodeBinRegOperator(ins);
+ ByteCode bci = ByteCodeBinImmOperator(ins);
+ if (ins.stemp[1] < 0)
+ {
+ if (ins.siconst[1] >= 0 && ins.siconst[1] <= 255)
+ {
+ if (ins.stemp[0] == ins.ttemp)
+ {
+ ByteCodeInstruction bins(bci);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ bins.mValue = ins.siconst[1];
+ mIns.Push(bins);
+ return;
+ }
+
+ ByteCodeInstruction lins(BC_LOAD_REG_16);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ lins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(lins);
+
+ ByteCodeInstruction bins(bci);
+ bins.mRegister = BC_REG_ACCU;
+ bins.mValue = ins.siconst[1];
+ mIns.Push(bins);
+ }
+ else
+ {
+ IntConstToAccu(ins.siconst[1]);
+ ByteCodeInstruction bins(bc);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(bins);
+ }
+ }
+ else if (ins.stemp[0] < 0)
+ {
+ if (ins.siconst[0] >= 0 && ins.siconst[0] <= 255)
+ {
+ if (ins.stemp[1] == ins.ttemp)
+ {
+ ByteCodeInstruction bins(bci);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[1]];
+ bins.mRegisterFinal = ins.sfinal[1];
+ bins.mValue = ins.siconst[0];
+ mIns.Push(bins);
+ return;
+ }
+
+ ByteCodeInstruction lins(BC_LOAD_REG_16);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[1]];
+ lins.mRegisterFinal = ins.sfinal[1];
+ mIns.Push(lins);
+
+ ByteCodeInstruction bins(bci);
+ bins.mRegister = BC_REG_ACCU;
+ bins.mValue = ins.siconst[0];
+ mIns.Push(bins);
+ }
+ else
+ {
+ IntConstToAccu(ins.siconst[0]);
+ ByteCodeInstruction bins(bc);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[1]];
+ bins.mRegisterFinal = ins.sfinal[1];
+ mIns.Push(bins);
+ }
+ }
+ else
+ {
+ ByteCodeInstruction lins(BC_LOAD_REG_16);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[1]];
+ lins.mRegisterFinal = ins.sfinal[1];
+ mIns.Push(lins);
+
+ ByteCodeInstruction bins(bc);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(bins);
+ }
+ } break;
+ case IA_XOR:
+ {
+ ByteCode bc = ByteCodeBinRegOperator(ins);
+ if (ins.stemp[1] < 0)
+ {
+ IntConstToAccu(ins.siconst[1]);
+ ByteCodeInstruction bins(bc);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(bins);
+ }
+ else if (ins.stemp[0] < 0)
+ {
+ IntConstToAccu(ins.siconst[0]);
+ ByteCodeInstruction bins(bc);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[1]];
+ bins.mRegisterFinal = ins.sfinal[1];
+ mIns.Push(bins);
+ }
+ else
+ {
+ ByteCodeInstruction lins(BC_LOAD_REG_16);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[1]];
+ lins.mRegisterFinal = ins.sfinal[1];
+ mIns.Push(lins);
+
+ ByteCodeInstruction bins(bc);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(bins);
+ }
+ } break;
+ case IA_DIVS:
+ case IA_MODS:
+ case IA_DIVU:
+ case IA_MODU:
+ {
+ ByteCode bc = ByteCodeBinRegOperator(ins);
+ if (ins.stemp[1] < 0)
+ {
+ IntConstToAccu(ins.siconst[1]);
+ ByteCodeInstruction bins(bc);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(bins);
+ }
+ else if (ins.stemp[0] < 0)
+ {
+ ByteCodeInstruction lins(BC_LOAD_REG_16);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[1]];
+ lins.mRegisterFinal = ins.sfinal[1];
+ mIns.Push(lins);
+
+ IntConstToAddr(ins.siconst[0]);
+
+ ByteCodeInstruction bins(bc);
+ bins.mRegister = BC_REG_ADDR;
+ mIns.Push(bins);
+ }
+ else
+ {
+ ByteCodeInstruction lins(BC_LOAD_REG_16);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[1]];
+ lins.mRegisterFinal = ins.sfinal[1];
+ mIns.Push(lins);
+
+ ByteCodeInstruction bins(bc);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(bins);
+ }
+ } break;
+
+ case IA_SHL:
+ case IA_SHR:
+ case IA_SAR:
+ {
+ ByteCode rbc = ByteCodeBinRegOperator(ins);
+
+ ByteCode ibc = ByteCodeBinImmOperator(ins);
+ if (ins.stemp[1] < 0)
+ {
+ IntConstToAccu(ins.siconst[1]);
+
+ ByteCodeInstruction bins(rbc);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(bins);
+ }
+ else if (ins.stemp[0] < 0)
+ {
+ ByteCodeInstruction lins(BC_LOAD_REG_16);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[1]];
+ lins.mRegisterFinal = ins.sfinal[1];
+ mIns.Push(lins);
+
+ ByteCodeInstruction bins(ibc);
+ bins.mValue = ins.siconst[0];
+ mIns.Push(bins);
+ }
+ else
+ {
+ ByteCodeInstruction lins(BC_LOAD_REG_16);
+ lins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[1]];
+ lins.mRegisterFinal = ins.sfinal[1];
+ mIns.Push(lins);
+
+ ByteCodeInstruction bins(rbc);
+ bins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.stemp[0]];
+ bins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(bins);
+ }
+
+ } break;
+ }
+
+ ByteCodeInstruction sins(BC_STORE_REG_16);
+ sins.mRegister = BC_REG_TMP + proc->mTempOffset[ins.ttemp];
+ mIns.Push(sins);
+ }
+}
+
+void ByteCodeBasicBlock::Compile(InterCodeProcedure* iproc, ByteCodeProcedure* proc, InterCodeBasicBlock* sblock)
+{
+ num = sblock->num;
+
+ int i = 0;
+ while (i < sblock->code.Size())
+ {
+ const InterInstruction & ins = sblock->code[i];
+
+ switch (ins.code)
+ {
+ case IC_STORE:
+ StoreDirectValue(iproc, ins);
+ break;
+ case IC_LOAD:
+ LoadDirectValue(iproc, ins);
+ break;
+ case IC_COPY:
+ CopyValue(iproc, ins);
+ break;
+ case IC_LOAD_TEMPORARY:
+ {
+ if (ins.stemp[0] != ins.ttemp)
+ {
+ ByteCodeInstruction lins(BC_LOAD_REG_16);
+ lins.mRegister = BC_REG_TMP + iproc->mTempOffset[ins.stemp[0]];
+ lins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(lins);
+ ByteCodeInstruction sins(BC_STORE_REG_16);
+ sins.mRegister = BC_REG_TMP + iproc->mTempOffset[ins.ttemp];
+ mIns.Push(sins);
+ }
+ } break;
+ case IC_BINARY_OPERATOR:
+ BinaryOperator(iproc, ins);
+ break;
+ case IC_UNARY_OPERATOR:
+ UnaryOperator(iproc, ins);
+ break;
+ case IC_CONVERSION_OPERATOR:
+ NumericConversion(iproc, ins);
+ break;
+ case IC_LEA:
+ LoadEffectiveAddress(iproc, ins);
+ break;
+ case IC_CONSTANT:
+ LoadConstant(iproc, ins);
+ break;
+ case IC_CALL:
+ CallFunction(iproc, ins);
+ break;
+ case IC_JSR:
+ CallAssembler(iproc, ins);
+ break;
+ case IC_PUSH_FRAME:
+ {
+ ByteCodeInstruction bins(BC_PUSH_FRAME);
+ bins.mValue = ins.ivalue + 2;
+ mIns.Push(bins);
+
+ } break;
+ case IC_POP_FRAME:
+ {
+ ByteCodeInstruction bins(BC_POP_FRAME);
+ bins.mValue = ins.ivalue + 2;
+ mIns.Push(bins);
+
+ } break;
+
+ case IC_RELATIONAL_OPERATOR:
+ if (sblock->code[i + 1].code == IC_BRANCH)
+ {
+ ByteCode code = RelationalOperator(iproc, ins);
+ this->Close(proc->CompileBlock(iproc, sblock->trueJump), proc->CompileBlock(iproc, sblock->falseJump), code);
+ i++;
+ return;
+ }
+ else
+ {
+ ByteCode code = RelationalOperator(iproc, ins);
+ ByteCodeInstruction bins(ByteCode(code - BC_BRANCHS_EQ + BC_SET_EQ));
+ mIns.Push(bins);
+ ByteCodeInstruction sins(BC_STORE_REG_16);
+ sins.mRegister = BC_REG_TMP + iproc->mTempOffset[ins.ttemp];
+ mIns.Push(sins);
+ }
+ break;
+
+ case IC_RETURN_VALUE:
+ if (ins.stemp[0] < 0)
+ IntConstToAccu(ins.siconst[0]);
+ else if (ins.stype[0] == IT_FLOAT)
+ {
+ ByteCodeInstruction lins(BC_LOAD_REG_32);
+ lins.mRegister = BC_REG_TMP + iproc->mTempOffset[ins.stemp[0]];
+ lins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(lins);
+ }
+ else
+ {
+ ByteCodeInstruction lins(BC_LOAD_REG_16);
+ lins.mRegister = BC_REG_TMP + iproc->mTempOffset[ins.stemp[0]];
+ lins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(lins);
+ }
+
+ this->Close(proc->exitBlock, nullptr, BC_JUMPS);
+ return;
+
+ case IC_RETURN:
+ this->Close(proc->exitBlock, nullptr, BC_JUMPS);
+ return;
+
+ case IC_TYPECAST:
+ if (ins.stemp[0] >= 0 && ins.ttemp != ins.stemp[0])
+ {
+ ByteCodeInstruction lins(BC_LOAD_REG_16);
+ lins.mRegister = BC_REG_TMP + iproc->mTempOffset[ins.stemp[0]];
+ lins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(lins);
+ ByteCodeInstruction sins(BC_STORE_REG_16);
+ sins.mRegister = BC_REG_TMP + iproc->mTempOffset[ins.ttemp];
+ mIns.Push(sins);
+ }
+ break;
+
+ case IC_BRANCH:
+ if (ins.stemp[0] < 0)
+ {
+ if (ins.siconst[0] == 0)
+ this->Close(proc->CompileBlock(iproc, sblock->falseJump), nullptr, BC_JUMPS);
+ else
+ this->Close(proc->CompileBlock(iproc, sblock->trueJump), nullptr, BC_JUMPS);
+ }
+ else
+ {
+ ByteCodeInstruction lins(BC_LOAD_REG_16);
+ lins.mRegister = BC_REG_TMP + iproc->mTempOffset[ins.stemp[0]];
+ lins.mRegisterFinal = ins.sfinal[0];
+ mIns.Push(lins);
+
+ this->Close(proc->CompileBlock(iproc, sblock->trueJump), proc->CompileBlock(iproc, sblock->falseJump), BC_BRANCHS_NE);
+ }
+ return;
+
+ }
+
+ i++;
+ }
+
+ this->Close(proc->CompileBlock(iproc, sblock->trueJump), nullptr, BC_JUMPS);
+}
+
+void ByteCodeBasicBlock::PeepHoleOptimizer(void)
+{
+ int accuReg = -1;
+
+ bool progress = false;
+ do {
+ progress = false;
+
+ int i = 0;
+ int j = 0;
+ while (i < mIns.Size())
+ {
+ if (mIns[i].mCode == BC_NOP)
+ ;
+ else
+ {
+ if (i != j)
+ mIns[j] = mIns[i];
+ j++;
+ }
+ i++;
+ }
+ mIns.SetSize(j);
+
+ int accuTemp = -1, addrTemp = -1;
+
+ for (int i = 0; i < mIns.Size(); i++)
+ {
+ if (i + 2 < mIns.Size())
+ {
+ if (mIns[i].mCode == BC_LOAD_LOCAL_16 &&
+ mIns[i + 1].mCode == BC_LOAD_LOCAL_16 && mIns[i + 1].mRegister != BC_REG_ACCU && mIns[i + 1].mRegister != mIns[i].mRegister &&
+ mIns[i + 2].mCode == BC_LOAD_REG_16 && mIns[i + 2].mRegister == mIns[i].mRegister && mIns[i + 2].mRegisterFinal)
+ {
+ mIns[i].mRegister = BC_REG_ACCU;
+ mIns[i + 2].mCode = BC_NOP;
+ progress = true;
+ }
+ else if (mIns[i].mCode == BC_STORE_REG_16 &&
+ !mIns[i + 1].ChangesAccu() && mIns[i + 1].mRegister != mIns[i].mRegister &&
+ mIns[i + 2].mCode == BC_LOAD_REG_16 && mIns[i].mRegister == mIns[i + 2].mRegister)
+ {
+ mIns[i + 2].mCode = BC_NOP;
+ if (mIns[i + 2].mRegisterFinal)
+ mIns[i].mCode = BC_NOP;
+ }
+ else if (mIns[i].mCode == BC_STORE_REG_32 &&
+ !mIns[i + 1].ChangesAccu() && mIns[i + 1].mRegister != mIns[i].mRegister &&
+ mIns[i + 2].mCode == BC_LOAD_REG_32 && mIns[i].mRegister == mIns[i + 2].mRegister)
+ {
+ mIns[i + 2].mCode = BC_NOP;
+ if (mIns[i + 2].mRegisterFinal)
+ mIns[i].mCode = BC_NOP;
+ }
+ else if (mIns[i].mCode == BC_STORE_REG_16 &&
+ !mIns[i + 1].ChangesAccu() && mIns[i + 1].mRegister != mIns[i].mRegister &&
+ mIns[i + 2].IsStore() && mIns[i].mRegister == mIns[i + 2].mRegister && mIns[i + 2].mRegisterFinal)
+ {
+ mIns[i].mCode = BC_NOP;
+ mIns[i + 2].mRegister = BC_REG_ACCU;
+ }
+ else if (mIns[i].mCode == BC_STORE_REG_16 &&
+ !mIns[i + 1].ChangesAddr() && mIns[i + 1].mRegister != mIns[i].mRegister &&
+ mIns[i + 2].mCode == BC_ADDR_REG && mIns[i].mRegister == mIns[i + 2].mRegister && mIns[i + 2].mRegisterFinal)
+ {
+ mIns[i].mCode = BC_ADDR_REG;
+ mIns[i].mRegister = BC_REG_ACCU;
+ mIns[i + 2].mCode = BC_NOP;
+ }
+ else if (
+ mIns[i + 2].mCode == BC_BINOP_ADDR_16 &&
+ mIns[i + 1].mCode == BC_LOAD_REG_16 && mIns[i + 1].mRegister != mIns[i + 2].mRegister &&
+ mIns[i + 0].LoadsRegister(mIns[i + 2].mRegister) && mIns[i + 2].mRegisterFinal)
+ {
+ mIns[i + 0].mRegister = BC_REG_ACCU;
+ mIns[i + 1].mCode = mIns[i + 2].mCode;
+ mIns[i + 2].mCode = BC_NOP;
+ }
+ else if (
+ mIns[i + 2].mCode == BC_BINOP_ADDR_16 &&
+ mIns[i + 1].mCode == BC_LOAD_REG_16 && mIns[i + 1].mRegister != mIns[i + 2].mRegister &&
+ mIns[i + 0].mCode == BC_STORE_REG_16 && mIns[i + 0].mRegister == mIns[i + 2].mRegister && mIns[i + 2].mRegisterFinal)
+ {
+ mIns[i + 0].mCode = BC_NOP;;
+ mIns[i + 1].mCode = mIns[i + 2].mCode;
+ mIns[i + 2].mCode = BC_NOP;
+ }
+ else if (mIns[i].mCode == BC_STORE_REG_32 &&
+ mIns[i + 1].mCode == BC_LOAD_REG_32 && mIns[i + 1].mRegister != mIns[i + 2].mRegister &&
+ mIns[i + 2].IsCommutative() && mIns[i].mRegister == mIns[i + 2].mRegister)
+ {
+ if (mIns[i + 2].mRegisterFinal)
+ mIns[i + 0].mCode = BC_NOP;
+ mIns[i + 1].mCode = BC_NOP;
+ mIns[i + 2].mRegister = mIns[i + 1].mRegister;
+ mIns[i + 2].mRegisterFinal = mIns[i + 1].mRegisterFinal;
+ }
+ else if (mIns[i].mCode == BC_STORE_REG_16 &&
+ mIns[i + 1].mCode == BC_LOAD_REG_16 && mIns[i + 1].mRegister != mIns[i + 2].mRegister &&
+ mIns[i + 2].IsCommutative() && mIns[i].mRegister == mIns[i + 2].mRegister)
+ {
+ if (mIns[i + 2].mRegisterFinal)
+ mIns[i + 0].mCode = BC_NOP;
+ mIns[i + 1].mCode = BC_NOP;
+ mIns[i + 2].mRegister = mIns[i + 1].mRegister;
+ mIns[i + 2].mRegisterFinal = mIns[i + 1].mRegisterFinal;
+ }
+ else if (mIns[i + 0].mCode == BC_STORE_REG_32 &&
+ mIns[i + 2].mCode == BC_BINOP_CMP_F32 && mIns[i + 2].mRegister == mIns[i + 0].mRegister && mIns[i + 2].mRegisterFinal &&
+ mIns[i + 1].LoadsRegister(BC_REG_ACCU) && i + 3 == mIns.Size())
+ {
+ mIns[i + 1].mRegister = mIns[i + 0].mRegister;
+ mIns[i + 0].mCode = BC_NOP;
+ branch = TransposeBranchCondition(branch);
+ }
+ }
+ if (i + 1 < mIns.Size())
+ {
+ if (mIns[i].mCode == BC_STORE_REG_16 && mIns[i + 1].mCode == BC_LOAD_REG_16 && mIns[i].mRegister == mIns[i + 1].mRegister)
+ {
+ mIns[i + 1].mCode = BC_NOP;
+ if (mIns[i + 1].mRegisterFinal)
+ mIns[i].mCode = BC_NOP;
+ progress = true;
+ }
+ else if (mIns[i].mCode == BC_LOAD_REG_16 && mIns[i + 1].mCode == BC_STORE_REG_16 && mIns[i].mRegister == mIns[i + 1].mRegister)
+ {
+ mIns[i + 1].mCode = BC_NOP;
+ progress = true;
+ }
+ else if (mIns[i].mCode == BC_STORE_REG_32 && mIns[i + 1].mCode == BC_LOAD_REG_32 && mIns[i].mRegister == mIns[i + 1].mRegister)
+ {
+ mIns[i + 1].mCode = BC_NOP;
+ if (mIns[i + 1].mRegisterFinal)
+ mIns[i].mCode = BC_NOP;
+ progress = true;
+ }
+ else if (mIns[i].mCode == BC_LOAD_REG_32 && mIns[i + 1].mCode == BC_STORE_REG_32 && mIns[i].mRegister == mIns[i + 1].mRegister)
+ {
+ mIns[i + 1].mCode = BC_NOP;
+ progress = true;
+ }
+ else if (mIns[i].mCode == BC_STORE_REG_16 && mIns[i + 1].mCode == BC_ADDR_REG && mIns[i].mRegister == mIns[i + 1].mRegister && mIns[i + 1].mRegisterFinal)
+ {
+ mIns[i].mCode = BC_ADDR_REG;
+ mIns[i].mRegister = BC_REG_ACCU;
+ mIns[i + 1].mCode = BC_NOP;
+ progress = true;
+ }
+ else if (mIns[i + 1].mCode == BC_LOAD_REG_16 && mIns[i].LoadsRegister(mIns[i + 1].mRegister) && mIns[i + 1].mRegisterFinal)
+ {
+ mIns[i].mRegister = BC_REG_ACCU;
+ mIns[i + 1].mCode = BC_NOP;
+ progress = true;
+ }
+ else if (mIns[i + 1].mCode == BC_LOAD_REG_32 && mIns[i].LoadsRegister(mIns[i + 1].mRegister) && mIns[i + 1].mRegisterFinal)
+ {
+ mIns[i].mRegister = BC_REG_ACCU;
+ mIns[i + 1].mCode = BC_NOP;
+ progress = true;
+ }
+ else if (mIns[i].mCode == BC_STORE_REG_16 && mIns[i + 1].StoresRegister(mIns[i].mRegister) && mIns[i + 1].mRegisterFinal)
+ {
+ mIns[i + 1].mRegister = BC_REG_ACCU;
+ mIns[i].mCode = BC_NOP;
+ progress = true;
+ }
+ else if (mIns[i].mCode == BC_STORE_REG_32 && mIns[i + 1].StoresRegister(mIns[i].mRegister) && mIns[i + 1].mRegisterFinal)
+ {
+ mIns[i + 1].mRegister = BC_REG_ACCU;
+ mIns[i].mCode = BC_NOP;
+ progress = true;
+ }
+ else if (mIns[i + 1].mCode == BC_LOAD_REG_32 && mIns[i].LoadsRegister(mIns[i + 1].mRegister) && mIns[i + 1].mRegisterFinal)
+ {
+ mIns[i].mRegister = BC_REG_ACCU;
+ mIns[i + 1].mCode = BC_NOP;
+ progress = true;
+ }
+ }
+
+ if ((mIns[i].mCode == BC_LOAD_REG_16 || mIns[i].mCode == BC_STORE_REG_16 || mIns[i].mCode == BC_LOAD_REG_32 || mIns[i].mCode == BC_STORE_REG_32) && accuTemp == mIns[i].mRegister)
+ mIns[i].mCode = BC_NOP;
+ if (mIns[i].mCode == BC_ADDR_REG && mIns[i].mRegister == addrTemp)
+ mIns[i].mCode = BC_NOP;
+
+ if (mIns[i].ChangesAccu())
+ accuTemp = -1;
+ if (mIns[i].ChangesAddr())
+ addrTemp = -1;
+ if (accuTemp != -1 && mIns[i].ChangesRegister(accuTemp))
+ accuTemp = -1;
+ if (addrTemp != -1 && mIns[i].ChangesRegister(addrTemp))
+ addrTemp = -1;
+
+ if (mIns[i].mCode == BC_LOAD_REG_16 || mIns[i].mCode == BC_STORE_REG_16 || mIns[i].mCode == BC_LOAD_REG_32 || mIns[i].mCode == BC_STORE_REG_32)
+ accuTemp = mIns[i].mRegister;
+ if (mIns[i].mCode == BC_ADDR_REG && mIns[i].mRegister != BC_REG_ACCU)
+ addrTemp = mIns[i].mRegister;
+ }
+ } while (progress);
+}
+
+void ByteCodeBasicBlock::Assemble(ByteCodeGenerator* generator)
+{
+ if (!mAssembled)
+ {
+ mAssembled = true;
+
+ PeepHoleOptimizer();
+
+ for (int i = 0; i < mIns.Size(); i++)
+ mIns[i].Assemble(generator, this);
+
+ if (this->trueJump)
+ this->trueJump->Assemble(generator);
+ if (this->falseJump)
+ this->falseJump->Assemble(generator);
+ }
+}
+
+void ByteCodeBasicBlock::Close(ByteCodeBasicBlock* trueJump, ByteCodeBasicBlock* falseJump, ByteCode branch)
+{
+ this->trueJump = this->trueLink = trueJump;
+ this->falseJump = this->falseLink = falseJump;
+ this->branch = branch;
+}
+
+static int BranchByteSize(int from, int to)
+{
+ if (to - from >= -126 && to - from <= 129)
+ return 2;
+ else
+ return 3;
+}
+
+static int JumpByteSize(int from, int to)
+{
+ if (to - from >= -126 && to - from <= 129)
+ return 2;
+ else
+ return 3;
+}
+
+ByteCodeBasicBlock* ByteCodeBasicBlock::BypassEmptyBlocks(void)
+{
+ if (bypassed)
+ return this;
+ else if (!falseJump && code.Size() == 0)
+ return trueJump->BypassEmptyBlocks();
+ else
+ {
+ bypassed = true;
+
+ if (falseJump)
+ falseJump = falseJump->BypassEmptyBlocks();
+ if (trueJump)
+ trueJump = trueJump->BypassEmptyBlocks();
+
+ return this;
+ }
+}
+
+void ByteCodeBasicBlock::CopyCode(ByteCodeGenerator* generator, uint8 * target)
+{
+ int i;
+ int next;
+ int pos, at;
+ uint8 b;
+
+ if (!copied)
+ {
+ copied = true;
+
+ for (int i = 0; i < mRelocations.Size(); i++)
+ {
+ ByteCodeRelocation rl = mRelocations[i];
+ rl.mAddr += target - generator->mMemory + mOffset;
+ generator->mRelocations.Push(rl);
+ }
+
+ next = mOffset + code.Size();
+
+ if (falseJump)
+ {
+ if (falseJump->mOffset <= mOffset)
+ {
+ if (trueJump->mOffset <= mOffset)
+ {
+ next += PutBranch(generator, branch, trueJump->mOffset - next);
+ next += PutBranch(generator, BC_JUMPS, falseJump->mOffset - next);
+
+ }
+ else
+ {
+ next += PutBranch(generator, InvertBranchCondition(branch), falseJump->mOffset - next);
+ }
+ }
+ else
+ {
+ next += PutBranch(generator, branch, trueJump->mOffset - next);
+ }
+ }
+ else if (trueJump)
+ {
+ if (trueJump->mOffset != next)
+ {
+ next += PutBranch(generator, BC_JUMPS, trueJump->mOffset - next);
+ }
+ }
+
+ assert(next - mOffset == mSize);
+
+ for (i = 0; i < code.Size(); i++)
+ {
+ code.Lookup(i, target[i + mOffset]);
+ }
+
+ if (trueJump) trueJump->CopyCode(generator, target);
+ if (falseJump) falseJump->CopyCode(generator, target);
+ }
+}
+
+void ByteCodeBasicBlock::CalculateOffset(int& total)
+{
+ int next;
+
+ if (mOffset > total)
+ {
+ mOffset = total;
+ next = total + code.Size();
+
+ if (falseJump)
+ {
+ if (falseJump->mOffset <= total)
+ {
+ // falseJump has been placed
+
+ if (trueJump->mOffset <= total)
+ {
+ // trueJump and falseJump have been placed, not much to do
+
+ next = next + BranchByteSize(next, trueJump->mOffset);
+ total = next + JumpByteSize(next, falseJump->mOffset);
+ mSize = total - mOffset;
+ }
+ else
+ {
+ // trueJump has not been placed, but falseJump has
+
+ total = next + BranchByteSize(next, falseJump->mOffset);
+ mSize = total - mOffset;
+ trueJump->CalculateOffset(total);
+ }
+ }
+ else if (trueJump->mOffset <= total)
+ {
+ // falseJump has not been placed, but trueJump has
+
+ total = next + BranchByteSize(next, trueJump->mOffset);
+ mSize = total - mOffset;
+ falseJump->CalculateOffset(total);
+ }
+ else if (knownShortBranch)
+ {
+ // neither falseJump nor trueJump have been placed,
+ // but we know from previous iteration that we can do
+ // a short branch
+
+ total = next + 2;
+ mSize = total - mOffset;
+
+ falseJump->CalculateOffset(total);
+ if (trueJump->mOffset > total)
+ {
+ // trueJump was not placed in the process, so lets place it now
+ trueJump->CalculateOffset(total);
+ }
+ }
+ else
+ {
+ // neither falseJump nor trueJump have been placed
+ // this may lead to some undo operation...
+ // first assume a full size branch:
+
+ total = next + 3;
+ mSize = total - mOffset;
+
+ falseJump->CalculateOffset(total);
+ if (trueJump->mOffset > total)
+ {
+ // trueJump was not placed in the process, so lets place it now
+
+ trueJump->CalculateOffset(total);
+ }
+
+ if (BranchByteSize(next, trueJump->mOffset) < 3)
+ {
+ // oh, we can replace by a short branch
+
+ knownShortBranch = true;
+
+ total = next + 2;
+ mSize = total - mOffset;
+
+ falseJump->CalculateOffset(total);
+ if (trueJump->mOffset > total)
+ {
+ // trueJump was not placed in the process, so lets place it now
+
+ trueJump->CalculateOffset(total);
+ }
+ }
+ }
+ }
+ else if (trueJump)
+ {
+ if (trueJump->mOffset <= total)
+ {
+ // trueJump has been placed, so append the branch size
+
+ total = next + JumpByteSize(next, trueJump->mOffset);
+ mSize = total - mOffset;
+ }
+ else
+ {
+ // we have to place trueJump, so just put it right behind us
+
+ total = next;
+ mSize = total - mOffset;
+
+ trueJump->CalculateOffset(total);
+ }
+ }
+ else
+ {
+ // no exit from block
+
+ total += code.Size();
+ mSize = total - mOffset;
+ }
+ }
+}
+
+ByteCodeProcedure::ByteCodeProcedure(void)
+{
+}
+
+ByteCodeProcedure::~ByteCodeProcedure(void)
+{
+}
+
+
+
+void ByteCodeProcedure::Compile(ByteCodeGenerator* generator, InterCodeProcedure* proc)
+{
+ tblocks = new ByteCodeBasicBlock * [proc->blocks.Size()];
+ for (int i = 0; i < proc->blocks.Size(); i++)
+ tblocks[i] = nullptr;
+
+ int tempSave = proc->mTempSize > 16 ? proc->mTempSize - 16 : 0;
+
+ entryBlock = new ByteCodeBasicBlock();
+ entryBlock->PutCode(generator, BC_ENTER); entryBlock->PutWord(proc->mLocalSize + 2 + tempSave); entryBlock->PutByte(tempSave);
+
+ if (!proc->mLeafProcedure)
+ {
+ entryBlock->PutCode(generator, BC_PUSH_FRAME);
+ entryBlock->PutWord(uint16(proc->mCommonFrameSize + 2));
+ }
+
+ tblocks[0] = entryBlock;
+
+ exitBlock = new ByteCodeBasicBlock();
+
+ if (!proc->mLeafProcedure)
+ {
+ exitBlock->PutCode(generator, BC_POP_FRAME);
+ exitBlock->PutWord(uint16(proc->mCommonFrameSize + 2));
+ }
+ exitBlock->PutCode(generator, BC_RETURN); exitBlock->PutByte(tempSave); exitBlock->PutWord(proc->mLocalSize + 2 + tempSave);
+
+ entryBlock->Compile(proc, this, proc->blocks[0]);
+ entryBlock->Assemble(generator);
+
+ int total;
+
+ ByteCodeBasicBlock* lentryBlock = entryBlock->BypassEmptyBlocks();
+
+ total = 0;
+
+ lentryBlock->CalculateOffset(total);
+
+ generator->AddAddress(proc->mID, true, generator->mProgEnd, total, proc->mIdent, false);
+
+ mProgStart = generator->mProgEnd;
+ lentryBlock->CopyCode(generator, generator->mMemory + generator->mProgEnd);
+ mProgSize = total;
+
+ generator->mProgEnd += total;
+}
+
+ByteCodeBasicBlock* ByteCodeProcedure::CompileBlock(InterCodeProcedure* iproc, InterCodeBasicBlock* sblock)
+{
+ if (tblocks[sblock->num])
+ return tblocks[sblock->num];
+
+ ByteCodeBasicBlock * block = new ByteCodeBasicBlock();
+ tblocks[sblock->num] = block;
+ block->Compile(iproc, this, sblock);
+
+ return block;
+}
+
+const char* ByteCodeProcedure::TempName(uint8 tmp, char* buffer, InterCodeProcedure* proc)
+{
+ if (tmp == BC_REG_ADDR)
+ return "ADDR";
+ else if (tmp == BC_REG_ACCU)
+ return "ACCU";
+ else if (tmp >= BC_REG_TMP && tmp < BC_REG_TMP + proc->mTempSize)
+ {
+ int i = 0;
+ while (i + 1 < proc->mTempOffset.Size() && proc->mTempOffset[i + 1] <= tmp - BC_REG_TMP)
+ i++;
+ sprintf_s(buffer, 10, "T%d", i);
+ return buffer;
+ }
+ else
+ {
+ sprintf_s(buffer, 10, "$%02x", tmp);
+ return buffer;
+ }
+}
+
+
+void ByteCodeProcedure::Disassemble(FILE * file, ByteCodeGenerator * generator, InterCodeProcedure * proc)
+{
+ fprintf(file, "--------------------------------------------------------------------\n");
+ if (proc->mIdent)
+ fprintf(file, "%s:\n", proc->mIdent->mString);
+
+ char tbuffer[10];
+
+ int i = 0;
+ while (i < mProgSize)
+ {
+ ByteCode bc = ByteCode(generator->mMemory[mProgStart + i] / 2);
+
+ fprintf(file, "%04x:\t", mProgStart + i);
+ i++;
+
+ switch (bc)
+ {
+ case BC_NOP:
+ fprintf(file, "NOP");
+ break;
+ case BC_EXIT:
+ fprintf(file, "EXIT");
+ break;
+
+ case BC_CONST_P8:
+ fprintf(file, "MOV\t%s, #%d", TempName(generator->mMemory[mProgStart + i], tbuffer, proc), generator->mMemory[mProgStart + i + 1]);
+ i += 2;
+ break;
+ case BC_CONST_N8:
+ fprintf(file, "MOV\t%s, #%d", TempName(generator->mMemory[mProgStart + i], tbuffer, proc), int(generator->mMemory[mProgStart + i + 1]) - 0x100);
+ i += 2;
+ break;
+ case BC_CONST_16:
+ fprintf(file, "MOV\t%s, #$%04x", TempName(generator->mMemory[mProgStart + i], tbuffer, proc), uint16(generator->mMemory[mProgStart + i + 1] + 256 * generator->mMemory[mProgStart + i + 2]));
+ i += 3;
+ break;
+ case BC_CONST_32:
+ fprintf(file, "MOVD\t%s, #$%08x", TempName(generator->mMemory[mProgStart + i], tbuffer, proc), uint32(generator->mMemory[mProgStart + i + 1] + 256 * generator->mMemory[mProgStart + i + 2] + 0x10000 * generator->mMemory[mProgStart + i + 3] + 0x1000000 * generator->mMemory[mProgStart + i + 4]));
+ i += 5;
+ break;
+
+ case BC_LOAD_REG_16:
+ fprintf(file, "MOV\tACCU, %s", TempName(generator->mMemory[mProgStart + i], tbuffer, proc));
+ i += 1;
+ break;
+ case BC_STORE_REG_16:
+ fprintf(file, "MOV\t%s, ACCU", TempName(generator->mMemory[mProgStart + i], tbuffer, proc));
+ i += 1;
+ break;
+ case BC_LOAD_REG_32:
+ fprintf(file, "MOVD\tACCU, %s", TempName(generator->mMemory[mProgStart + i], tbuffer, proc));
+ i += 1;
+ break;
+ case BC_STORE_REG_32:
+ fprintf(file, "MOVD\t%s, ACCU", TempName(generator->mMemory[mProgStart + i], tbuffer, proc));
+ i += 1;
+ break;
+ case BC_ADDR_REG:
+ fprintf(file, "MOV\tADDR, %s", TempName(generator->mMemory[mProgStart + i], tbuffer, proc));
+ i += 1;
+ break;
+
+ case BC_LOAD_ABS_U8:
+ fprintf(file, "MOVUB\t%s, $%04x", TempName(generator->mMemory[mProgStart + i + 2], tbuffer, proc), uint16(generator->mMemory[mProgStart + i + 0] + 256 * generator->mMemory[mProgStart + i + 1]));
+ i += 3;
+ break;
+ case BC_LOAD_ABS_I8:
+ fprintf(file, "MOVSB\t%s, $%04x", TempName(generator->mMemory[mProgStart + i + 2], tbuffer, proc), uint16(generator->mMemory[mProgStart + i + 0] + 256 * generator->mMemory[mProgStart + i + 1]));
+ i += 3;
+ break;
+ case BC_LOAD_ABS_16:
+ fprintf(file, "MOV\t%s, $%04x", TempName(generator->mMemory[mProgStart + i + 2], tbuffer, proc), uint16(generator->mMemory[mProgStart + i + 0] + 256 * generator->mMemory[mProgStart + i + 1]));
+ i += 3;
+ break;
+ case BC_LOAD_ABS_32:
+ fprintf(file, "MOVD\t%s, $%04x", TempName(generator->mMemory[mProgStart + i + 2], tbuffer, proc), uint16(generator->mMemory[mProgStart + i + 0] + 256 * generator->mMemory[mProgStart + i + 1]));
+ i += 3;
+ break;
+
+ case BC_LEA_ABS:
+ fprintf(file, "LEA\t%s, $%04x", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc), uint16(generator->mMemory[mProgStart + i + 1] + 256 * generator->mMemory[mProgStart + i + 2]));
+ i += 3;
+ break;
+
+ case BC_STORE_ABS_8:
+ fprintf(file, "MOVB\t$%04x, %s", uint16(generator->mMemory[mProgStart + i + 0] + 256 * generator->mMemory[mProgStart + i + 1]), TempName(generator->mMemory[mProgStart + i + 2], tbuffer, proc));
+ i += 3;
+ break;
+ case BC_STORE_ABS_16:
+ fprintf(file, "MOV\t$%04x, %s", uint16(generator->mMemory[mProgStart + i + 0] + 256 * generator->mMemory[mProgStart + i + 1]), TempName(generator->mMemory[mProgStart + i + 2], tbuffer, proc));
+ i += 3;
+ break;
+ case BC_STORE_ABS_32:
+ fprintf(file, "MOVD\t$%04x, %s", uint16(generator->mMemory[mProgStart + i + 0] + 256 * generator->mMemory[mProgStart + i + 1]), TempName(generator->mMemory[mProgStart + i + 2], tbuffer, proc));
+ i += 3;
+ break;
+
+ case BC_LOAD_LOCAL_U8:
+ fprintf(file, "MOVUB\t%s, %d(FP)", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc), generator->mMemory[mProgStart + i + 1]);
+ i += 2;
+ break;
+ case BC_LOAD_LOCAL_I8:
+ fprintf(file, "MOVSB\t%s, %d(FP)", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc), generator->mMemory[mProgStart + i + 1]);
+ i += 2;
+ break;
+ case BC_LOAD_LOCAL_16:
+ fprintf(file, "MOV\t%s, %d(FP)", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc), generator->mMemory[mProgStart + i + 1]);
+ i += 2;
+ break;
+ case BC_LOAD_LOCAL_32:
+ fprintf(file, "MOVD\t%s, %d(FP)", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc), generator->mMemory[mProgStart + i + 1]);
+ i += 2;
+ break;
+
+ case BC_STORE_LOCAL_8:
+ fprintf(file, "MOVB\t%d(FP), %s", generator->mMemory[mProgStart + i + 1], TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i += 2;
+ break;
+ case BC_STORE_LOCAL_16:
+ fprintf(file, "MOV\t%d(FP), %s", generator->mMemory[mProgStart + i + 1], TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i += 2;
+ break;
+ case BC_STORE_LOCAL_32:
+ fprintf(file, "MOVD\t%d(FP), %s", generator->mMemory[mProgStart + i + 1], TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i += 2;
+ break;
+
+ case BC_LEA_LOCAL:
+ fprintf(file, "LEA\t%s, %d(FP)", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc), uint16(generator->mMemory[mProgStart + i + 1] + 256 * generator->mMemory[mProgStart + i + 2]));
+ i += 3;
+ break;
+
+ case BC_STORE_FRAME_8:
+ fprintf(file, "MOVB\t%d(SP), %s", generator->mMemory[mProgStart + i + 1], TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i += 2;
+ break;
+ case BC_STORE_FRAME_16:
+ fprintf(file, "MOV\t%d(SP), %s", generator->mMemory[mProgStart + i + 1], TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i += 2;
+ break;
+ case BC_STORE_FRAME_32:
+ fprintf(file, "MOVD\t%d(SP), %s", generator->mMemory[mProgStart + i + 1], TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i += 2;
+ break;
+
+ case BC_BINOP_ADDR_16:
+ fprintf(file, "ADD\tACCU, %s", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i += 1;
+ break;
+ case BC_BINOP_SUBR_16:
+ fprintf(file, "SUB\tACCU, %s", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i += 1;
+ break;
+ case BC_BINOP_MULR_16:
+ fprintf(file, "MUL\tACCU, %s", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i += 1;
+ break;
+ case BC_BINOP_DIVR_U16:
+ fprintf(file, "DIVU\tACCU, %s", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i += 1;
+ break;
+ case BC_BINOP_MODR_U16:
+ fprintf(file, "MODU\tACCU, %s", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i += 1;
+ break;
+ case BC_BINOP_DIVR_I16:
+ fprintf(file, "DIVS\tACCU, %s", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i += 1;
+ break;
+ case BC_BINOP_MODR_I16:
+ fprintf(file, "MODS\tACCU, %s", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i += 1;
+ break;
+ case BC_BINOP_ANDR_16:
+ fprintf(file, "AND\tACCU, %s", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i += 1;
+ break;
+ case BC_BINOP_ORR_16:
+ fprintf(file, "OR\tACCU, %s", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i += 1;
+ break;
+ case BC_BINOP_XORR_16:
+ fprintf(file, "XOR\tACCU, %s", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i += 1;
+ break;
+ case BC_BINOP_SHLR_16:
+ fprintf(file, "SHL\tACCU, %s", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i += 1;
+ break;
+ case BC_BINOP_SHRR_I16:
+ fprintf(file, "SHRU\tACCU, %s", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i += 1;
+ break;
+ case BC_BINOP_SHRR_U16:
+ fprintf(file, "SHRI\tACCU, %s", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i += 1;
+ break;
+
+ case BC_BINOP_ADDI_16:
+ fprintf(file, "ADD\t%s, #$%04X", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc), uint16(generator->mMemory[mProgStart + i + 1] + 256 * generator->mMemory[mProgStart + i + 2]));
+ i += 3;
+ break;
+ case BC_BINOP_SUBI_16:
+ fprintf(file, "SUBR\t%s, #$%04X", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc), uint16(generator->mMemory[mProgStart + i + 1] + 256 * generator->mMemory[mProgStart + i + 2]));
+ i += 3;
+ break;
+ case BC_BINOP_ANDI_16:
+ fprintf(file, "AND\t%s, #$%04X", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc), uint16(generator->mMemory[mProgStart + i + 1] + 256 * generator->mMemory[mProgStart + i + 2]));
+ i += 3;
+ break;
+ case BC_BINOP_ORI_16:
+ fprintf(file, "OR\t%s, #$%04X", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc), uint16(generator->mMemory[mProgStart + i + 1] + 256 * generator->mMemory[mProgStart + i + 2]));
+ i += 3;
+ break;
+ case BC_BINOP_MULI8_16:
+ fprintf(file, "MUL\t%s, #%d", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc), generator->mMemory[mProgStart + i + 1]);
+ i += 2;
+ break;
+
+ case BC_BINOP_SHLI_16:
+ fprintf(file, "SHL\tACCU, #%d", uint8(generator->mMemory[mProgStart + i + 0]));
+ i += 1;
+ break;
+ case BC_BINOP_SHRI_U16:
+ fprintf(file, "SHRU\tACCU, #%d", uint8(generator->mMemory[mProgStart + i + 0]));
+ i += 1;
+ break;
+ case BC_BINOP_SHRI_I16:
+ fprintf(file, "SHRS\tACCU, #%d", uint8(generator->mMemory[mProgStart + i + 0]));
+ i += 1;
+ break;
+
+ case BC_BINOP_CMPUR_16:
+ fprintf(file, "CMPU\tACCU, %s", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i += 1;
+ break;
+ case BC_BINOP_CMPSR_16:
+ fprintf(file, "CMPS\tACCU, %s", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i += 1;
+ break;
+
+ case BC_BINOP_CMPUI_16:
+ fprintf(file, "CMPU\tACCU, #$%04X", uint16(generator->mMemory[mProgStart + i + 0] + 256 * generator->mMemory[mProgStart + i + 1]));
+ i += 2;
+ break;
+ case BC_BINOP_CMPSI_16:
+ fprintf(file, "CMPS\tACCU, #$%04X", uint16(generator->mMemory[mProgStart + i + 0] + 256 * generator->mMemory[mProgStart + i + 1]));
+ i += 2;
+ break;
+
+ case BC_BINOP_ADD_F32:
+ fprintf(file, "ADDF\tACCU, %s", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i += 1;
+ break;
+ case BC_BINOP_SUB_F32:
+ fprintf(file, "SUBF\tACCU, %s", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i += 1;
+ break;
+ case BC_BINOP_MUL_F32:
+ fprintf(file, "MULF\tACCU, %s", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i += 1;
+ break;
+ case BC_BINOP_DIV_F32:
+ fprintf(file, "DIVF\tACCU, %s", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i += 1;
+ break;
+ case BC_BINOP_CMP_F32:
+ fprintf(file, "CMPF\tACCU, %s", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i += 1;
+ break;
+
+ case BC_COPY:
+ fprintf(file, "COPY\t#%d", generator->mMemory[mProgStart + i + 0]);
+ i++;
+ break;
+
+ case BC_COPY_LONG:
+ fprintf(file, "COPYL\t#%d", uint16(generator->mMemory[mProgStart + i + 0] + 256 * generator->mMemory[mProgStart + i + 1]));
+ i += 2;
+ break;
+
+ case BC_OP_NEGATE_16:
+ fprintf(file, "NEG\tACCU");
+ break;
+ case BC_OP_INVERT_16:
+ fprintf(file, "NOT\tACCU");
+ break;
+
+ case BC_OP_NEGATE_F32:
+ fprintf(file, "NEGF\tACCU");
+ break;
+ case BC_OP_ABS_F32:
+ fprintf(file, "ABSF\tACCU");
+ break;
+ case BC_OP_FLOOR_F32:
+ fprintf(file, "FLOORF\tACCU");
+ break;
+ case BC_OP_CEIL_F32:
+ fprintf(file, "CEILF\tACCU");
+ break;
+
+
+ case BC_CONV_U16_F32:
+ fprintf(file, "CNVUF\tACCU");
+ break;
+ case BC_CONV_I16_F32:
+ fprintf(file, "CNVSF\tACCU");
+ break;
+ case BC_CONV_F32_U16:
+ fprintf(file, "CNVFU\tACCU");
+ break;
+ case BC_CONV_F32_I16:
+ fprintf(file, "CNVFS\tACCU");
+ break;
+
+ case BC_JUMPS:
+ fprintf(file, "JUMP\t$%04X", mProgStart + i + 1 + int8(generator->mMemory[mProgStart + i + 0]));
+ i++;
+ break;
+ case BC_BRANCHS_EQ:
+ fprintf(file, "BEQ\t$%04X", mProgStart + i + 1 + int8(generator->mMemory[mProgStart + i + 0]));
+ i++;
+ break;
+ case BC_BRANCHS_NE:
+ fprintf(file, "BNE\t$%04X", mProgStart + i + 1 + int8(generator->mMemory[mProgStart + i + 0]));
+ i++;
+ break;
+ case BC_BRANCHS_GT:
+ fprintf(file, "BGT\t$%04X", mProgStart + i + 1 + int8(generator->mMemory[mProgStart + i + 0]));
+ i++;
+ break;
+ case BC_BRANCHS_GE:
+ fprintf(file, "BGE\t$%04X", mProgStart + i + 1 + int8(generator->mMemory[mProgStart + i + 0]));
+ i++;
+ break;
+ case BC_BRANCHS_LT:
+ fprintf(file, "BLT\t$%04X", mProgStart + i + 1 + int8(generator->mMemory[mProgStart + i + 0]));
+ i++;
+ break;
+ case BC_BRANCHS_LE:
+ fprintf(file, "BLE\t$%04X", mProgStart + i + 1 + int8(generator->mMemory[mProgStart + i + 0]));
+ i++;
+ break;
+
+ case BC_JUMPF:
+ fprintf(file, "JUMPF\t$%04X", mProgStart + i + 2 + int16(generator->mMemory[mProgStart + i + 0] + 256 * generator->mMemory[mProgStart + i + 1]));
+ i += 2;
+ break;
+ case BC_BRANCHF_EQ:
+ fprintf(file, "BEQF\t$%04X", mProgStart + i + 2 + int16(generator->mMemory[mProgStart + i + 0] + 256 * generator->mMemory[mProgStart + i + 1]));
+ i += 2;
+ break;
+ case BC_BRANCHF_NE:
+ fprintf(file, "BNEF\t$%04X", mProgStart + i + 2 + int16(generator->mMemory[mProgStart + i + 0] + 256 * generator->mMemory[mProgStart + i + 1]));
+ i += 2;
+ break;
+ case BC_BRANCHF_GT:
+ fprintf(file, "BGTF\t$%04X", mProgStart + i + 2 + int16(generator->mMemory[mProgStart + i + 0] + 256 * generator->mMemory[mProgStart + i + 1]));
+ i += 2;
+ break;
+ case BC_BRANCHF_GE:
+ fprintf(file, "BGEF\t$%04X", mProgStart + i + 2 + int16(generator->mMemory[mProgStart + i + 0] + 256 * generator->mMemory[mProgStart + i + 1]));
+ i += 2;
+ break;
+ case BC_BRANCHF_LT:
+ fprintf(file, "BLTF\t$%04X", mProgStart + i + 2 + int16(generator->mMemory[mProgStart + i + 0] + 256 * generator->mMemory[mProgStart + i + 1]));
+ i += 2;
+ break;
+ case BC_BRANCHF_LE:
+ fprintf(file, "BLEF\t$%04X", mProgStart + i + 2 + int16(generator->mMemory[mProgStart + i + 0] + 256 * generator->mMemory[mProgStart + i + 1]));
+ i += 2;
+ break;
+
+ case BC_SET_EQ:
+ fprintf(file, "SEQ");
+ break;
+ case BC_SET_NE:
+ fprintf(file, "SNE");
+ break;
+ case BC_SET_GT:
+ fprintf(file, "SGT");
+ break;
+ case BC_SET_GE:
+ fprintf(file, "SGE");
+ break;
+ case BC_SET_LT:
+ fprintf(file, "SLT");
+ break;
+ case BC_SET_LE:
+ fprintf(file, "SLE");
+ break;
+
+ case BC_ENTER:
+ fprintf(file, "ENTER\t%d, %d", generator->mMemory[mProgStart + i + 2], uint16(generator->mMemory[mProgStart + i + 0] + 256 * generator->mMemory[mProgStart + i + 1]));
+ i += 3;
+ break;
+ case BC_RETURN:
+ fprintf(file, "RETURN\t%d, %d", generator->mMemory[mProgStart + i], uint16(generator->mMemory[mProgStart + i + 1] + 256 * generator->mMemory[mProgStart + i + 2]));
+ i += 3;
+ break;
+ case BC_CALL:
+ fprintf(file, "CALL");
+ break;
+ case BC_JSR:
+ fprintf(file, "JSR\t$%04x", uint16(generator->mMemory[mProgStart + i + 0] + 256 * generator->mMemory[mProgStart + i + 1]));
+ i += 2;
+ break;
+
+ case BC_PUSH_FRAME:
+ fprintf(file, "PUSH\t#$%04X", uint16(generator->mMemory[mProgStart + i + 0] + 256 * generator->mMemory[mProgStart + i + 1]));
+ i += 2;
+ break;
+
+ case BC_POP_FRAME:
+ fprintf(file, "POP\t#$%04X", uint16(generator->mMemory[mProgStart + i + 0] + 256 * generator->mMemory[mProgStart + i + 1]));
+ i += 2;
+ break;
+
+ case BC_LOAD_ADDR_U8:
+ fprintf(file, "MOVUB\t%s, (ADDR)", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i++;
+ break;
+ case BC_LOAD_ADDR_I8:
+ fprintf(file, "MOVSB\t%s, (ADDR)", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i++;
+ break;
+ case BC_LOAD_ADDR_16:
+ fprintf(file, "MOV\t%s, (ADDR)", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i++;
+ break;
+ case BC_LOAD_ADDR_32:
+ fprintf(file, "MOVD\t%s, (ADDR)", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i++;
+ break;
+
+ case BC_STORE_ADDR_8:
+ fprintf(file, "MOVB\t(ADDR), %s", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i++;
+ break;
+ case BC_STORE_ADDR_16:
+ fprintf(file, "MOV\t(ADDR), %s", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i++;
+ break;
+ case BC_STORE_ADDR_32:
+ fprintf(file, "MOV\t(ADDR), %s", TempName(generator->mMemory[mProgStart + i + 0], tbuffer, proc));
+ i++;
+ break;
+
+ }
+
+ fprintf(file, "\n");
+ }
+}
+
+ByteCodeGenerator::ByteCodeGenerator(void)
+ : mProcedureAddr({ 0 }), mGlobalAddr({ 0 }), mRelocations({ 0 })
+{
+ mProgStart = mProgEnd = 0x0801;
+ for (int i = 0; i < 128; i++)
+ mByteCodeUsed[i] = false;
+}
+
+ByteCodeGenerator::~ByteCodeGenerator(void)
+{
+}
+
+int ByteCodeGenerator::AddGlobal(int index, const Ident* ident, int size, const uint8* data, bool assembler)
+{
+ int addr = mProgEnd;
+
+ AddAddress(index, false, addr, size, ident, assembler);
+
+ if (data)
+ {
+ for (int i = 0; i < size; i++)
+ mMemory[mProgEnd + i] = data[i];
+ }
+ else
+ {
+ for (int i = 0; i < size; i++)
+ mMemory[mProgEnd + i] = 0;
+ }
+
+ mProgEnd += size;
+
+ return addr;
+}
+
+void ByteCodeGenerator::AddAddress(int index, bool function, int address, int size, const Ident* ident, bool assembler)
+{
+ Address addr;
+ addr.mIndex = index;
+ addr.mFunction = function;
+ addr.mAddress = address;
+ addr.mSize = size;
+ addr.mIdent = ident;
+ addr.mAssembler = assembler;
+ if (function)
+ mProcedureAddr[index] = addr;
+ else
+ mGlobalAddr[index] = addr;
+}
+
+
+void ByteCodeGenerator::WriteBasicHeader(void)
+{
+ mMemory[mProgEnd++] = 0x0b;
+ mMemory[mProgEnd++] = 0x08;
+ mMemory[mProgEnd++] = 0x0a;
+ mMemory[mProgEnd++] = 0x00;
+ mMemory[mProgEnd++] = 0x9e;
+ mMemory[mProgEnd++] = 0x32;
+ mMemory[mProgEnd++] = 0x30;
+ mMemory[mProgEnd++] = 0x36;
+ mMemory[mProgEnd++] = 0x31;
+ mMemory[mProgEnd++] = 0x00;
+ mMemory[mProgEnd++] = 0x00;
+ mMemory[mProgEnd++] = 0x00;
+}
+
+void ByteCodeGenerator::SetBasicEntry(int index)
+{
+ mProgEntry = index;
+}
+
+void ByteCodeGenerator::WriteByteCodeHeader(void)
+{
+ int n = mProgEnd + 6;
+
+ mMemory[mProgEnd++] = BC_LEA_ABS * 2;
+ mMemory[mProgEnd++] = BC_REG_ADDR;
+ mMemory[mProgEnd++] = n & 255;
+ mMemory[mProgEnd++] = n >> 8;
+ mMemory[mProgEnd++] = BC_CALL * 2;
+ mMemory[mProgEnd++] = BC_EXIT * 2;
+
+ mByteCodeUsed[BC_LEA_ABS] = true;
+ mByteCodeUsed[BC_CALL] = true;
+ mByteCodeUsed[BC_EXIT] = true;
+}
+
+void ByteCodeGenerator::ResolveRelocations(void)
+{
+ for (int i = 0; i < mRelocations.Size(); i++)
+ {
+ int dp = mRelocations[i].mAddr;
+ int sp;
+ if (mRelocations[i].mFunction)
+ sp = mProcedureAddr[mRelocations[i].mIndex].mAddress + mRelocations[i].mOffset;
+ else
+ sp = mGlobalAddr[mRelocations[i].mIndex].mAddress + mRelocations[i].mOffset;
+ if (mRelocations[i].mLower)
+ mMemory[dp++] = sp & 255;
+ if (mRelocations[i].mUpper)
+ mMemory[dp++] = sp >> 8;
+ }
+
+ int entry = mGlobalAddr[mProgEntry].mAddress;
+
+ mMemory[mProgStart + 5] = (entry / 1000) % 10 + '0';
+ mMemory[mProgStart + 6] = (entry / 100) % 10 + '0';
+ mMemory[mProgStart + 7] = (entry / 10) % 10 + '0';
+ mMemory[mProgStart + 8] = entry % 10 + '0';
+}
+
+bool ByteCodeGenerator::WritePRGFile(const char* filename)
+{
+ FILE* file;
+ fopen_s(&file, filename, "wb");
+ if (file)
+ {
+ mMemory[mProgStart - 2] = mProgStart & 0xff;
+ mMemory[mProgStart - 1] = mProgStart >> 8;
+
+ int done = fwrite(mMemory + mProgStart - 2, 1, mProgEnd - mProgStart + 2, file);
+ fclose(file);
+ return done == mProgEnd - mProgStart + 2;
+ }
+ else
+ return false;
+}
+
+void ByteCodeGenerator::WriteAsmFile(FILE* file)
+{
+ for (int i = 0; i < mGlobalAddr.Size(); i++)
+ {
+ if (mGlobalAddr[i].mAssembler)
+ {
+ fprintf(file, "--------------------------------------------------------------------\n");
+ if (mGlobalAddr[i].mIdent)
+ fprintf(file, "%s:\n", mGlobalAddr[i].mIdent->mString);
+
+ int ip = mGlobalAddr[i].mAddress;
+ while (ip < mGlobalAddr[i].mAddress + mGlobalAddr[i].mSize)
+ {
+ int iip = ip;
+ uint8 opcode = mMemory[ip++];
+ AsmInsData d = DecInsData[opcode];
+ int addr = 0;
+
+ switch (d.mMode)
+ {
+ case ASMIM_IMPLIED:
+ fprintf(file, "%04x : %04x %02x __ __ %s\n", iip, ip, mMemory[ip], AsmInstructionNames[d.mType]);
+ break;
+ case ASMIM_IMMEDIATE:
+ addr = mMemory[ip++];
+ fprintf(file, "%04x : %04x %02x %02x __ %s #$%02x\n", iip, ip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], addr);
+ break;
+ case ASMIM_ZERO_PAGE:
+ addr = mMemory[ip++];
+ fprintf(file, "%04x : %04x %02x %02x __ %s $%02x\n", iip, ip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], addr);
+ break;
+ case ASMIM_ZERO_PAGE_X:
+ addr = mMemory[ip++];
+ fprintf(file, "%04x : %04x %02x %02x __ %s $%02x,x\n", iip, ip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], addr);
+ break;
+ case ASMIM_ZERO_PAGE_Y:
+ addr = mMemory[ip++];
+ fprintf(file, "%04x : %04x %02x %02x __ %s $%02x,y\n", iip, ip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], addr);
+ break;
+ case ASMIM_ABSOLUTE:
+ addr = mMemory[ip] + 256 * mMemory[ip + 1];
+ fprintf(file, "%04x : %04x %02x %02x %02x %s $%04x\n", iip, ip, mMemory[ip], mMemory[ip + 1], mMemory[ip + 2], AsmInstructionNames[d.mType], addr);
+ ip += 2;
+ break;
+ case ASMIM_ABSOLUTE_X:
+ addr = mMemory[ip] + 256 * mMemory[ip + 1];
+ fprintf(file, "%04x : %04x %02x %02x %02x %s $%04x,x\n", iip, ip, mMemory[ip], mMemory[ip + 1], mMemory[ip + 2], AsmInstructionNames[d.mType], addr);
+ ip += 2;
+ break;
+ case ASMIM_ABSOLUTE_Y:
+ addr = mMemory[ip] + 256 * mMemory[ip + 1];
+ fprintf(file, "%04x : %04x %02x %02x %02x %s $%04x,y\n", iip, ip, mMemory[ip], mMemory[ip + 1], mMemory[ip + 2], AsmInstructionNames[d.mType], addr);
+ ip += 2;
+ break;
+ case ASMIM_INDIRECT:
+ addr = mMemory[ip] + 256 * mMemory[ip + 1];
+ ip += 2;
+ fprintf(file, "%04x : %04x %02x %02x %02x %s ($%04x)\n", iip, ip, mMemory[ip], mMemory[ip + 1], mMemory[ip + 2], AsmInstructionNames[d.mType], addr);
+ break;
+ case ASMIM_INDIRECT_X:
+ addr = mMemory[ip++];
+ fprintf(file, "%04x : %04x %02x %02x __ %s ($%02x,x)\n", iip, ip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], addr);
+ break;
+ case ASMIM_INDIRECT_Y:
+ addr = mMemory[ip++];
+ fprintf(file, "%04x : %04x %02x %02x __ %s ($%02x),y\n", iip, ip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], addr);
+ break;
+ case ASMIM_RELATIVE:
+ addr = mMemory[ip++];
+ if (addr & 0x80)
+ addr = addr + ip - 256;
+ else
+ addr = addr + ip;
+ fprintf(file, "%04x : %04x %02x %02x __ %s $%02x\n", iip, ip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], addr);
+ break;
+ }
+ }
+ }
+ }
+}
+
+bool ByteCodeGenerator::WriteMapFile(const char* filename)
+{
+ FILE* file;
+ fopen_s(&file, filename, "wb");
+ if (file)
+ {
+ for (int i = 0; i < mProcedureAddr.Size(); i++)
+ {
+ if (mProcedureAddr[i].mIdent)
+ fprintf(file, "%04x - %04x : F %s\n", mProcedureAddr[i].mAddress, mProcedureAddr[i].mAddress + mProcedureAddr[i].mSize, mProcedureAddr[i].mIdent->mString);
+ else
+ fprintf(file, "%04x - %04x : F\n", mProcedureAddr[i].mAddress, mProcedureAddr[i].mAddress + mProcedureAddr[i].mSize);
+ }
+
+ for (int i = 0; i < mGlobalAddr.Size(); i++)
+ {
+ if (mGlobalAddr[i].mAssembler)
+ {
+ if (mGlobalAddr[i].mIdent)
+ fprintf(file, "%04x - %04x : A %s\n", mGlobalAddr[i].mAddress, mGlobalAddr[i].mAddress + mGlobalAddr[i].mSize, mGlobalAddr[i].mIdent->mString);
+ else
+ fprintf(file, "%04x - %04x : A\n", mGlobalAddr[i].mAddress, mGlobalAddr[i].mAddress + mGlobalAddr[i].mSize);
+ }
+ else
+ {
+ if (mGlobalAddr[i].mIdent)
+ fprintf(file, "%04x - %04x : V %s\n", mGlobalAddr[i].mAddress, mGlobalAddr[i].mAddress + mGlobalAddr[i].mSize, mGlobalAddr[i].mIdent->mString);
+ else
+ fprintf(file, "%04x - %04x : V\n", mGlobalAddr[i].mAddress, mGlobalAddr[i].mAddress + mGlobalAddr[i].mSize);
+ }
+ }
+
+ return true;
+ }
+ else
+ return false;
+}
+
diff --git a/oscar64/ByteCodeGenerator.h b/oscar64/ByteCodeGenerator.h
new file mode 100644
index 0000000..244188b
--- /dev/null
+++ b/oscar64/ByteCodeGenerator.h
@@ -0,0 +1,285 @@
+#pragma once
+
+#include "InterCode.h"
+#include "Ident.h"
+
+enum ByteCode
+{
+ BC_NOP,
+ BC_EXIT,
+
+ BC_CONST_P8,
+ BC_CONST_N8,
+ BC_CONST_16,
+ BC_CONST_32,
+
+ BC_LOAD_REG_16,
+ BC_STORE_REG_16,
+ BC_ADDR_REG,
+ BC_LOAD_REG_32,
+ BC_STORE_REG_32,
+
+ BC_LOAD_ABS_U8,
+ BC_LOAD_ABS_I8,
+ BC_LOAD_ABS_16,
+ BC_LOAD_ABS_32,
+
+ BC_STORE_ABS_8,
+ BC_STORE_ABS_16,
+ BC_STORE_ABS_32,
+
+ BC_LEA_ABS,
+
+ BC_LOAD_LOCAL_U8,
+ BC_LOAD_LOCAL_I8,
+ BC_LOAD_LOCAL_16,
+ BC_LOAD_LOCAL_32,
+
+ BC_STORE_LOCAL_8,
+ BC_STORE_LOCAL_16,
+ BC_STORE_LOCAL_32,
+
+ BC_LEA_LOCAL,
+
+ BC_STORE_FRAME_8,
+ BC_STORE_FRAME_16,
+ BC_STORE_FRAME_32,
+
+ BC_LOAD_ADDR_U8,
+ BC_LOAD_ADDR_I8,
+ BC_LOAD_ADDR_16,
+ BC_LOAD_ADDR_32,
+
+ BC_STORE_ADDR_8,
+ BC_STORE_ADDR_16,
+ BC_STORE_ADDR_32,
+
+ BC_BINOP_ADDR_16,
+ BC_BINOP_SUBR_16,
+ BC_BINOP_ANDR_16,
+ BC_BINOP_ORR_16,
+ BC_BINOP_XORR_16,
+ BC_BINOP_MULR_16,
+ BC_BINOP_DIVR_U16,
+ BC_BINOP_MODR_U16,
+ BC_BINOP_DIVR_I16,
+ BC_BINOP_MODR_I16,
+ BC_BINOP_SHLR_16,
+ BC_BINOP_SHRR_U16,
+ BC_BINOP_SHRR_I16,
+
+ BC_BINOP_ADDI_16,
+ BC_BINOP_SUBI_16,
+ BC_BINOP_ANDI_16,
+ BC_BINOP_ORI_16,
+ BC_BINOP_MULI8_16,
+
+ BC_BINOP_SHLI_16,
+ BC_BINOP_SHRI_U16,
+ BC_BINOP_SHRI_I16,
+
+ BC_BINOP_CMPUR_16,
+ BC_BINOP_CMPSR_16,
+
+ BC_BINOP_CMPUI_16,
+ BC_BINOP_CMPSI_16,
+
+ BC_OP_NEGATE_16,
+ BC_OP_INVERT_16,
+
+ BC_BINOP_ADD_F32,
+ BC_BINOP_SUB_F32,
+ BC_BINOP_MUL_F32,
+ BC_BINOP_DIV_F32,
+ BC_BINOP_CMP_F32,
+ BC_OP_NEGATE_F32,
+ BC_OP_ABS_F32,
+ BC_OP_FLOOR_F32,
+ BC_OP_CEIL_F32,
+
+ BC_CONV_U16_F32,
+ BC_CONV_I16_F32,
+ BC_CONV_F32_U16,
+ BC_CONV_F32_I16,
+
+ BC_JUMPS,
+ BC_BRANCHS_EQ,
+ BC_BRANCHS_NE,
+ BC_BRANCHS_GT,
+ BC_BRANCHS_GE,
+ BC_BRANCHS_LT,
+ BC_BRANCHS_LE,
+
+ BC_JUMPF,
+ BC_BRANCHF_EQ,
+ BC_BRANCHF_NE,
+ BC_BRANCHF_GT,
+ BC_BRANCHF_GE,
+ BC_BRANCHF_LT,
+ BC_BRANCHF_LE,
+
+ BC_SET_EQ,
+ BC_SET_NE,
+ BC_SET_GT,
+ BC_SET_GE,
+ BC_SET_LT,
+ BC_SET_LE,
+
+ BC_ENTER,
+ BC_RETURN,
+ BC_CALL,
+ BC_PUSH_FRAME,
+ BC_POP_FRAME,
+
+ BC_JSR,
+
+ BC_COPY,
+ BC_COPY_LONG
+};
+
+class ByteCodeProcedure;
+class ByteCodeGenerator;
+
+class ByteCodeRelocation
+{
+public:
+ uint16 mAddr;
+ bool mFunction, mLower, mUpper;
+ uint16 mIndex, mOffset;
+};
+
+class ByteCodeBasicBlock;
+
+class ByteCodeInstruction
+{
+public:
+ ByteCodeInstruction(ByteCode code = BC_NOP);
+
+ void Assemble(ByteCodeGenerator* generator, ByteCodeBasicBlock* block);
+
+ ByteCode mCode;
+ uint32 mRegister;
+ int mValue, mVIndex;
+ bool mRelocate, mFunction, mRegisterFinal;
+
+ bool IsStore(void) const;
+ bool ChangesAccu(void) const;
+ bool ChangesAddr(void) const;
+ bool ChangesRegister(uint32 reg) const;
+ bool LoadsRegister(uint32 reg) const;
+ bool StoresRegister(uint32 reg) const;
+
+ bool IsCommutative(void) const;
+};
+
+class ByteCodeBasicBlock
+{
+public:
+ DynamicArray code;
+ int num;
+
+ ByteCodeBasicBlock * trueJump, * falseJump;
+ ByteCodeBasicBlock * trueLink, * falseLink;
+ ByteCode branch;
+
+ GrowingArray mIns;
+ GrowingArray mRelocations;
+
+ int mOffset, mSize;
+ bool placed, copied, knownShortBranch, killed, bypassed, mAssembled;
+
+ ByteCodeBasicBlock(void);
+
+ void Assemble(ByteCodeGenerator* generator);
+ void Compile(InterCodeProcedure* iproc, ByteCodeProcedure * proc, InterCodeBasicBlock * block);
+ void Close(ByteCodeBasicBlock* trueJump, ByteCodeBasicBlock* falseJump, ByteCode branch);
+
+ void PutByte(uint8 code);
+ void PutWord(uint16 code);
+ void PutDWord(uint32 code);
+ void PutBytes(const uint8* code, int num);
+
+ void PutCode(ByteCodeGenerator* generator, ByteCode code);
+ int PutBranch(ByteCodeGenerator* generator, ByteCode code, int offset);
+
+ ByteCodeBasicBlock* BypassEmptyBlocks(void);
+ void CalculateOffset(int& total);
+ void CopyCode(ByteCodeGenerator* generator, uint8* target);
+
+ void IntConstToAccu(__int64 val);
+ void IntConstToAddr(__int64 val);
+ void FloatConstToAccu(double val);
+ void CopyValue(InterCodeProcedure* proc, const InterInstruction& ins);
+ void LoadConstant(InterCodeProcedure* proc, const InterInstruction& ins);
+ void StoreDirectValue(InterCodeProcedure* proc, const InterInstruction & ins);
+ void LoadDirectValue(InterCodeProcedure* proc, const InterInstruction& ins);
+ void LoadEffectiveAddress(InterCodeProcedure* proc, const InterInstruction& ins);
+ void CallFunction(InterCodeProcedure* proc, const InterInstruction& ins);
+ void CallAssembler(InterCodeProcedure* proc, const InterInstruction& ins);
+ void BinaryOperator(InterCodeProcedure* proc, const InterInstruction& ins);
+ void UnaryOperator(InterCodeProcedure* proc, const InterInstruction& ins);
+ void BinaryRROperator(InterCodeProcedure* proc, const InterInstruction& ins);
+ ByteCode RelationalOperator(InterCodeProcedure* proc, const InterInstruction& ins);
+ void BinaryIntOperator(InterCodeProcedure* proc, const InterInstruction& ins, ByteCode code);
+ void NumericConversion(InterCodeProcedure* proc, const InterInstruction& ins);
+
+ void PeepHoleOptimizer(void);
+};
+
+class ByteCodeGenerator;
+
+class ByteCodeProcedure
+{
+public:
+ ByteCodeProcedure(void);
+ ~ByteCodeProcedure(void);
+
+ ByteCodeBasicBlock * entryBlock, * exitBlock;
+ ByteCodeBasicBlock ** tblocks;
+
+ int mProgStart, mProgSize;
+
+ void Compile(ByteCodeGenerator* generator, InterCodeProcedure* proc);
+ ByteCodeBasicBlock * CompileBlock(InterCodeProcedure* iproc, InterCodeBasicBlock* block);
+
+ void Disassemble(FILE * file, ByteCodeGenerator* generator, InterCodeProcedure* proc);
+protected:
+ const char* TempName(uint8 tmp, char * buffer, InterCodeProcedure* proc);
+};
+
+class ByteCodeGenerator
+{
+public:
+ ByteCodeGenerator(void);
+ ~ByteCodeGenerator(void);
+
+ void WriteBasicHeader(void);
+ void WriteByteCodeHeader(void);
+ void SetBasicEntry(int index);
+
+ bool WritePRGFile(const char* filename);
+ bool WriteMapFile(const char* filename);
+
+ void WriteAsmFile(FILE * file);
+
+ void ResolveRelocations(void);
+
+ int AddGlobal(int index, const Ident* ident, int size, const uint8* data, bool assembler);
+
+ void AddAddress(int index, bool function, int address, int size, const Ident * ident, bool assembler);
+
+ struct Address
+ {
+ int mIndex, mAddress, mSize;
+ bool mFunction, mAssembler;
+ const Ident * mIdent;
+ };
+
+ GrowingArray mProcedureAddr, mGlobalAddr;
+ GrowingArray mRelocations;
+
+ bool mByteCodeUsed[128];
+
+ uint8 mMemory[0x10000];
+ int mProgEnd, mProgStart, mProgEntry;
+};
diff --git a/oscar64/CompilationUnits.cpp b/oscar64/CompilationUnits.cpp
new file mode 100644
index 0000000..c08ff52
--- /dev/null
+++ b/oscar64/CompilationUnits.cpp
@@ -0,0 +1,96 @@
+#include "CompilationUnits.h"
+#include
+#include
+#include
+
+CompilationUnits::CompilationUnits(Errors * errors)
+ : mErrors(errors)
+{
+ mCompilationUnits = nullptr;
+ mPendingUnits = nullptr;
+ mScope = new DeclarationScope(nullptr);
+ mStartup = nullptr;
+
+ for (int i = 0; i < 128; i++)
+ mByteCodes[i] = nullptr;
+}
+
+CompilationUnits::~CompilationUnits(void)
+{
+
+}
+
+bool CompilationUnits::AddUnit(Location& location, const char* name, const char* from)
+{
+ char filename[200];
+
+ if (!from)
+ {
+ strcpy_s(filename, name);
+ }
+ else
+ {
+ strcpy_s(filename, from);
+ int i = strlen(filename);
+ while (i > 0 && (filename[i - 1] != '/' && filename[i - 1] != '\\'))
+ i--;
+ while (name[0] == '.' && name[1] == '.' && name[2] == '/')
+ {
+ name += 3;
+ while (i > 0 && (filename[i - 1] != '/' && filename[i - 1] != '\\'))
+ i--;
+ }
+ filename[i] = 0;
+ strcat_s(filename, name);
+ }
+
+ int i = 0;
+ while (filename[i])
+ {
+ if (filename[i] == '\\')
+ filename[i] = '/';
+ i++;
+ }
+
+ if (_access(filename, 0) != 0)
+ {
+ mErrors->Error(location, "Could not open source file.", filename);
+ return false;
+ }
+
+ CompilationUnit* cunit = mCompilationUnits, * punit = nullptr;
+ while (cunit && strcmp(cunit->mFileName, filename) != 0)
+ {
+ punit = cunit;
+ cunit = cunit->mNext;
+ }
+
+ if (cunit)
+ return true;
+
+ cunit = new CompilationUnit();
+ cunit->mLocation = location;
+ strcpy_s(cunit->mFileName, filename);
+ cunit->mCompiled = false;
+ cunit->mNext = nullptr;
+
+ if (punit)
+ punit->mNext = cunit;
+ else
+ mCompilationUnits = cunit;
+
+ if (!mPendingUnits)
+ mPendingUnits = cunit;
+
+ return true;
+}
+
+CompilationUnit* CompilationUnits::PendingUnit(void)
+{
+ CompilationUnit* unit = mPendingUnits;
+
+ if (mPendingUnits)
+ mPendingUnits = mPendingUnits->mNext;
+
+ return unit;
+}
diff --git a/oscar64/CompilationUnits.h b/oscar64/CompilationUnits.h
new file mode 100644
index 0000000..9f5c795
--- /dev/null
+++ b/oscar64/CompilationUnits.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include "Declaration.h"
+#include "Errors.h"
+
+class CompilationUnit
+{
+public:
+ Location mLocation;
+ char mFileName[200];
+ CompilationUnit * mNext;
+ bool mCompiled;
+};
+
+class CompilationUnits
+{
+public:
+ CompilationUnits(Errors * errors);
+ ~CompilationUnits(void);
+
+ DeclarationScope* mScope;
+ CompilationUnit* mCompilationUnits, * mPendingUnits;
+
+ Declaration* mStartup;
+ Declaration* mByteCodes[128];
+
+ bool AddUnit(Location & location, const char* name, const char * from);
+ CompilationUnit* PendingUnit(void);
+protected:
+ Errors* mErrors;
+};
+
diff --git a/oscar64/Compiler.cpp b/oscar64/Compiler.cpp
new file mode 100644
index 0000000..16fc48f
--- /dev/null
+++ b/oscar64/Compiler.cpp
@@ -0,0 +1,240 @@
+#include "Compiler.h"
+#include "Scanner.h"
+#include "Parser.h"
+#include "InterCodeGenerator.h"
+#include "InterCode.h"
+#include "ByteCodeGenerator.h"
+#include "Emulator.h"
+#include
+
+Compiler::Compiler(void)
+ : mByteCodeFunctions(nullptr)
+{
+ mErrors = new Errors();
+ mCompilationUnits = new CompilationUnits(mErrors);
+ mPreprocessor = new Preprocessor(mErrors);
+ mByteCodeGenerator = new ByteCodeGenerator();
+ mInterCodeGenerator = new InterCodeGenerator(mErrors);
+ mInterCodeModule = new InterCodeModule();
+}
+
+Compiler::~Compiler(void)
+{
+
+}
+
+bool Compiler::ParseSource(void)
+{
+ CompilationUnit* cunit;
+ while (mErrors->mErrorCount == 0 && (cunit = mCompilationUnits->PendingUnit()))
+ {
+ if (mPreprocessor->OpenSource(cunit->mFileName, true))
+ {
+ Scanner* scanner = new Scanner(mErrors, mPreprocessor);
+ Parser* parser = new Parser(mErrors, scanner, mCompilationUnits);
+
+ parser->Parse();
+ }
+ else
+ mErrors->Error(cunit->mLocation, "Could not open source file", cunit->mFileName);
+ }
+
+ return mErrors->mErrorCount == 0;
+}
+
+bool Compiler::GenerateCode(void)
+{
+ Location loc;
+
+ Declaration* dcrtstart = mCompilationUnits->mStartup;
+ if (!dcrtstart)
+ {
+ mErrors->Error(loc, "Runtime startup not found");
+ return false;
+ }
+
+ mInterCodeGenerator->TranslateAssembler(mInterCodeModule, dcrtstart->mValue);
+
+ if (mErrors->mErrorCount != 0)
+ return false;
+
+ mByteCodeGenerator->WriteBasicHeader();
+
+ mInterCodeModule->UseGlobal(dcrtstart->mVarIndex);
+
+ InterVariable& vmain(mInterCodeModule->mGlobalVars[dcrtstart->mVarIndex]);
+ vmain.mAddr = mByteCodeGenerator->AddGlobal(vmain.mIndex, vmain.mIdent, vmain.mSize, vmain.mData, vmain.mAssembler);
+ vmain.mPlaced = true;
+ mByteCodeGenerator->SetBasicEntry(dcrtstart->mVarIndex);
+
+ mByteCodeGenerator->mProgEnd = 0x0a00;
+ mByteCodeGenerator->WriteByteCodeHeader();
+
+ const Ident* imain = Ident::Unique("main");
+ Declaration* dmain = mCompilationUnits->mScope->Lookup(imain);
+ if (!dmain)
+ {
+ mErrors->Error(loc, "main function not found");
+ return false;
+ }
+
+ InterCodeProcedure* iproc = mInterCodeGenerator->TranslateProcedure(mInterCodeModule, dmain->mValue, dmain);
+
+ if (mErrors->mErrorCount != 0)
+ return false;
+
+ for (int i = 0; i < mInterCodeModule->mProcedures.Size(); i++)
+ {
+ ByteCodeProcedure* bgproc = new ByteCodeProcedure();
+
+ mInterCodeModule->mProcedures[i]->ReduceTemporaries();
+
+#if _DEBUG
+ mInterCodeModule->mProcedures[i]->Disassemble("final");
+#endif
+
+ bgproc->Compile(mByteCodeGenerator, mInterCodeModule->mProcedures[i]);
+ mByteCodeFunctions.Push(bgproc);
+
+#if _DEBUG
+ FILE* file;
+ fopen_s(&file, "r:\\cldiss.txt", "a");
+
+ if (file)
+ {
+ bgproc->Disassemble(file, mByteCodeGenerator, mInterCodeModule->mProcedures[i]);
+ fclose(file);
+ }
+#endif
+ }
+
+ for (int i = 0; i < 128; i++)
+ {
+ if (mByteCodeGenerator->mByteCodeUsed[i])
+ {
+ Declaration* bcdec = mCompilationUnits->mByteCodes[i];
+ if (bcdec)
+ {
+ int index = -1, offset = 0;
+ if (bcdec->mType == DT_CONST_ASSEMBLER)
+ {
+ if (bcdec->mVarIndex < 0)
+ mInterCodeGenerator->TranslateAssembler(mInterCodeModule, bcdec->mValue);
+ index = bcdec->mVarIndex;
+ }
+ else if (bcdec->mType == DT_LABEL)
+ {
+ if (bcdec->mBase->mVarIndex < 0)
+ mInterCodeGenerator->TranslateAssembler(mInterCodeModule, bcdec->mBase->mValue);
+ index = bcdec->mBase->mVarIndex;
+ offset = bcdec->mInteger;
+ }
+
+ assert(index > 0);
+ mInterCodeModule->UseGlobal(index);
+
+ ByteCodeRelocation rel;
+ rel.mAddr = 0x900 + 2 * i;
+ rel.mFunction = false;
+ rel.mLower = true;
+ rel.mUpper = true;
+ rel.mIndex = index;
+ rel.mOffset = offset;
+ mByteCodeGenerator->mRelocations.Push(rel);
+ }
+ }
+ }
+
+ for (int i = 0; i < mInterCodeModule->mGlobalVars.Size(); i++)
+ {
+ InterVariable& var(mInterCodeModule->mGlobalVars[i]);
+ if (var.mUsed)
+ {
+ if (!var.mPlaced)
+ {
+ var.mAddr = mByteCodeGenerator->AddGlobal(var.mIndex, var.mIdent, var.mSize, var.mData, var.mAssembler);
+ var.mPlaced = true;
+ }
+ for (int j = 0; j < var.mNumReferences; j++)
+ {
+ InterVariable::Reference& ref(var.mReferences[j]);
+ ByteCodeRelocation rel;
+ rel.mAddr = var.mAddr + ref.mAddr;
+ rel.mFunction = ref.mFunction;
+ rel.mLower = ref.mLower;
+ rel.mUpper = ref.mUpper;
+ rel.mIndex = ref.mIndex;
+ rel.mOffset = ref.mOffset;
+ mByteCodeGenerator->mRelocations.Push(rel);
+ }
+ }
+ }
+
+ mByteCodeGenerator->ResolveRelocations();
+
+ return mErrors->mErrorCount == 0;
+}
+
+bool Compiler::WriteOutputFile(const char* targetPath)
+{
+ char prgPath[200], mapPath[200], asmPath[200];
+
+ strcpy_s(prgPath, targetPath);
+ int i = strlen(prgPath);
+ while (i > 0 && prgPath[i - 1] != '.')
+ i--;
+ prgPath[i] = 0;
+
+ strcpy_s(mapPath, prgPath);
+ strcpy_s(asmPath, prgPath);
+
+ strcat_s(prgPath, "prg");
+ strcat_s(mapPath, "map");
+ strcat_s(asmPath, "asm");
+
+ printf("Writing <%s>\n", prgPath);
+ mByteCodeGenerator->WritePRGFile(prgPath);
+
+ printf("Writing <%s>\n", mapPath);
+ mByteCodeGenerator->WriteMapFile(mapPath);
+
+ printf("Writing <%s>\n", asmPath);
+ {
+ FILE* file;
+ fopen_s(&file, asmPath, "w");
+
+ if (file)
+ {
+ for (int i = 0; i < mByteCodeFunctions.Size(); i++)
+ mByteCodeFunctions[i]->Disassemble(file, mByteCodeGenerator, mInterCodeModule->mProcedures[i]);
+
+ mByteCodeGenerator->WriteAsmFile(file);
+
+ fclose(file);
+ }
+ }
+
+ return true;
+}
+
+int Compiler::ExecuteCode(void)
+{
+ Location loc;
+
+ printf("Running emulation...\n");
+ Emulator* emu = new Emulator();
+ memcpy(emu->mMemory + mByteCodeGenerator->mProgStart, mByteCodeGenerator->mMemory + mByteCodeGenerator->mProgStart, mByteCodeGenerator->mProgEnd - mByteCodeGenerator->mProgStart);
+ emu->mMemory[0x2d] = mByteCodeGenerator->mProgEnd & 0xff;
+ emu->mMemory[0x2e] = mByteCodeGenerator->mProgEnd >> 8;
+ int ecode = emu->Emulate(2061);
+ printf("Emulation result %d\n", ecode);
+
+ if (ecode != 0)
+ {
+ char sd[20];
+ sprintf_s(sd, "%d", ecode);
+ mErrors->Error(loc, "Execution failed", sd);
+ }
+
+ return ecode;
+}
diff --git a/oscar64/Compiler.h b/oscar64/Compiler.h
new file mode 100644
index 0000000..b8095f7
--- /dev/null
+++ b/oscar64/Compiler.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include "Errors.h"
+#include "CompilationUnits.h"
+#include "Preprocessor.h"
+#include "ByteCodeGenerator.h"
+#include "InterCodeGenerator.h"
+
+class Compiler
+{
+public:
+ Compiler(void);
+ ~Compiler(void);
+
+ Errors* mErrors;
+ CompilationUnits* mCompilationUnits;
+ Preprocessor* mPreprocessor;
+ ByteCodeGenerator* mByteCodeGenerator;
+ InterCodeGenerator* mInterCodeGenerator;
+ InterCodeModule* mInterCodeModule;
+
+ GrowingArray mByteCodeFunctions;
+
+ bool ParseSource(void);
+ bool GenerateCode(void);
+ bool WriteOutputFile(const char* targetPath);
+ int ExecuteCode(void);
+};
diff --git a/oscar64/Declaration.cpp b/oscar64/Declaration.cpp
new file mode 100644
index 0000000..b53bd11
--- /dev/null
+++ b/oscar64/Declaration.cpp
@@ -0,0 +1,513 @@
+#include "Declaration.h"
+
+DeclarationScope::DeclarationScope(DeclarationScope* parent)
+{
+ mParent = parent;
+ mHashSize = 0;
+ mHashFill = 0;
+ mHash = nullptr;
+}
+
+DeclarationScope::~DeclarationScope(void)
+{
+ delete[] mHash;
+}
+
+Declaration * DeclarationScope::Insert(const Ident* ident, Declaration* dec)
+{
+ if (!mHash)
+ {
+ mHashSize = 16;
+ mHashFill = 0;
+ mHash = new Entry[mHashSize];
+ for (int i = 0; i < mHashSize; i++)
+ {
+ mHash[i].mDec = nullptr;
+ mHash[i].mIdent = nullptr;
+ }
+ }
+
+ int hm = mHashSize - 1;
+ int hi = ident->mHash & hm;
+
+ while (mHash[hi].mIdent)
+ {
+ if (ident == mHash[hi].mIdent)
+ return mHash[hi].mDec;
+ hi = (hi + 1) & hm;
+ }
+
+ mHash[hi].mIdent = ident;
+ mHash[hi].mDec = dec;
+ mHashFill++;
+
+ if (2 * mHashFill >= mHashSize)
+ {
+ int size = mHashSize;
+ Entry* entries = mHash;
+ mHashSize *= 2;
+ mHashFill = 0;
+ mHash = new Entry[mHashSize];
+ for (int i = 0; i < mHashSize; i++)
+ {
+ mHash[i].mDec = nullptr;
+ mHash[i].mIdent = nullptr;
+ }
+ for (int i = 0; i < size; i++)
+ {
+ if (entries[i].mIdent)
+ Insert(entries[i].mIdent, entries[i].mDec);
+ }
+ delete[] entries;
+ }
+
+ return nullptr;
+}
+
+Declaration* DeclarationScope::Lookup(const Ident* ident)
+{
+ if (mHashSize > 0)
+ {
+ int hm = mHashSize - 1;
+ int hi = ident->mHash & hm;
+
+ while (mHash[hi].mIdent)
+ {
+ if (ident == mHash[hi].mIdent)
+ return mHash[hi].mDec;
+ hi = (hi + 1) & hm;
+ }
+ }
+
+ return mParent ? mParent->Lookup(ident) : nullptr;
+}
+
+
+Expression::Expression(const Location& loc, ExpressionType type)
+ : mLocation(loc), mType(type), mLeft(nullptr), mRight(nullptr), mConst(false)
+{
+
+}
+
+Expression::~Expression(void)
+{
+
+}
+
+Expression* Expression::LogicInvertExpression(void)
+{
+ if (mType == EX_LOGICAL_NOT)
+ return mLeft;
+ else if (mType == EX_LOGICAL_AND)
+ {
+ mType = EX_LOGICAL_OR;
+ mLeft = mLeft->LogicInvertExpression();
+ mRight = mRight->LogicInvertExpression();
+ return this;
+ }
+ else if (mType == EX_LOGICAL_OR)
+ {
+ mType = EX_LOGICAL_OR;
+ mLeft = mLeft->LogicInvertExpression();
+ mRight = mRight->LogicInvertExpression();
+ return this;
+ }
+ else if (mType == EX_RELATIONAL)
+ {
+ switch (mToken)
+ {
+ case TK_EQUAL:
+ mToken = TK_NOT_EQUAL;
+ break;
+ case TK_NOT_EQUAL:
+ mToken = TK_EQUAL;
+ break;
+ case TK_GREATER_THAN:
+ mToken = TK_LESS_EQUAL;
+ break;
+ case TK_GREATER_EQUAL:
+ mToken = TK_LESS_THAN;
+ break;
+ case TK_LESS_THAN:
+ mToken = TK_GREATER_EQUAL;
+ break;
+ case TK_LESS_EQUAL:
+ mToken = TK_GREATER_THAN;
+ break;
+ }
+
+ return this;
+ }
+ else
+ {
+ Expression* ex = new Expression(mLocation, EX_LOGICAL_NOT);
+ ex->mLeft = this;
+ return ex;
+ }
+}
+
+Expression* Expression::ConstantFold(void)
+{
+ if (mType == EX_PREFIX && mLeft->mType == EX_CONSTANT)
+ {
+ if (mLeft->mDecValue->mType == DT_CONST_INTEGER)
+ {
+ switch (mToken)
+ {
+ case TK_ADD:
+ return mLeft;
+ case TK_SUB:
+ {
+ Expression* ex = new Expression(mLocation, EX_CONSTANT);
+ Declaration * dec = new Declaration(mLocation, DT_CONST_INTEGER);
+ dec->mBase = TheSignedIntTypeDeclaration;
+ dec->mInteger = - mLeft->mDecValue->mInteger;
+ ex->mDecValue = dec;
+ ex->mDecType = TheSignedIntTypeDeclaration;
+ return ex;
+ }
+ case TK_BINARY_NOT:
+ {
+ Expression* ex = new Expression(mLocation, EX_CONSTANT);
+ Declaration* dec = new Declaration(mLocation, DT_CONST_INTEGER);
+ dec->mBase = mLeft->mDecValue->mBase;
+ dec->mInteger = ~mLeft->mDecValue->mInteger;
+ ex->mDecValue = dec;
+ ex->mDecType = dec->mBase;
+ return ex;
+ }
+
+ }
+ }
+ else if (mLeft->mDecValue->mType == DT_CONST_FLOAT)
+ {
+ switch (mToken)
+ {
+ case TK_ADD:
+ return mLeft;
+ case TK_SUB:
+ {
+ Expression* ex = new Expression(mLocation, EX_CONSTANT);
+ Declaration* dec = new Declaration(mLocation, DT_CONST_FLOAT);
+ dec->mBase = TheFloatTypeDeclaration;
+ dec->mNumber = -mLeft->mDecValue->mNumber;
+ ex->mDecValue = dec;
+ ex->mDecType = TheFloatTypeDeclaration;
+ return ex;
+ }
+
+ }
+
+ }
+ }
+ else if (mType == EX_TYPECAST && mRight->mType == EX_CONSTANT)
+ {
+ if (mLeft->mDecType->mType == DT_TYPE_POINTER)
+ {
+ if (mRight->mDecValue->mType == DT_CONST_ADDRESS || mRight->mDecValue->mType == DT_CONST_INTEGER)
+ {
+ Expression* ex = new Expression(mLocation, EX_CONSTANT);
+ Declaration* dec = new Declaration(mLocation, DT_CONST_ADDRESS);
+ dec->mBase = mLeft->mDecType;
+ dec->mInteger = mRight->mDecValue->mInteger;
+ ex->mDecValue = dec;
+ ex->mDecType = mLeft->mDecType;
+ return ex;
+ }
+ }
+ else if (mLeft->mDecType->mType == DT_CONST_INTEGER)
+ {
+ if (mRight->mDecValue->mType == DT_CONST_FLOAT)
+ {
+ Expression* ex = new Expression(mLocation, EX_CONSTANT);
+ Declaration* dec = new Declaration(mLocation, DT_CONST_INTEGER);
+ dec->mBase = mLeft->mDecType;
+ dec->mInteger = mRight->mDecValue->mNumber;
+ ex->mDecValue = dec;
+ ex->mDecType = mLeft->mDecType;
+ return ex;
+ }
+ }
+ else if (mLeft->mDecType->mType == DT_CONST_FLOAT)
+ {
+ if (mRight->mDecValue->mType == DT_CONST_INTEGER)
+ {
+ Expression* ex = new Expression(mLocation, EX_CONSTANT);
+ Declaration* dec = new Declaration(mLocation, DT_CONST_FLOAT);
+ dec->mBase = mLeft->mDecType;
+ dec->mNumber = mRight->mDecValue->mInteger;
+ ex->mDecValue = dec;
+ ex->mDecType = mLeft->mDecType;
+ return ex;
+ }
+ }
+ }
+ else if (mType == EX_BINARY && mLeft->mType == EX_CONSTANT && mRight->mType == EX_CONSTANT)
+ {
+ if (mLeft->mDecValue->mType == DT_CONST_INTEGER && mRight->mDecValue->mType == DT_CONST_INTEGER)
+ {
+ __int64 ival, ileft = mLeft->mDecValue->mInteger, iright = mRight->mDecValue->mInteger;
+
+ switch (mToken)
+ {
+ case TK_ADD:
+ ival = ileft + iright;
+ break;
+ case TK_SUB:
+ ival = ileft - iright;
+ break;
+ case TK_MUL:
+ ival = ileft * iright;
+ break;
+ case TK_DIV:
+ ival = ileft / iright;
+ break;
+ case TK_MOD:
+ ival = ileft % iright;
+ break;
+ case TK_LEFT_SHIFT:
+ ival = ileft << iright;
+ break;
+ case TK_RIGHT_SHIFT:
+ ival = ileft >> iright;
+ break;
+ case TK_BINARY_AND:
+ ival = ileft & iright;
+ break;
+ case TK_BINARY_OR:
+ ival = ileft | iright;
+ break;
+ case TK_BINARY_XOR:
+ ival = ileft ^ iright;
+ break;
+ default:
+ ival = 0;
+ }
+
+ Expression* ex = new Expression(mLocation, EX_CONSTANT);
+ Declaration* dec = new Declaration(mLocation, DT_CONST_INTEGER);
+ dec->mBase = ival < 32768 ? TheSignedIntTypeDeclaration : TheUnsignedIntTypeDeclaration;
+ dec->mInteger = ival;
+ ex->mDecValue = dec;
+ ex->mDecType = dec->mBase;
+ return ex;
+ }
+ else if ((mLeft->mDecValue->mType == DT_CONST_INTEGER || mLeft->mDecValue->mType == DT_CONST_FLOAT) && (mRight->mDecValue->mType == DT_CONST_INTEGER || mRight->mDecValue->mType == DT_CONST_FLOAT))
+ {
+
+ double dval;
+ double dleft = mLeft->mDecValue->mType == DT_CONST_INTEGER ? mLeft->mDecValue->mInteger : mLeft->mDecValue->mNumber;
+ double dright = mRight->mDecValue->mType == DT_CONST_INTEGER ? mRight->mDecValue->mInteger : mRight->mDecValue->mNumber;
+
+ switch (mToken)
+ {
+ case TK_ADD:
+ dval = dleft + dright;
+ break;
+ case TK_SUB:
+ dval = dleft - dright;
+ break;
+ case TK_MUL:
+ dval = dleft * dright;
+ break;
+ case TK_DIV:
+ dval = dleft / dright;
+ break;
+ default:
+ dval = 0;
+ }
+
+ Expression* ex = new Expression(mLocation, EX_CONSTANT);
+ Declaration* dec = new Declaration(mLocation, DT_CONST_FLOAT);
+ dec->mBase = TheFloatTypeDeclaration;
+ dec->mNumber = dval;
+ ex->mDecValue = dec;
+ ex->mDecType = dec->mBase;
+ return ex;
+ }
+ }
+
+ return this;
+}
+
+Declaration::Declaration(const Location& loc, DecType type)
+ : mLocation(loc), mType(type), mScope(nullptr), mData(nullptr), mIdent(nullptr), mSize(0), mOffset(0), mFlags(0), mBase(nullptr), mParams(nullptr), mValue(nullptr), mNext(nullptr)
+{}
+
+Declaration::~Declaration(void)
+{
+ delete mScope;
+ delete[] mData;
+}
+
+bool Declaration::IsSubType(const Declaration* dec) const
+{
+ if (this == dec)
+ return true;
+ if (mType != dec->mType)
+ return false;
+ if (mSize != dec->mSize)
+ return false;
+
+ if ((mFlags & DTF_SIGNED) != (dec->mFlags & DTF_SIGNED))
+ return false;
+
+ if ((dec->mFlags & ~mFlags) & (DTF_CONST | DTF_VOLATILE))
+ return false;
+
+ if (mType == DT_TYPE_INTEGER)
+ return true;
+ else if (mType == DT_TYPE_BOOL || mType == DT_TYPE_FLOAT || mType == DT_TYPE_VOID)
+ return true;
+ else if (mType == DT_TYPE_STRUCT || mType == DT_TYPE_ENUM)
+ return false;
+ else if (mType == DT_TYPE_POINTER || mType == DT_TYPE_ARRAY)
+ return mBase->IsSubType(dec->mBase);
+ else if (mType == DT_TYPE_FUNCTION)
+ {
+ if (!dec->mBase->IsSubType(mBase))
+ return false;
+ Declaration* dl = mParams, * dr = dec->mParams;
+ while (dl && dr)
+ {
+ if (!dl->mBase->IsSubType(dr->mBase))
+ return false;
+ dl = dl->mNext;
+ dr = dr->mNext;
+ }
+
+ if (dl || dr)
+ return false;
+
+ if ((mFlags & DTF_VARIADIC) != (dec->mFlags & DTF_VARIADIC))
+ return false;
+
+ return true;
+ }
+
+ return false;
+}
+
+bool Declaration::IsSame(const Declaration* dec) const
+{
+ if (this == dec)
+ return true;
+ if (mType != dec->mType)
+ return false;
+ if (mSize != dec->mSize)
+ return false;
+
+ if ((mFlags & (DTF_SIGNED | DTF_CONST | DTF_VOLATILE)) != (dec->mFlags & (DTF_SIGNED | DTF_CONST | DTF_VOLATILE)))
+ return false;
+
+ if (mType == DT_TYPE_INTEGER)
+ return true;
+ else if (mType == DT_TYPE_BOOL || mType == DT_TYPE_FLOAT || mType == DT_TYPE_VOID)
+ return true;
+ else if (mType == DT_TYPE_STRUCT || mType == DT_TYPE_ENUM)
+ return false;
+ else if (mType == DT_TYPE_POINTER || mType == DT_TYPE_ARRAY)
+ return mBase->IsSame(dec->mBase);
+ else if (mType == DT_TYPE_FUNCTION)
+ {
+ if (!mBase->IsSame(dec->mBase))
+ return false;
+ Declaration* dl = mParams, * dr = dec->mParams;
+ while (dl && dr)
+ {
+ if (!dl->mBase->IsSame(dr->mBase))
+ return false;
+ dl = dl->mNext;
+ dr = dr->mNext;
+ }
+
+ if (dl || dr)
+ return false;
+
+ if ((mFlags & DTF_VARIADIC) != (dec->mFlags & DTF_VARIADIC))
+ return false;
+
+ return true;
+ }
+
+ return false;
+}
+
+bool Declaration::CanAssign(const Declaration* fromType) const
+{
+ if (this->IsSame(fromType))
+ return true;
+ else if (IsNumericType())
+ {
+ if (fromType->IsNumericType())
+ return true;
+ }
+ else if (mType == DT_TYPE_POINTER)
+ {
+ if (fromType->mType == DT_TYPE_POINTER || fromType->mType == DT_TYPE_ARRAY)
+ {
+ if (mBase->mType == DT_TYPE_VOID || fromType->mBase->mType == DT_TYPE_VOID)
+ return true;
+ else if (mBase->IsSubType(fromType->mBase))
+ return true;
+ }
+ else if (mBase->mType == DT_TYPE_FUNCTION && fromType->mType == DT_TYPE_FUNCTION)
+ {
+ return mBase->IsSame(fromType);
+ }
+ }
+
+ return false;
+}
+
+bool Declaration::IsIntegerType(void) const
+{
+ return mType == DT_TYPE_INTEGER || mType == DT_TYPE_BOOL || mType == DT_TYPE_ENUM;
+}
+
+bool Declaration::IsNumericType(void) const
+{
+ return mType == DT_TYPE_INTEGER || mType == DT_TYPE_BOOL || mType == DT_TYPE_FLOAT || mType == DT_TYPE_ENUM;
+}
+
+Declaration* TheVoidTypeDeclaration, * TheSignedIntTypeDeclaration, * TheUnsignedIntTypeDeclaration, * TheConstSignedCharTypeDeclaration, * TheSignedCharTypeDeclaration, * TheUnsignedCharTypeDeclaration, * TheBoolTypeDeclaration, * TheFloatTypeDeclaration, * TheVoidPointerTypeDeclaration;
+
+void InitDeclarations(void)
+{
+ static Location noloc;
+ TheVoidTypeDeclaration = new Declaration(noloc, DT_TYPE_VOID);
+ TheVoidTypeDeclaration->mFlags = DTF_DEFINED;
+
+ TheVoidPointerTypeDeclaration = new Declaration(noloc, DT_TYPE_POINTER);
+ TheVoidPointerTypeDeclaration->mBase = TheVoidTypeDeclaration;
+ TheVoidPointerTypeDeclaration->mSize = 2;
+ TheVoidPointerTypeDeclaration->mFlags = DTF_DEFINED;
+
+ TheSignedIntTypeDeclaration = new Declaration(noloc, DT_TYPE_INTEGER);
+ TheSignedIntTypeDeclaration->mSize = 2;
+ TheSignedIntTypeDeclaration->mFlags = DTF_DEFINED | DTF_SIGNED;
+
+ TheUnsignedIntTypeDeclaration = new Declaration(noloc, DT_TYPE_INTEGER);
+ TheUnsignedIntTypeDeclaration->mSize = 2;
+ TheUnsignedIntTypeDeclaration->mFlags = DTF_DEFINED;
+
+ TheSignedCharTypeDeclaration = new Declaration(noloc, DT_TYPE_INTEGER);
+ TheSignedCharTypeDeclaration->mSize = 1;
+ TheSignedCharTypeDeclaration->mFlags = DTF_DEFINED | DTF_SIGNED;
+
+ TheConstSignedCharTypeDeclaration = new Declaration(noloc, DT_TYPE_INTEGER);
+ TheConstSignedCharTypeDeclaration->mSize = 1;
+ TheConstSignedCharTypeDeclaration->mFlags = DTF_DEFINED | DTF_SIGNED | DTF_CONST;
+
+ TheUnsignedCharTypeDeclaration = new Declaration(noloc, DT_TYPE_INTEGER);
+ TheUnsignedCharTypeDeclaration->mSize = 1;
+ TheUnsignedCharTypeDeclaration->mFlags = DTF_DEFINED;
+
+ TheBoolTypeDeclaration = new Declaration(noloc, DT_TYPE_BOOL);
+ TheBoolTypeDeclaration->mSize = 1;
+ TheBoolTypeDeclaration->mFlags = DTF_DEFINED;
+
+ TheFloatTypeDeclaration = new Declaration(noloc, DT_TYPE_FLOAT);
+ TheFloatTypeDeclaration->mSize = 4;
+ TheFloatTypeDeclaration->mFlags = DTF_DEFINED | DTF_SIGNED;
+}
diff --git a/oscar64/Declaration.h b/oscar64/Declaration.h
new file mode 100644
index 0000000..35f5f7c
--- /dev/null
+++ b/oscar64/Declaration.h
@@ -0,0 +1,165 @@
+#pragma once
+
+#include "Ident.h"
+#include "Scanner.h"
+#include "MachineTypes.h"
+#include "Assembler.h"
+
+enum DecType
+{
+ DT_TYPE_VOID,
+ DT_TYPE_NULL,
+ DT_TYPE_BOOL,
+ DT_TYPE_INTEGER,
+ DT_TYPE_FLOAT,
+ DT_TYPE_ENUM,
+ DT_TYPE_POINTER,
+ DT_TYPE_ARRAY,
+ DT_TYPE_STRUCT,
+ DT_TYPE_UNION,
+ DT_TYPE_FUNCTION,
+ DT_TYPE_ASSEMBLER,
+
+ DT_TYPE_CONST,
+ DT_TYPE_VOLATILE,
+
+ DT_CONST_INTEGER,
+ DT_CONST_FLOAT,
+ DT_CONST_FUNCTION,
+ DT_CONST_ADDRESS,
+ DT_CONST_DATA,
+ DT_CONST_STRUCT,
+ DT_CONST_POINTER,
+ DT_CONST_ASSEMBLER,
+
+ DT_VARIABLE,
+ DT_ARGUMENT,
+ DT_ELEMENT,
+ DT_ANON,
+ DT_LABEL,
+ DT_VARIABLE_REF,
+ DT_LABEL_REF
+};
+
+// TypeFlags
+
+static const uint32 DTF_SIGNED = 0x00000001;
+static const uint32 DTF_DEFINED = 0x00000002;
+static const uint32 DTF_GLOBAL = 0x00000004;
+static const uint32 DTF_VARIADIC = 0x00000008;
+static const uint32 DTF_INTRINSIC = 0x00000010;
+static const uint32 DTF_STATIC = 0x00000020;
+static const uint32 DTF_CONST = 0x00000040;
+static const uint32 DTF_VOLATILE = 0x00000080;
+static const uint32 DTF_EXTERN = 0x00000100;
+
+class Declaration;
+
+class DeclarationScope
+{
+public:
+ DeclarationScope(DeclarationScope * parent);
+ ~DeclarationScope(void);
+
+ Declaration* Insert(const Ident* ident, Declaration* dec);
+ Declaration* Lookup(const Ident* ident);
+
+ DeclarationScope* mParent;
+protected:
+ struct Entry
+ {
+ const Ident* mIdent;
+ Declaration* mDec;
+ };
+ Entry * mHash;
+ int mHashSize, mHashFill;
+};
+
+enum ExpressionType
+{
+ EX_ERROR,
+ EX_VOID,
+ EX_CONSTANT,
+ EX_VARIABLE,
+ EX_ASSIGNMENT,
+ EX_BINARY,
+ EX_RELATIONAL,
+ EX_PREINCDEC,
+ EX_PREFIX,
+ EX_POSTFIX,
+ EX_POSTINCDEC,
+ EX_INDEX,
+ EX_QUALIFY,
+ EX_CALL,
+ EX_LIST,
+ EX_RETURN,
+ EX_SEQUENCE,
+ EX_WHILE,
+ EX_IF,
+ EX_ELSE,
+ EX_FOR,
+ EX_DO,
+ EX_BREAK,
+ EX_CONTINUE,
+ EX_TYPE,
+ EX_TYPECAST,
+ EX_LOGICAL_AND,
+ EX_LOGICAL_OR,
+ EX_LOGICAL_NOT,
+ EX_ASSEMBLER,
+ EX_UNDEFINED,
+ EX_SWITCH,
+ EX_CASE,
+ EX_DEFAULT,
+ EX_CONDITIONAL
+};
+
+class Expression
+{
+public:
+ Expression(const Location& loc, ExpressionType type);
+ ~Expression(void);
+
+ Location mLocation;
+ ExpressionType mType;
+ Expression * mLeft, * mRight;
+ Token mToken;
+ Declaration * mDecValue, * mDecType;
+ AsmInsType mAsmInsType;
+ AsmInsMode mAsmInsMode;
+ bool mConst;
+
+ Expression* LogicInvertExpression(void);
+ Expression* ConstantFold(void);
+};
+
+class Declaration
+{
+public:
+ Declaration(const Location & loc, DecType type);
+ ~Declaration(void);
+
+ Location mLocation;
+ DecType mType;
+ Token mToken;
+ Declaration* mBase, *mParams, * mNext;
+ Expression* mValue;
+ DeclarationScope* mScope;
+ int mOffset, mSize, mVarIndex;
+ __int64 mInteger;
+ double mNumber;
+ uint32 mFlags;
+ const Ident * mIdent;
+ const uint8* mData;
+
+ bool CanAssign(const Declaration* fromType) const;
+ bool IsSame(const Declaration* dec) const;
+ bool IsSubType(const Declaration* dec) const;
+
+ bool IsIntegerType(void) const;
+ bool IsNumericType(void) const;
+};
+
+void InitDeclarations(void);
+
+extern Declaration* TheVoidTypeDeclaration, * TheSignedIntTypeDeclaration, * TheUnsignedIntTypeDeclaration, * TheConstSignedCharTypeDeclaration, * TheSignedCharTypeDeclaration, * TheUnsignedCharTypeDeclaration, * TheBoolTypeDeclaration, * TheFloatTypeDeclaration, * TheVoidPointerTypeDeclaration;
diff --git a/oscar64/Emulator.cpp b/oscar64/Emulator.cpp
new file mode 100644
index 0000000..f6b8a91
--- /dev/null
+++ b/oscar64/Emulator.cpp
@@ -0,0 +1,608 @@
+#include "Emulator.h"
+#include
+
+Emulator::Emulator(void)
+{
+ for (int i = 0; i < 0x10000; i++)
+ mMemory[i] = 0;
+}
+
+
+Emulator::~Emulator(void)
+{
+
+}
+
+static const uint8 STATUS_SIGN = 0x80;
+static const uint8 STATUS_OVERFLOW = 0x40;
+static const uint8 STATUS_ZERO = 0x02;
+static const uint8 STATUS_CARRY = 0x01;
+
+void Emulator::UpdateStatus(uint8 result)
+{
+ mRegP &= ~(STATUS_ZERO | STATUS_SIGN);
+ if (result == 0) mRegP |= STATUS_ZERO;
+ if (result & 0x80) mRegP |= STATUS_SIGN;
+}
+
+void Emulator::UpdateStatusCarry(uint8 result, bool carry)
+{
+ mRegP &= ~(STATUS_ZERO | STATUS_SIGN | STATUS_CARRY);
+ if (result == 0) mRegP |= STATUS_ZERO;
+ if (result & 0x80) mRegP |= STATUS_SIGN;
+ if (carry)
+ mRegP |= STATUS_CARRY;
+}
+
+void Emulator::DumpCycles(void)
+{
+ int numTops = 0;
+ int topIP[101], topCycles[101];
+
+ int totalCycles = 0;
+
+ for (int i = 0; i < 0x10000; i++)
+ {
+ int cycles = mCycles[i];
+ totalCycles += cycles;
+ if (cycles > 0)
+ {
+ if (numTops == 0 || cycles > topCycles[numTops])
+ {
+ if (numTops < 40)
+ numTops++;
+ int j = numTops;
+ while (j > 0 && topCycles[j-1] < cycles)
+ {
+ topCycles[j] = topCycles[j - 1];
+ topIP[j] = topIP[j - 1];
+ j--;
+ }
+ topCycles[j] = cycles;
+ topIP[j] = i;
+ }
+ }
+ }
+
+ printf("Total Cycles %d\n", totalCycles);
+ return;
+
+ for (int i = 0; i < numTops; i++)
+ {
+ printf(" %2d : %04x : %d\n", i, topIP[i], topCycles[i]);
+ }
+
+}
+
+bool Emulator::EmulateInstruction(AsmInsType type, AsmInsMode mode, int addr, int & cycles)
+{
+ int t;
+
+ switch (type)
+ {
+ case ASMIT_ADC:
+ if (mode != ASMIM_IMMEDIATE)
+ addr = mMemory[addr];
+ t = mRegA + addr + (mRegP & STATUS_CARRY);
+
+ mRegP = 0;
+
+ if ((mRegA & 0x80) && (addr & 0x80) && !(t & 0x80) ||
+ !(mRegA & 0x80) && !(addr & 0x80) && (t & 0x80))
+ mRegP |= STATUS_OVERFLOW;
+
+ mRegA = (t & 255);
+ UpdateStatusCarry(mRegA, t >= 256);
+ break;
+ case ASMIT_AND:
+ if (mode != ASMIM_IMMEDIATE)
+ addr = mMemory[addr];
+ mRegA &= addr;
+ UpdateStatus(mRegA);
+ break;
+ case ASMIT_ASL:
+ if (mode == ASMIM_IMPLIED)
+ {
+ t = mRegA << 1;
+ mRegA = (t & 255);
+ UpdateStatusCarry(mRegA, t >= 256);
+ }
+ else
+ {
+ t = mMemory[addr] << 1;
+ mMemory[addr] = t & 255;
+ UpdateStatusCarry(t & 255, t >= 256);
+ cycles += 2;
+ }
+ break;
+ case ASMIT_BCC:
+ if (!(mRegP & STATUS_CARRY))
+ mIP = addr;
+ break;
+ case ASMIT_BCS:
+ if ((mRegP & STATUS_CARRY))
+ mIP = addr;
+ break;
+ case ASMIT_BEQ:
+ if ((mRegP & STATUS_ZERO))
+ mIP = addr;
+ break;
+ case ASMIT_BIT:
+ t = mMemory[addr];
+ mRegP &= ~(STATUS_ZERO | STATUS_SIGN | STATUS_OVERFLOW);
+ if (t & 0x80) mRegP |= STATUS_SIGN;
+ if (t & 0x40) mRegP |= STATUS_OVERFLOW;
+ if (!(t & mRegA)) mRegP |= STATUS_ZERO;
+ break;
+ case ASMIT_BMI:
+ if ((mRegP & STATUS_SIGN))
+ {
+ mIP = addr;
+ cycles++;
+ }
+ break;
+ case ASMIT_BNE:
+ if (!(mRegP & STATUS_ZERO))
+ {
+ mIP = addr;
+ cycles++;
+ }
+ break;
+ case ASMIT_BPL:
+ if (!(mRegP & STATUS_SIGN))
+ {
+ mIP = addr;
+ cycles++;
+ }
+ break;
+ case ASMIT_BRK:
+ return false;
+ break;
+ case ASMIT_BVC:
+ if (!(mRegP & STATUS_OVERFLOW))
+ {
+ mIP = addr;
+ cycles++;
+ }
+ break;
+ case ASMIT_BVS:
+ if ((mRegP & STATUS_OVERFLOW))
+ {
+ mIP = addr;
+ cycles++;
+ }
+ break;
+ case ASMIT_CLC:
+ mRegP &= ~STATUS_CARRY;
+ break;
+ case ASMIT_CLD:
+ break;
+ case ASMIT_CLI:
+ break;
+ case ASMIT_CLV:
+ mRegP &= ~STATUS_OVERFLOW;
+ break;
+ case ASMIT_CMP:
+ if (mode != ASMIM_IMMEDIATE)
+ addr = mMemory[addr];
+ t = mRegA + (addr ^ 0xff) + 1;
+
+ mRegP = 0;
+
+ if ((mRegA & 0x80) && !(addr & 0x80) && !(t & 0x80) ||
+ !(mRegA & 0x80) && (addr & 0x80) && (t & 0x80))
+ mRegP |= STATUS_OVERFLOW;
+
+ UpdateStatusCarry(t & 255, t >= 256);
+ break;
+ case ASMIT_CPX:
+ if (mode != ASMIM_IMMEDIATE)
+ addr = mMemory[addr];
+ t = mRegX + (addr ^ 0xff) + 1;
+
+ mRegP = 0;
+
+ if ((mRegX & 0x80) && !(addr & 0x80) && !(t & 0x80) ||
+ !(mRegX & 0x80) && (addr & 0x80) && (t & 0x80))
+ mRegP |= STATUS_OVERFLOW;
+
+ UpdateStatusCarry(t & 255, t >= 256);
+ break;
+ case ASMIT_CPY:
+ if (mode != ASMIM_IMMEDIATE)
+ addr = mMemory[addr];
+ t = mRegY + (addr ^ 0xff) + 1;
+
+ mRegP = 0;
+
+ if ((mRegY & 0x80) && !(addr & 0x80) && !(t & 0x80) ||
+ !(mRegY & 0x80) && (addr & 0x80) && (t & 0x80))
+ mRegP |= STATUS_OVERFLOW;
+
+ UpdateStatusCarry(t & 255, t >= 256);
+ break;
+ case ASMIT_DEC:
+ if (mode == ASMIM_IMPLIED)
+ {
+ t = mRegA - 1;
+ mRegA = (t & 255);
+ UpdateStatus(mRegA);
+ }
+ else
+ {
+ t = mMemory[addr] - 1;
+ mMemory[addr] = t & 255;
+ UpdateStatus(t & 255);
+ cycles += 2;
+ }
+ break;
+ case ASMIT_DEX:
+ t = mRegX - 1;
+ mRegX = (t & 255);
+ UpdateStatus(mRegX);
+ break;
+ case ASMIT_DEY:
+ t = mRegY - 1;
+ mRegY = (t & 255);
+ UpdateStatus(mRegY);
+ break;
+ case ASMIT_EOR:
+ if (mode != ASMIM_IMMEDIATE)
+ addr = mMemory[addr];
+ mRegA ^= addr;
+ UpdateStatus(mRegA);
+ break;
+ case ASMIT_INC:
+ if (mode == ASMIM_IMPLIED)
+ {
+ t = mRegA + 1;
+ mRegA = (t & 255);
+ UpdateStatus(mRegA);
+ }
+ else
+ {
+ t = mMemory[addr] + 1;
+ mMemory[addr] = t & 255;
+ UpdateStatus(t & 255);
+ cycles += 2;
+ }
+ break;
+ case ASMIT_INX:
+ t = mRegX + 1;
+ mRegX = (t & 255);
+ UpdateStatus(mRegX);
+ break;
+ case ASMIT_INY:
+ t = mRegY + 1;
+ mRegY = (t & 255);
+ UpdateStatus(mRegY);
+ break;
+ case ASMIT_JMP:
+ mIP = addr;
+ break;
+ case ASMIT_JSR:
+ mRegS--;
+ mMemory[0x100 + mRegS] = (mIP - 1) >> 8;
+ mRegS--;
+ mMemory[0x100 + mRegS] = (mIP - 1) & 0xff;
+ mIP = addr;
+ cycles += 2;
+ break;
+ case ASMIT_LDA:
+ if (mode != ASMIM_IMMEDIATE)
+ addr = mMemory[addr];
+ mRegA = addr;
+ UpdateStatus(mRegA);
+ break;
+ case ASMIT_LDX:
+ if (mode != ASMIM_IMMEDIATE)
+ addr = mMemory[addr];
+ mRegX = addr;
+ UpdateStatus(mRegX);
+ break;
+ case ASMIT_LDY:
+ if (mode != ASMIM_IMMEDIATE)
+ addr = mMemory[addr];
+ mRegY = addr;
+ UpdateStatus(mRegY);
+ break;
+ case ASMIT_LSR:
+ if (mode == ASMIM_IMPLIED)
+ {
+ int c = mRegA & 1;
+ t = mRegA >> 1;
+ mRegA = (t & 255);
+ UpdateStatusCarry(mRegA, c != 0);
+ }
+ else
+ {
+ int c = mMemory[addr] & 1;
+ t = mMemory[addr] >> 1;
+ mMemory[addr] = t & 255;
+ UpdateStatusCarry(t & 255, c != 0);
+ cycles += 2;
+ }
+ break;
+ case ASMIT_NOP:
+ break;
+ case ASMIT_ORA:
+ if (mode != ASMIM_IMMEDIATE)
+ addr = mMemory[addr];
+ mRegA |= addr;
+ UpdateStatus(mRegA);
+ break;
+ case ASMIT_PHA:
+ mRegS--;
+ mMemory[0x100 + mRegS] = mRegA;
+ cycles ++;
+ break;
+ case ASMIT_PHP:
+ mRegS--;
+ mMemory[0x100 + mRegS] = mRegP;
+ cycles++;
+ break;
+ case ASMIT_PLA:
+ mRegA = mMemory[0x100 + mRegS];
+ mRegS++;
+ cycles++;
+ break;
+ case ASMIT_PLP:
+ mRegP = mMemory[0x100 + mRegS];
+ mRegS++;
+ cycles++;
+ break;
+ case ASMIT_ROL:
+ if (mode == ASMIM_IMPLIED)
+ {
+ t = (mRegA << 1) | (mRegP & STATUS_CARRY);
+ mRegA = (t & 255);
+ UpdateStatusCarry(mRegA, t >= 256);
+ }
+ else
+ {
+ t = (mMemory[addr] << 1) | (mRegP & STATUS_CARRY);;
+ mMemory[addr] = t & 255;
+ UpdateStatusCarry(t & 255, t >= 256);
+ cycles+=2;
+ }
+ break;
+ case ASMIT_ROR:
+ if (mode == ASMIM_IMPLIED)
+ {
+ int c = mRegA & 1;
+ t = (mRegA >> 1) | ((mRegP & STATUS_CARRY) << 7);
+ mRegA = (t & 255);
+ UpdateStatusCarry(mRegA, c != 0);
+ }
+ else
+ {
+ int c = mMemory[addr] & 1;
+ t = (mMemory[addr] >> 1) | ((mRegP & STATUS_CARRY) << 7);
+ mMemory[addr] = t & 255;
+ UpdateStatusCarry(t & 255, c != 0);
+ cycles++;
+ }
+ break;
+ case ASMIT_RTI:
+ break;
+ case ASMIT_RTS:
+ mIP = (mMemory[0x100 + mRegS] + 256 * mMemory[0x101 + mRegS] + 1) & 0xffff;
+ mRegS += 2;
+ cycles += 4;
+ break;
+ case ASMIT_SBC:
+ if (mode != ASMIM_IMMEDIATE)
+ addr = mMemory[addr];
+ t = mRegA + (addr ^ 0xff) + (mRegP & STATUS_CARRY);
+
+ mRegP = 0;
+
+ if ((mRegA & 0x80) && !(addr & 0x80) && !(t & 0x80) ||
+ !(mRegA & 0x80) && (addr & 0x80) && (t & 0x80))
+ mRegP |= STATUS_OVERFLOW;
+
+ mRegA = (t & 255);
+ UpdateStatusCarry(t & 255, t >= 256);
+ break;
+ case ASMIT_SEC:
+ mRegP |= STATUS_CARRY;
+ break;
+ case ASMIT_SED:
+ break;
+ case ASMIT_SEI:
+ break;
+ case ASMIT_STA:
+ mMemory[addr] = mRegA;
+ break;
+ case ASMIT_STX:
+ mMemory[addr] = mRegX;
+ break;
+ case ASMIT_STY:
+ mMemory[addr] = mRegY;
+ break;
+ case ASMIT_TAX:
+ mRegX = mRegA;
+ UpdateStatus(mRegX);
+ break;
+ case ASMIT_TAY:
+ mRegY = mRegA;
+ UpdateStatus(mRegY);
+ break;
+ case ASMIT_TSX:
+ mRegX = mRegS;
+ UpdateStatus(mRegX);
+ break;
+ case ASMIT_TXA:
+ mRegA = mRegX;
+ UpdateStatus(mRegA);
+ break;
+ case ASMIT_TXS:
+ mRegS = mRegX;
+ break;
+ case ASMIT_TYA:
+ mRegA = mRegY;
+ UpdateStatus(mRegA);
+ break;
+ case ASMIT_INV:
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+int Emulator::Emulate(int startIP)
+{
+ int trace = 0;
+
+ for (int i = 0; i < 0x10000; i++)
+ mCycles[i] = 0;
+
+ mIP = startIP;
+ mRegA = 0;
+ mRegX = 0;
+ mRegY = 0;
+ mRegP = 0;
+ mRegS = 0xfe;
+
+ mMemory[0x1fe] = 0xff;
+ mMemory[0x1ff] = 0xff;
+
+ while (mIP != 0)
+ {
+ if (mIP == 0xffd2)
+ {
+ if (mRegA == 13)
+ putchar('\n');
+ else
+ putchar(mRegA);
+ mIP = mMemory[0x100 + mRegS] + 256 * mMemory[0x101 + mRegS] + 1;
+ mRegS += 2;
+ }
+
+ uint8 opcode = mMemory[mIP];
+ AsmInsData d = DecInsData[opcode];
+ int addr = 0, taddr;
+ int ip = mIP;
+ int iip = mMemory[BC_REG_IP] + 256 * mMemory[BC_REG_IP + 1];
+
+ mIP++;
+ switch (d.mMode)
+ {
+ case ASMIM_IMPLIED:
+ if (trace & 2)
+ printf("%04x : %04x %02x __ __ %s (A:%02x X:%02x Y:%02x P:%02x S:%02x)\n", iip, ip, mMemory[ip], AsmInstructionNames[d.mType], mRegA, mRegX, mRegY, mRegP, mRegS);
+ mCycles[ip] += 2;
+ break;
+ case ASMIM_IMMEDIATE:
+ addr = mMemory[mIP++];
+ if (trace & 2)
+ printf("%04x : %04x %02x %02x __ %s #$%02x (A:%02x X:%02x Y:%02x P:%02x S:%02x)\n", iip, ip, mMemory[ip], mMemory[ip+1], AsmInstructionNames[d.mType], addr, mRegA, mRegX, mRegY, mRegP, mRegS);
+ mCycles[ip] += 2;
+ break;
+ case ASMIM_ZERO_PAGE:
+ addr = mMemory[mIP++];
+ if (trace & 2)
+ printf("%04x : %04x %02x %02x __ %s $%02x (A:%02x X:%02x Y:%02x P:%02x S:%02x)\n", iip, ip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], addr, mRegA, mRegX, mRegY, mRegP, mRegS);
+ mCycles[ip] += 3;
+ break;
+ case ASMIM_ZERO_PAGE_X:
+ taddr = mMemory[mIP++];
+ addr = (taddr + mRegX) & 0xff;
+ if (trace & 2)
+ printf("%04x : %04x %02x %02x __ %s $%02x,x (A:%02x X:%02x Y:%02x P:%02x S:%02x %04x)\n", iip, ip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], taddr, mRegA, mRegX, mRegY, mRegP, mRegS, addr);
+ mCycles[ip] += 3;
+ break;
+ case ASMIM_ZERO_PAGE_Y:
+ taddr = mMemory[mIP++];
+ addr = (taddr + mRegY) & 0xff;
+ if (trace & 2)
+ printf("%04x : %04x %02x %02x __ %s $%02x,y (A:%02x X:%02x Y:%02x P:%02x S:%02x %04x)\n", iip, ip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], taddr, mRegA, mRegX, mRegY, mRegP, mRegS, addr);
+ mCycles[ip] += 3;
+ break;
+ case ASMIM_ABSOLUTE:
+ addr = mMemory[mIP] + 256 * mMemory[mIP + 1];
+ if (trace & 2)
+ printf("%04x : %04x %02x %02x %02x %s $%04x (A:%02x X:%02x Y:%02x P:%02x S:%02x)\n", iip, ip, mMemory[ip], mMemory[ip + 1], mMemory[ip + 2], AsmInstructionNames[d.mType], addr, mRegA, mRegX, mRegY, mRegP, mRegS);
+ mIP += 2;
+ mCycles[ip] += 4;
+ break;
+ case ASMIM_ABSOLUTE_X:
+ taddr = mMemory[mIP] + 256 * mMemory[mIP + 1];
+ addr = (taddr + mRegX) & 0xffff;
+ if (trace & 2)
+ printf("%04x : %04x %02x %02x %02x %s $%04x,x (A:%02x X:%02x Y:%02x P:%02x S:%02x %04x)\n", iip, ip, mMemory[ip], mMemory[ip + 1], mMemory[ip + 2], AsmInstructionNames[d.mType], taddr, mRegA, mRegX, mRegY, mRegP, mRegS, addr);
+ mIP += 2;
+ mCycles[ip] += 5;
+ break;
+ case ASMIM_ABSOLUTE_Y:
+ taddr = mMemory[mIP] + 256 * mMemory[mIP + 1];
+ addr = (taddr + mRegY) & 0xffff;
+ if (trace & 2)
+ printf("%04x : %04x %02x %02x %02x %s $%04x,y (A:%02x X:%02x Y:%02x P:%02x S:%02x %04x)\n", iip, ip, mMemory[ip], mMemory[ip + 1], mMemory[ip + 2], AsmInstructionNames[d.mType], taddr, mRegA, mRegX, mRegY, mRegP, mRegS, addr);
+ mIP += 2;
+ mCycles[ip] += 5;
+ break;
+ case ASMIM_INDIRECT:
+ taddr = mMemory[mIP] + 256 * mMemory[mIP + 1];
+ mIP += 2;
+ addr = mMemory[taddr] + 256 * mMemory[taddr + 1];
+ if (trace & 2)
+ printf("%04x : %04x %02x %02x %02x %s ($%04x) (A:%02x X:%02x Y:%02x P:%02x S:%02x %04x)\n", iip, ip, mMemory[ip], mMemory[ip + 1], mMemory[ip + 2], AsmInstructionNames[d.mType], taddr, mRegA, mRegX, mRegY, mRegP, mRegS, addr);
+ mCycles[ip] += 6;
+ break;
+ case ASMIM_INDIRECT_X:
+ taddr = (mMemory[mIP++] + mRegX) & 0xff;
+ addr = mMemory[taddr] + 256 * mMemory[taddr + 1];
+ if (trace & 2)
+ printf("%04x : %04x %02x %02x __ %s ($%02x,x) (A:%02x X:%02x Y:%02x P:%02x S:%02x %02x %04x)\n", iip, ip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], mMemory[ip + 1], mRegA, mRegX, mRegY, mRegP, mRegS, taddr, addr);
+ mCycles[ip] += 5;
+ break;
+ case ASMIM_INDIRECT_Y:
+ taddr = mMemory[mIP++];
+ addr = (mMemory[taddr] + 256 * mMemory[taddr + 1] + mRegY) & 0xffff;
+ if (trace & 2)
+ printf("%04x : %04x %02x %02x __ %s ($%02x),y (A:%02x X:%02x Y:%02x P:%02x S:%02x %04x)\n", iip, ip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], taddr, mRegA, mRegX, mRegY, mRegP, mRegS, addr);
+ mCycles[ip] += 4;
+ break;
+ case ASMIM_RELATIVE:
+ taddr = mMemory[mIP++];
+ if (taddr & 0x80)
+ addr = taddr + mIP - 256;
+ else
+ addr = taddr + mIP;
+ if (trace & 2)
+ printf("%04x : %04x %02x %02x __ %s $%02x (A:%02x X:%02x Y:%02x P:%02x S:%02x %04x)\n", iip, ip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], taddr, mRegA, mRegX, mRegY, mRegP, mRegS, addr);
+ mCycles[ip] += 2;
+ break;
+ }
+
+ if ((trace & 1) && ip == 0x0823)
+ {
+ int accu = mMemory[BC_REG_ACCU] + 256 * mMemory[BC_REG_ACCU + 1];
+ int ptr = mMemory[BC_REG_ADDR] + 256 * mMemory[BC_REG_ADDR + 1];
+ int sp = mMemory[BC_REG_STACK] + 256 * mMemory[BC_REG_STACK + 1];
+ printf("%04x (A:%04x P:%04x S:%04x) %04x %04x %04x %04x %04x %04x %04x %04x\n", addr, accu, ptr, sp,
+ mMemory[BC_REG_TMP + 0] + 256 * mMemory[BC_REG_TMP + 1],
+ mMemory[BC_REG_TMP + 2] + 256 * mMemory[BC_REG_TMP + 3],
+ mMemory[BC_REG_TMP + 4] + 256 * mMemory[BC_REG_TMP + 5],
+ mMemory[BC_REG_TMP + 6] + 256 * mMemory[BC_REG_TMP + 7],
+ mMemory[BC_REG_TMP + 8] + 256 * mMemory[BC_REG_TMP + 9],
+ mMemory[BC_REG_TMP + 10] + 256 * mMemory[BC_REG_TMP + 11],
+ mMemory[BC_REG_TMP + 12] + 256 * mMemory[BC_REG_TMP + 13],
+ mMemory[BC_REG_TMP + 14] + 256 * mMemory[BC_REG_TMP + 15]
+ );
+ }
+
+ if (!EmulateInstruction(d.mType, d.mMode, addr, mCycles[ip]))
+ return -1;
+ }
+
+ if (mRegS == 0)
+ {
+ DumpCycles();
+ return int16(mMemory[BC_REG_ACCU] + 256 * mMemory[BC_REG_ACCU + 1]);
+ }
+
+ return -1;
+}
diff --git a/oscar64/Emulator.h b/oscar64/Emulator.h
new file mode 100644
index 0000000..bbf44a5
--- /dev/null
+++ b/oscar64/Emulator.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "Assembler.h"
+#include "MachineTypes.h"
+
+class Emulator
+{
+public:
+ Emulator(void);
+ ~Emulator(void);
+
+ uint8 mMemory[0x10000];
+ int mCycles[0x10000];
+
+ int mIP;
+ uint8 mRegA, mRegX, mRegY, mRegS, mRegP;
+
+ int Emulate(int startIP);
+ bool EmulateInstruction(AsmInsType type, AsmInsMode mode, int addr, int & cycles);
+protected:
+ void UpdateStatus(uint8 result);
+ void UpdateStatusCarry(uint8 result, bool carry);
+ void DumpCycles(void);
+};
\ No newline at end of file
diff --git a/oscar64/Errors.cpp b/oscar64/Errors.cpp
new file mode 100644
index 0000000..8ee2e63
--- /dev/null
+++ b/oscar64/Errors.cpp
@@ -0,0 +1,33 @@
+#include "Errors.h"
+#include
+#include
+
+Errors::Errors(void)
+ : mErrorCount(0)
+{
+
+}
+
+void Errors::Warning(const Location& loc, const char* error)
+{
+ printf("Warning %s in %s: %d, %d\n", error, loc.mFileName, loc.mLine, loc.mColumn);
+}
+
+void Errors::Error(const Location& loc, const char* error)
+{
+ printf("Error %s in %s: %d, %d\n", error, loc.mFileName, loc.mLine, loc.mColumn);
+ mErrorCount++;
+ if (mErrorCount > 10)
+ exit(10);
+}
+
+void Errors::Error(const Location& loc, const char* error, const char* info)
+{
+ printf("Error %s '%s' in %s: %d, %d\n", error, info, loc.mFileName, loc.mLine, loc.mColumn);
+ mErrorCount++;
+ if (mErrorCount > 10)
+ exit(10);
+}
+
+
+
diff --git a/oscar64/Errors.h b/oscar64/Errors.h
new file mode 100644
index 0000000..4a63985
--- /dev/null
+++ b/oscar64/Errors.h
@@ -0,0 +1,23 @@
+#pragma once
+
+class Location
+{
+public:
+ const char* mFileName;
+ int mLine, mColumn;
+
+ Location() : mFileName(nullptr), mLine(0), mColumn(0) {}
+};
+
+
+class Errors
+{
+public:
+ Errors(void);
+
+ int mErrorCount;
+
+ void Error(const Location& loc, const char* msg);
+ void Error(const Location& loc, const char* msg, const char * info);
+ void Warning(const Location& loc, const char* msg);
+};
diff --git a/oscar64/Ident.cpp b/oscar64/Ident.cpp
new file mode 100644
index 0000000..667416e
--- /dev/null
+++ b/oscar64/Ident.cpp
@@ -0,0 +1,138 @@
+#include "Ident.h"
+#include
+
+Ident::~Ident()
+{
+ delete[] mString;
+}
+
+unsigned int IHash(const char* str)
+{
+ unsigned int hash = 32324124;
+ int i = 0;
+ while (str[i])
+ {
+ hash = hash * 123211 + str[i];
+ i++;
+ }
+
+ return hash;
+}
+
+Ident::Ident(const char* str, unsigned int hash)
+{
+ ptrdiff_t ssize = strlen(str);
+ mString = new char[ssize + 1];
+ strcpy_s(mString, ssize + 1, str);
+
+ mHash = hash;
+}
+
+Ident * UniqueIdents[0x10000];
+
+const Ident* Ident::Unique(const char* str)
+{
+ unsigned int hash = IHash(str);
+ int i = hash & 0xffff;
+ while (UniqueIdents[i])
+ {
+ if (!strcmp(UniqueIdents[i]->mString, str))
+ return UniqueIdents[i];
+ i = (i + 1) & 0xffff;
+ }
+ return UniqueIdents[i] = new Ident(str, hash);
+}
+
+
+
+IdentDict::IdentDict(void)
+{
+ mHashSize = 0;
+ mHashFill = 0;
+ mHash = nullptr;
+}
+
+IdentDict::~IdentDict(void)
+{
+ delete[] mHash;
+}
+
+void IdentDict::Insert(const Ident* ident, const char* str)
+{
+ int s = strlen(str);
+ char* nstr = new char[s + 1];
+ strcpy_s(nstr, s + 1, str);
+ InsertCopy(ident, nstr);
+}
+
+void IdentDict::InsertCopy(const Ident* ident, char* str)
+{
+ if (!mHash)
+ {
+ mHashSize = 16;
+ mHashFill = 0;
+ mHash = new Entry[mHashSize];
+ for (int i = 0; i < mHashSize; i++)
+ {
+ mHash[i].mString = nullptr;
+ mHash[i].mIdent = nullptr;
+ }
+ }
+
+ int hm = mHashSize - 1;
+ int hi = ident->mHash & hm;
+
+ while (mHash[hi].mIdent)
+ {
+ if (ident == mHash[hi].mIdent)
+ {
+ mHash[hi].mString = str;
+ return;
+ }
+
+ hi = (hi + 1) & hm;
+ }
+
+ mHash[hi].mIdent = ident;
+ mHash[hi].mString = str;
+ mHashFill++;
+
+ if (2 * mHashFill >= mHashSize)
+ {
+ int size = mHashSize;
+ Entry* entries = mHash;
+ mHashSize *= 2;
+ mHashFill = 0;
+ mHash = new Entry[mHashSize];
+ for (int i = 0; i < mHashSize; i++)
+ {
+ mHash[i].mString = nullptr;
+ mHash[i].mIdent = nullptr;
+ }
+ for (int i = 0; i < size; i++)
+ {
+ if (entries[i].mIdent)
+ InsertCopy(entries[i].mIdent, entries[i].mString);
+ }
+ delete[] entries;
+ }
+}
+
+const char * IdentDict::Lookup(const Ident* ident)
+{
+ if (mHashSize > 0)
+ {
+ int hm = mHashSize - 1;
+ int hi = ident->mHash & hm;
+
+ while (mHash[hi].mIdent)
+ {
+ if (ident == mHash[hi].mIdent)
+ return mHash[hi].mString;
+ hi = (hi + 1) & hm;
+ }
+ }
+
+ return nullptr;
+}
+
diff --git a/oscar64/Ident.h b/oscar64/Ident.h
new file mode 100644
index 0000000..efa5db3
--- /dev/null
+++ b/oscar64/Ident.h
@@ -0,0 +1,35 @@
+#pragma once
+
+class Ident
+{
+public:
+ ~Ident();
+
+ char * mString;
+ unsigned int mHash;
+
+ static const Ident* Unique(const char* str);
+protected:
+ Ident(const char* str, unsigned int hash);
+};
+
+class IdentDict
+{
+public:
+ IdentDict(void);
+ ~IdentDict(void);
+
+ void Insert(const Ident* ident, const char * str);
+ const char * Lookup(const Ident* ident);
+
+protected:
+ void InsertCopy(const Ident* ident, char* str);
+
+ struct Entry
+ {
+ const Ident* mIdent;
+ char* mString;
+ };
+ Entry* mHash;
+ int mHashSize, mHashFill;
+};
\ No newline at end of file
diff --git a/oscar64/InterCode.cpp b/oscar64/InterCode.cpp
new file mode 100644
index 0000000..491dc49
--- /dev/null
+++ b/oscar64/InterCode.cpp
@@ -0,0 +1,3355 @@
+#include "InterCode.h"
+
+#include "InterCode.h"
+#include
+#include
+#include
+
+ValueSet::ValueSet(void)
+{
+ size = 32;
+ num = 0;
+ instructions = new InterInstructionPtr[size];
+}
+
+ValueSet::ValueSet(const ValueSet& values)
+{
+ int i;
+
+ size = values.size;
+ num = values.num;
+ instructions = new InterInstructionPtr[size];
+
+ for (i = 0; i < num; i++)
+ instructions[i] = values.instructions[i];
+}
+
+ValueSet::~ValueSet(void)
+{
+ delete[] instructions;
+}
+
+void ValueSet::FlushAll(void)
+{
+ num = 0;
+}
+
+void ValueSet::FlushCallAliases(void)
+{
+ int i;
+
+ i = 0;
+
+ while (i < num)
+ {
+ if ((instructions[i]->code == IC_LOAD || instructions[i]->code == IC_STORE) && instructions[i]->mem != IM_PARAM && instructions[i]->mem != IM_LOCAL)
+ {
+ //
+ // potential alias load
+ //
+ num--;
+ if (i < num)
+ {
+ instructions[i] = instructions[num];
+ }
+ }
+ else
+ i++;
+ }
+}
+
+static __int64 ConstantFolding(InterOperator oper, __int64 val1, __int64 val2)
+{
+ switch (oper)
+ {
+ case IA_ADD:
+ return val1 + val2;
+ break;
+ case IA_SUB:
+ return val1 - val2;
+ break;
+ case IA_MUL:
+ return val1 * val2;
+ break;
+ case IA_DIVU:
+ return (unsigned __int64)val1 / (unsigned __int64)val2;
+ break;
+ case IA_DIVS:
+ return val1 / val2;
+ break;
+ case IA_MODU:
+ return (unsigned __int64)val1 % (unsigned __int64)val2;
+ break;
+ case IA_MODS:
+ return val1 % val2;
+ break;
+ case IA_OR:
+ return val1 | val2;
+ break;
+ case IA_AND:
+ return val1 & val2;
+ break;
+ case IA_XOR:
+ return val1 ^ val2;
+ break;
+ case IA_NEG:
+ return -val1;
+ break;
+ case IA_NOT:
+ return ~val1;
+ break;
+ case IA_SHL:
+ return val1 << val2;
+ break;
+ case IA_SHR:
+ return (unsigned __int64)val1 >> (unsigned __int64)val2;
+ break;
+ case IA_SAR:
+ return val1 >> val2;
+ break;
+ case IA_CMPEQ:
+ return val1 == val2 ? 1 : 0;
+ break;
+ case IA_CMPNE:
+ return val1 != val2 ? 1 : 0;
+ break;
+ case IA_CMPGES:
+ return val1 >= val2 ? 1 : 0;
+ break;
+ case IA_CMPLES:
+ return val1 <= val2 ? 1 : 0;
+ break;
+ case IA_CMPGS:
+ return val1 > val2 ? 1 : 0;
+ break;
+ case IA_CMPLS:
+ return val1 < val2 ? 1 : 0;
+ break;
+ case IA_CMPGEU:
+ return (unsigned __int64)val1 >= (unsigned __int64)val2 ? 1 : 0;
+ break;
+ case IA_CMPLEU:
+ return (unsigned __int64)val1 <= (unsigned __int64)val2 ? 1 : 0;
+ break;
+ case IA_CMPGU:
+ return (unsigned __int64)val1 > (unsigned __int64)val2 ? 1 : 0;
+ break;
+ case IA_CMPLU:
+ return (unsigned __int64)val1 < (unsigned __int64)val2 ? 1 : 0;
+ break;
+ default:
+ return 0;
+ }
+}
+
+static __int64 ConstantRelationalFolding(InterOperator oper, double val1, double val2)
+{
+ switch (oper)
+ {
+ case IA_CMPEQ:
+ return val1 == val2 ? 1 : 0;
+ break;
+ case IA_CMPNE:
+ return val1 != val2 ? 1 : 0;
+ break;
+ case IA_CMPGES:
+ case IA_CMPGEU:
+ return val1 >= val2 ? 1 : 0;
+ break;
+ case IA_CMPLES:
+ case IA_CMPLEU:
+ return val1 <= val2 ? 1 : 0;
+ break;
+ case IA_CMPGS:
+ case IA_CMPGU:
+ return val1 > val2 ? 1 : 0;
+ break;
+ case IA_CMPLS:
+ case IA_CMPLU:
+ return val1 < val2 ? 1 : 0;
+ break;
+ default:
+ return 0;
+ }
+}
+
+static double ConstantFolding(InterOperator oper, double val1, double val2 = 0.0)
+{
+ switch (oper)
+ {
+ case IA_ADD:
+ return val1 + val2;
+ break;
+ case IA_SUB:
+ return val1 - val2;
+ break;
+ case IA_MUL:
+ return val1 * val2;
+ break;
+ case IA_DIVU:
+ case IA_DIVS:
+ return val1 / val2;
+ break;
+ case IA_NEG:
+ return -val1;
+ break;
+ case IA_ABS:
+ return fabs(val1);
+ break;
+ case IA_FLOOR:
+ return floor(val1);
+ break;
+ case IA_CEIL:
+ return ceil(val1);
+ break;
+
+ default:
+ return 0;
+ }
+}
+
+void ValueSet::InsertValue(InterInstruction& ins)
+{
+ InterInstructionPtr* nins;
+ int i;
+
+ if (num == size)
+ {
+ size *= 2;
+ nins = new InterInstructionPtr[size];
+ for (i = 0; i < num; i++)
+ nins[i] = instructions[i];
+ delete[] instructions;
+ instructions = nins;
+ }
+
+ instructions[num++] = &ins;
+}
+
+static bool MemPtrRange(const InterInstruction* ins, const GrowingInstructionPtrArray& tvalue, InterMemory& mem, int& vindex, int& offset)
+{
+ while (ins && ins->mem == IM_INDIRECT && ins->code == IC_LEA)
+ ins = tvalue[ins->stemp[1]];
+
+ if (ins && (ins->code == IC_CONSTANT || ins->code == IC_LEA))
+ {
+ mem = ins->mem;
+ vindex = ins->vindex;
+ offset = ins->ivalue;
+
+ return true;
+ }
+ else
+ return false;
+}
+
+
+static bool MemRange(const InterInstruction * ins, const GrowingInstructionPtrArray& tvalue, InterMemory& mem, int& vindex, int& offset)
+{
+ if (ins->mem == IM_INDIRECT)
+ {
+ if (ins->code == IC_LOAD)
+ return MemPtrRange(tvalue[ins->stemp[0]], tvalue, mem, vindex, offset);
+ else
+ return MemPtrRange(tvalue[ins->stemp[1]], tvalue, mem, vindex, offset);
+ }
+ if (ins)
+ {
+ mem = ins->mem;
+ vindex = ins->vindex;
+ offset = ins->ivalue;
+
+ return true;
+ }
+ else
+ return false;
+}
+
+static bool StoreAliasing(const InterInstruction * lins, const InterInstruction* sins, const GrowingInstructionPtrArray& tvalue, const NumberSet& aliasedLocals)
+{
+ InterMemory lmem, smem;
+ int lvindex, svindex;
+ int loffset, soffset;
+
+ if (MemRange(lins, tvalue, lmem, lvindex, loffset) && MemRange(sins, tvalue, smem, svindex, soffset))
+ {
+ if (smem == lmem && svindex == lvindex)
+ {
+ if (soffset + sins->opsize >= loffset && loffset + lins->opsize >= soffset)
+ return true;
+ }
+
+ return false;
+ }
+
+ if (lmem == IM_LOCAL)
+ return aliasedLocals[lvindex];
+
+ return true;
+}
+
+void ValueSet::UpdateValue(InterInstruction& ins, const GrowingInstructionPtrArray& tvalue, const NumberSet& aliasedLocals)
+{
+ int i, value, temp;
+
+ temp = ins.ttemp;
+
+ if (temp >= 0)
+ {
+ i = 0;
+ while (i < num)
+ {
+ if (temp == instructions[i]->ttemp ||
+ temp == instructions[i]->stemp[0] ||
+ temp == instructions[i]->stemp[1] ||
+ temp == instructions[i]->stemp[2])
+ {
+ num--;
+ if (i < num)
+ instructions[i] = instructions[num];
+ }
+ else
+ i++;
+ }
+ }
+
+ for (i = 0; i < 3; i++)
+ {
+ temp = ins.stemp[i];
+ if (temp >= 0 && tvalue[temp])
+ {
+ ins.stemp[i] = tvalue[temp]->ttemp;
+ }
+ }
+
+ switch (ins.code)
+ {
+ case IC_LOAD:
+ i = 0;
+ while (i < num &&
+ (instructions[i]->code != IC_LOAD ||
+ instructions[i]->stemp[0] != ins.stemp[0] ||
+ instructions[i]->opsize != ins.opsize))
+ {
+ i++;
+ }
+
+ if (i < num)
+ {
+ ins.code = IC_LOAD_TEMPORARY;
+ ins.stemp[0] = instructions[i]->ttemp;
+ ins.stype[0] = instructions[i]->ttype;
+ assert(ins.stemp[0] >= 0);
+ }
+ else
+ {
+ i = 0;
+ while (i < num &&
+ (instructions[i]->code != IC_STORE ||
+ instructions[i]->stemp[1] != ins.stemp[0] ||
+ instructions[i]->opsize != ins.opsize))
+ {
+ i++;
+ }
+
+ if (i < num)
+ {
+ if (instructions[i]->stemp[0] < 0)
+ {
+ ins.code = IC_CONSTANT;
+ ins.stemp[0] = -1;
+ ins.stype[0] = instructions[i]->stype[0];
+ ins.ivalue = instructions[i]->siconst[0];
+ }
+ else
+ {
+ ins.code = IC_LOAD_TEMPORARY;
+ ins.stemp[0] = instructions[i]->stemp[0];
+ ins.stype[0] = instructions[i]->stype[0];
+ assert(ins.stemp[0] >= 0);
+ }
+ }
+ else
+ {
+ InsertValue(ins);
+ }
+ }
+
+ break;
+ case IC_STORE:
+ i = 0;
+ while (i < num)
+ {
+ if ((instructions[i]->code == IC_LOAD || instructions[i]->code == IC_STORE) && StoreAliasing(instructions[i], &ins, tvalue, aliasedLocals))
+ {
+ num--;
+ if (num > 0)
+ instructions[i] = instructions[num];
+ }
+ else
+ i++;
+ }
+
+ InsertValue(ins);
+ break;
+ case IC_COPY:
+ i = 0;
+ while (i < num)
+ {
+ if ((instructions[i]->code == IC_LOAD || instructions[i]->code == IC_STORE) && StoreAliasing(instructions[i], &ins, tvalue, aliasedLocals))
+ {
+ num--;
+ if (num > 0)
+ instructions[i] = instructions[num];
+ }
+ else
+ i++;
+ }
+
+ break;
+
+ case IC_CONSTANT:
+ switch (ins.ttype)
+ {
+ case IT_FLOAT:
+ i = 0;
+ while (i < num &&
+ (instructions[i]->code != IC_CONSTANT ||
+ instructions[i]->ttype != ins.ttype ||
+ instructions[i]->fvalue != ins.fvalue))
+ {
+ i++;
+ }
+ break;
+ case IT_POINTER:
+ i = 0;
+ while (i < num &&
+ (instructions[i]->code != IC_CONSTANT ||
+ instructions[i]->ttype != ins.ttype ||
+ instructions[i]->ivalue != ins.ivalue ||
+ instructions[i]->mem != ins.mem ||
+ instructions[i]->vindex != ins.vindex))
+ {
+ i++;
+ }
+ break;
+ default:
+
+ i = 0;
+ while (i < num &&
+ (instructions[i]->code != IC_CONSTANT ||
+ instructions[i]->ttype != ins.ttype ||
+ instructions[i]->ivalue != ins.ivalue))
+ {
+ i++;
+ }
+ }
+
+ if (i < num)
+ {
+ ins.code = IC_LOAD_TEMPORARY;
+ ins.stemp[0] = instructions[i]->ttemp;
+ ins.stype[0] = instructions[i]->ttype;
+ assert(ins.stemp[0] >= 0);
+ }
+ else
+ {
+ InsertValue(ins);
+ }
+ break;
+
+ case IC_LEA:
+ i = 0;
+ while (i < num &&
+ (instructions[i]->code != IC_LEA ||
+ instructions[i]->stemp[0] != ins.stemp[0] ||
+ instructions[i]->stemp[1] != ins.stemp[1]))
+ {
+ i++;
+ }
+
+ if (i < num)
+ {
+ ins.code = IC_LOAD_TEMPORARY;
+ ins.stemp[0] = instructions[i]->ttemp;
+ ins.stype[0] = instructions[i]->ttype;
+ ins.stemp[1] = -1;
+ assert(ins.stemp[0] >= 0);
+ }
+ else
+ {
+ InsertValue(ins);
+ }
+ break;
+
+ case IC_BINARY_OPERATOR:
+ switch (ins.stype[0])
+ {
+ case IT_FLOAT:
+ if (ins.stemp[1] >= 0 && tvalue[ins.stemp[1]] && tvalue[ins.stemp[1]]->code == IC_CONSTANT &&
+ ins.stemp[0] >= 0 && tvalue[ins.stemp[0]] && tvalue[ins.stemp[0]]->code == IC_CONSTANT)
+ {
+ ins.code = IC_CONSTANT;
+ ins.fvalue = ConstantFolding(ins.oper, tvalue[ins.stemp[1]]->fvalue, tvalue[ins.stemp[0]]->fvalue);
+ ins.stemp[0] = -1;
+ ins.stemp[1] = -1;
+
+ i = 0;
+ while (i < num &&
+ (instructions[i]->code != IC_CONSTANT ||
+ instructions[i]->ttype != ins.ttype ||
+ instructions[i]->fvalue != ins.fvalue))
+ {
+ i++;
+ }
+
+ if (i < num)
+ {
+ ins.code = IC_LOAD_TEMPORARY;
+ ins.stemp[0] = instructions[i]->ttemp;
+ ins.stype[0] = instructions[i]->ttype;
+ assert(ins.stemp[0] >= 0);
+ }
+ else
+ {
+ InsertValue(ins);
+ }
+ }
+ else
+ {
+ i = 0;
+ while (i < num &&
+ (instructions[i]->code != IC_BINARY_OPERATOR ||
+ instructions[i]->oper != ins.oper ||
+ instructions[i]->stemp[0] != ins.stemp[0] ||
+ instructions[i]->stemp[1] != ins.stemp[1]))
+ {
+ i++;
+ }
+
+ if (i < num)
+ {
+ ins.code = IC_LOAD_TEMPORARY;
+ ins.stemp[0] = instructions[i]->ttemp;
+ ins.stype[0] = instructions[i]->ttype;
+ ins.stemp[1] = -1;
+ assert(ins.stemp[0] >= 0);
+ }
+ else
+ {
+ InsertValue(ins);
+ }
+ }
+ break;
+ case IT_POINTER:
+ break;
+ default:
+ if (ins.stemp[1] >= 0 && tvalue[ins.stemp[1]] && tvalue[ins.stemp[1]]->code == IC_CONSTANT &&
+ ins.stemp[0] >= 0 && tvalue[ins.stemp[0]] && tvalue[ins.stemp[0]]->code == IC_CONSTANT)
+ {
+ ins.code = IC_CONSTANT;
+ ins.ivalue = ConstantFolding(ins.oper, tvalue[ins.stemp[1]]->ivalue, tvalue[ins.stemp[0]]->ivalue);
+ ins.stemp[0] = -1;
+ ins.stemp[1] = -1;
+
+ UpdateValue(ins, tvalue, aliasedLocals);
+
+ return;
+ }
+
+ if (ins.stemp[0] >= 0 && tvalue[ins.stemp[0]] && tvalue[ins.stemp[0]]->code == IC_CONSTANT)
+ {
+ if ((ins.oper == IA_ADD || ins.oper == IA_SUB ||
+ ins.oper == IA_OR || ins.oper == IA_XOR ||
+ ins.oper == IA_SHL || ins.oper == IA_SHR || ins.oper == IA_SAR) && tvalue[ins.stemp[0]]->ivalue == 0 ||
+ (ins.oper == IA_MUL || ins.oper == IA_DIVU || ins.oper == IA_DIVS) && tvalue[ins.stemp[0]]->ivalue == 1 ||
+ (ins.oper == IA_AND) && tvalue[ins.stemp[0]]->ivalue == -1)
+ {
+ ins.code = IC_LOAD_TEMPORARY;
+ ins.stemp[0] = ins.stemp[1];
+ ins.stype[0] = ins.stype[1];
+ ins.stemp[1] = -1;
+ assert(ins.stemp[0] >= 0);
+
+ UpdateValue(ins, tvalue, aliasedLocals);
+
+ return;
+ }
+ else if ((ins.oper == IA_MUL || ins.oper == IA_AND) && tvalue[ins.stemp[0]]->ivalue == 0)
+ {
+ ins.code = IC_CONSTANT;
+ ins.ivalue = 0;
+ ins.stemp[0] = -1;
+ ins.stemp[1] = -1;
+
+ UpdateValue(ins, tvalue, aliasedLocals);
+
+ return;
+ }
+ }
+ else if (ins.stemp[1] >= 0 && tvalue[ins.stemp[1]] && tvalue[ins.stemp[1]]->code == IC_CONSTANT)
+ {
+ if ((ins.oper == IA_ADD || ins.oper == IA_OR || ins.oper == IA_XOR) && tvalue[ins.stemp[1]]->ivalue == 0 ||
+ (ins.oper == IA_MUL) && tvalue[ins.stemp[1]]->ivalue == 1 ||
+ (ins.oper == IA_AND) && tvalue[ins.stemp[1]]->ivalue == -1)
+ {
+ ins.code = IC_LOAD_TEMPORARY;
+ ins.stemp[1] = -1;
+ assert(ins.stemp[0] >= 0);
+
+ UpdateValue(ins, tvalue, aliasedLocals);
+
+ return;
+ }
+ else if ((ins.oper == IA_MUL || ins.oper == IA_AND ||
+ ins.oper == IA_SHL || ins.oper == IA_SHR || ins.oper == IA_SAR) && tvalue[ins.stemp[1]]->ivalue == 0)
+ {
+ ins.code = IC_CONSTANT;
+ ins.ivalue = 0;
+ ins.stemp[0] = -1;
+ ins.stemp[1] = -1;
+
+ UpdateValue(ins, tvalue, aliasedLocals);
+
+ return;
+ }
+ else if (ins.oper == IA_SUB && tvalue[ins.stemp[1]]->ivalue == 0)
+ {
+ ins.code = IC_UNARY_OPERATOR;
+ ins.oper = IA_NEG;
+ ins.stemp[1] = -1;
+
+ UpdateValue(ins, tvalue, aliasedLocals);
+
+ return;
+ }
+ }
+ else if (ins.stemp[0] == ins.stemp[1])
+ {
+ if (ins.oper == IA_SUB || ins.oper == IA_XOR)
+ {
+ ins.code = IC_CONSTANT;
+ ins.ivalue = 0;
+ ins.stemp[0] = -1;
+ ins.stemp[1] = -1;
+
+ UpdateValue(ins, tvalue, aliasedLocals);
+
+ return;
+ }
+ else if (ins.oper == IA_AND || ins.oper == IA_OR)
+ {
+ ins.code = IC_LOAD_TEMPORARY;
+ ins.stemp[1] = -1;
+ assert(ins.stemp[0] >= 0);
+
+ UpdateValue(ins, tvalue, aliasedLocals);
+
+ return;
+ }
+ }
+
+ i = 0;
+ while (i < num &&
+ (instructions[i]->code != IC_BINARY_OPERATOR ||
+ instructions[i]->oper != ins.oper ||
+ instructions[i]->stemp[0] != ins.stemp[0] ||
+ instructions[i]->stemp[1] != ins.stemp[1]))
+ {
+ i++;
+ }
+
+ if (i < num)
+ {
+ ins.code = IC_LOAD_TEMPORARY;
+ ins.stemp[0] = instructions[i]->ttemp;
+ ins.stype[0] = instructions[i]->ttype;
+ ins.stemp[1] = -1;
+ assert(ins.stemp[0] >= 0);
+ }
+ else
+ {
+ InsertValue(ins);
+ }
+ break;
+ }
+ break;
+
+ case IC_CONVERSION_OPERATOR:
+ if (ins.oper == IA_INT2FLOAT)
+ {
+ if (ins.stemp[0] >= 0 && tvalue[ins.stemp[0]] && tvalue[ins.stemp[0]]->code == IC_CONSTANT)
+ {
+ ins.code = IC_CONSTANT;
+ ins.fvalue = (double)(tvalue[ins.stemp[0]]->ivalue);
+ ins.stemp[0] = -1;
+
+ i = 0;
+ while (i < num &&
+ (instructions[i]->code != IC_CONSTANT ||
+ instructions[i]->ttype != ins.ttype ||
+ instructions[i]->fvalue != ins.fvalue))
+ {
+ i++;
+ }
+
+ if (i < num)
+ {
+ ins.code = IC_LOAD_TEMPORARY;
+ ins.stemp[0] = instructions[i]->ttemp;
+ ins.stype[0] = instructions[i]->ttype;
+ assert(ins.stemp[0] >= 0);
+ }
+ else
+ {
+ InsertValue(ins);
+ }
+ }
+ else
+ {
+ i = 0;
+ while (i < num &&
+ (instructions[i]->code != IC_CONVERSION_OPERATOR ||
+ instructions[i]->oper != ins.oper ||
+ instructions[i]->stemp[0] != ins.stemp[0]))
+ {
+ i++;
+ }
+
+ if (i < num)
+ {
+ ins.code = IC_LOAD_TEMPORARY;
+ ins.stemp[0] = instructions[i]->ttemp;
+ ins.stype[0] = instructions[i]->ttype;
+ ins.stemp[1] = -1;
+ assert(ins.stemp[0] >= 0);
+ }
+ else
+ {
+ InsertValue(ins);
+ }
+ }
+ }
+ else if (ins.oper == IA_FLOAT2INT)
+ {
+ }
+ break;
+
+ case IC_UNARY_OPERATOR:
+ switch (ins.stype[0])
+ {
+ case IT_FLOAT:
+ if (ins.stemp[0] >= 0 && tvalue[ins.stemp[0]] && tvalue[ins.stemp[0]]->code == IC_CONSTANT)
+ {
+ ins.code = IC_CONSTANT;
+ ins.fvalue = ConstantFolding(ins.oper, tvalue[ins.stemp[0]]->fvalue);
+ ins.stemp[0] = -1;
+
+ i = 0;
+ while (i < num &&
+ (instructions[i]->code != IC_CONSTANT ||
+ instructions[i]->ttype != ins.ttype ||
+ instructions[i]->fvalue != ins.fvalue))
+ {
+ i++;
+ }
+
+ if (i < num)
+ {
+ ins.code = IC_LOAD_TEMPORARY;
+ ins.stemp[0] = instructions[i]->ttemp;
+ ins.stype[0] = instructions[i]->ttype;
+ assert(ins.stemp[0] >= 0);
+ }
+ else
+ {
+ InsertValue(ins);
+ }
+ }
+ else
+ {
+ i = 0;
+ while (i < num &&
+ (instructions[i]->code != IC_UNARY_OPERATOR ||
+ instructions[i]->oper != ins.oper ||
+ instructions[i]->stemp[0] != ins.stemp[0]))
+ {
+ i++;
+ }
+
+ if (i < num)
+ {
+ ins.code = IC_LOAD_TEMPORARY;
+ ins.stemp[0] = instructions[i]->ttemp;
+ ins.stype[0] = instructions[i]->ttype;
+ ins.stemp[1] = -1;
+ assert(ins.stemp[0] >= 0);
+ }
+ else
+ {
+ InsertValue(ins);
+ }
+ }
+ break;
+ case IT_POINTER:
+ break;
+ default:
+ if (ins.stemp[0] >= 0 && tvalue[ins.stemp[0]] && tvalue[ins.stemp[0]]->code == IC_CONSTANT)
+ {
+ ins.code = IC_CONSTANT;
+ ins.ivalue = ConstantFolding(ins.oper, tvalue[ins.stemp[0]]->ivalue);
+ ins.stemp[0] = -1;
+
+ i = 0;
+ while (i < num &&
+ (instructions[i]->code != IC_CONSTANT ||
+ instructions[i]->ttype != ins.ttype ||
+ instructions[i]->ivalue != ins.ivalue))
+ {
+ i++;
+ }
+
+ if (i < num)
+ {
+ ins.code = IC_LOAD_TEMPORARY;
+ ins.stemp[0] = instructions[i]->ttemp;
+ ins.stype[0] = instructions[i]->ttype;
+ assert(ins.stemp[0] >= 0);
+ }
+ else
+ {
+ InsertValue(ins);
+ }
+ }
+ else
+ {
+ i = 0;
+ while (i < num &&
+ (instructions[i]->code != IC_UNARY_OPERATOR ||
+ instructions[i]->oper != ins.oper ||
+ instructions[i]->stemp[0] != ins.stemp[0]))
+ {
+ i++;
+ }
+
+ if (i < num)
+ {
+ ins.code = IC_LOAD_TEMPORARY;
+ ins.stemp[0] = instructions[i]->ttemp;
+ ins.stype[0] = instructions[i]->ttype;
+ assert(ins.stemp[0] >= 0);
+ }
+ else
+ {
+ InsertValue(ins);
+ }
+ }
+ break;
+ }
+ break;
+
+ case IC_RELATIONAL_OPERATOR:
+ switch (ins.stype[1])
+ {
+ case IT_FLOAT:
+ if (ins.stemp[1] >= 0 && tvalue[ins.stemp[1]] && tvalue[ins.stemp[1]]->code == IC_CONSTANT &&
+ ins.stemp[0] >= 0 && tvalue[ins.stemp[0]] && tvalue[ins.stemp[0]]->code == IC_CONSTANT)
+ {
+ ins.code = IC_CONSTANT;
+ ins.ivalue = ConstantRelationalFolding(ins.oper, tvalue[ins.stemp[1]]->fvalue, tvalue[ins.stemp[0]]->fvalue);
+ ins.stemp[0] = -1;
+ ins.stemp[1] = -1;
+
+ UpdateValue(ins, tvalue, aliasedLocals);
+ }
+ break;
+ case IT_POINTER:
+ break;
+ default:
+ if (ins.stemp[1] >= 0 && tvalue[ins.stemp[1]] && tvalue[ins.stemp[1]]->code == IC_CONSTANT &&
+ ins.stemp[0] >= 0 && tvalue[ins.stemp[0]] && tvalue[ins.stemp[0]]->code == IC_CONSTANT)
+ {
+ ins.code = IC_CONSTANT;
+ ins.ivalue = ConstantFolding(ins.oper, tvalue[ins.stemp[1]]->ivalue, tvalue[ins.stemp[0]]->ivalue);
+ ins.stemp[0] = -1;
+ ins.stemp[1] = -1;
+
+ UpdateValue(ins, tvalue, aliasedLocals);
+ }
+ else if (ins.stemp[1] == ins.stemp[0])
+ {
+ ins.code = IC_CONSTANT;
+
+ switch (ins.oper)
+ {
+ case IA_CMPEQ:
+ case IA_CMPGES:
+ case IA_CMPLES:
+ case IA_CMPGEU:
+ case IA_CMPLEU:
+ ins.ivalue = 1;
+ break;
+ case IA_CMPNE:
+ case IA_CMPGS:
+ case IA_CMPLS:
+ case IA_CMPGU:
+ case IA_CMPLU:
+ ins.ivalue = 0;
+ break;
+ }
+ ins.stemp[0] = -1;
+ ins.stemp[1] = -1;
+
+ UpdateValue(ins, tvalue, aliasedLocals);
+ }
+ break;
+ }
+ break;
+ case IC_CALL:
+ case IC_JSR:
+ FlushCallAliases();
+ break;
+
+ }
+}
+
+InterInstruction::InterInstruction(void)
+{
+ code = IC_NONE;
+
+ ttype = IT_NONE;
+ stype[0] = IT_NONE;
+ stype[1] = IT_NONE;
+ stype[2] = IT_NONE;
+
+ ttemp = INVALID_TEMPORARY;
+ stemp[0] = INVALID_TEMPORARY;
+ stemp[1] = INVALID_TEMPORARY;
+ stemp[2] = INVALID_TEMPORARY;
+
+ exceptionJump = NULL;
+}
+
+void InterInstruction::SetCode(const Location& loc, InterCode code)
+{
+ this->code = code;
+ this->loc = loc;
+}
+
+static bool TypeInteger(InterType t)
+{
+ return t == IT_UNSIGNED || t == IT_SIGNED || t == IT_BOOL || t == IT_POINTER;
+}
+
+static bool TypeCompatible(InterType t1, InterType t2)
+{
+ return t1 == t2 || TypeInteger(t1) && TypeInteger(t2);
+}
+
+static bool TypeArithmetic(InterType t)
+{
+ return t == IT_UNSIGNED || t == IT_SIGNED || t == IT_BOOL || t == IT_FLOAT;
+}
+
+static InterType TypeCheckArithmecitResult(InterType t1, InterType t2)
+{
+ if (t1 == IT_FLOAT && t2 == IT_FLOAT)
+ return IT_FLOAT;
+ else if (TypeInteger(t1) && TypeInteger(t2))
+ return IT_SIGNED;
+ else
+ throw InterCodeTypeMismatchException();
+}
+
+static void TypeCheckAssign(InterType& t, InterType s)
+{
+ if (s == IT_NONE)
+ throw InterCodeUninitializedException();
+ else if (t == IT_NONE)
+ t = s;
+ else if (!TypeCompatible(t, s))
+ throw InterCodeTypeMismatchException();
+}
+
+
+
+static void FilterTempUseUsage(NumberSet& requiredTemps, NumberSet& providedTemps, int temp)
+{
+ if (temp >= 0)
+ {
+ if (!providedTemps[temp]) requiredTemps += temp;
+ }
+}
+
+static void FilterTempDefineUsage(NumberSet& requiredTemps, NumberSet& providedTemps, int temp)
+{
+ if (temp >= 0)
+ {
+ providedTemps += temp;
+ }
+}
+
+void InterInstruction::CollectLocalAddressTemps(GrowingIntArray& localTable)
+{
+ if (code == IC_CONSTANT)
+ {
+ if (ttype == IT_POINTER && mem == IM_LOCAL)
+ localTable[ttemp] = vindex;
+ }
+ else if (code == IC_LEA)
+ {
+ if (mem == IM_LOCAL)
+ localTable[ttemp] = localTable[stemp[1]];
+ }
+ else if (code == IC_LOAD_TEMPORARY)
+ {
+ localTable[ttemp] = localTable[stemp[0]];
+ }
+}
+
+void InterInstruction::MarkAliasedLocalTemps(const GrowingIntArray& localTable, NumberSet& aliasedLocals)
+{
+ if (code == IC_STORE)
+ {
+ int l = localTable[stemp[0]];
+ if (l >= 0)
+ aliasedLocals += l;
+ }
+}
+
+void InterInstruction::FilterTempUsage(NumberSet& requiredTemps, NumberSet& providedTemps)
+{
+ FilterTempUseUsage(requiredTemps, providedTemps, stemp[0]);
+ FilterTempUseUsage(requiredTemps, providedTemps, stemp[1]);
+ FilterTempUseUsage(requiredTemps, providedTemps, stemp[2]);
+ FilterTempDefineUsage(requiredTemps, providedTemps, ttemp);
+}
+
+void InterInstruction::FilterVarsUsage(const GrowingVariableArray& localVars, NumberSet& requiredVars, NumberSet& providedVars)
+{
+ if (code == IC_LOAD && mem == IM_LOCAL)
+ {
+ assert(stemp[0] < 0);
+ if (!providedVars[vindex])
+ requiredVars += vindex;
+ }
+ else if (code == IC_STORE && mem == IM_LOCAL)
+ {
+ assert(stemp[1] < 0);
+ if (!providedVars[vindex] && (siconst[1] != 0 || opsize != localVars[vindex].mSize))
+ requiredVars += vindex;
+ providedVars += vindex;
+ }
+}
+
+static void PerformTempUseForwarding(int& temp, TempForwardingTable& forwardingTable)
+{
+ if (temp >= 0)
+ temp = forwardingTable[temp];
+}
+
+static void PerformTempDefineForwarding(int temp, TempForwardingTable& forwardingTable)
+{
+ if (temp >= 0)
+ {
+ forwardingTable.Destroy(temp);
+ }
+}
+
+void InterInstruction::PerformTempForwarding(TempForwardingTable& forwardingTable)
+{
+ PerformTempUseForwarding(stemp[0], forwardingTable);
+ PerformTempUseForwarding(stemp[1], forwardingTable);
+ PerformTempUseForwarding(stemp[2], forwardingTable);
+ PerformTempDefineForwarding(ttemp, forwardingTable);
+ if (code == IC_LOAD_TEMPORARY && ttemp != stemp[0])
+ {
+ forwardingTable.Build(ttemp, stemp[0]);
+ }
+}
+
+bool HasSideEffect(InterCode code)
+{
+ return code == IC_CALL || code == IC_JSR;
+}
+
+bool InterInstruction::RemoveUnusedResultInstructions(InterInstruction* pre, NumberSet& requiredTemps, int numStaticTemps)
+{
+ bool changed = false;
+
+ if (pre && code == IC_LOAD_TEMPORARY && pre->ttemp == stemp[0] && !requiredTemps[stemp[0]] && pre->ttemp >= numStaticTemps)
+ {
+ // previous instruction produced result, but it is not needed here
+ pre->ttemp = ttemp;
+
+ code = IC_NONE;
+ ttemp = -1;
+ stemp[0] = -1;
+ stemp[1] = -1;
+ stemp[2] = -1;
+
+ changed = true;
+ }
+ else if (ttemp != -1)
+ {
+ if (!requiredTemps[ttemp] && ttemp >= numStaticTemps)
+ {
+ if (!HasSideEffect(code))
+ {
+ code = IC_NONE;
+ ttemp = -1;
+ stemp[0] = -1;
+ stemp[1] = -1;
+ stemp[2] = -1;
+
+ changed = true;
+ }
+ else
+ {
+ ttemp = -1;
+
+ changed = true;
+ }
+ }
+ else
+ requiredTemps -= ttemp;
+ }
+
+ if (stemp[0] >= 0) sfinal[0] = !requiredTemps[stemp[0]] && stemp[0] >= numStaticTemps;
+ if (stemp[1] >= 0) sfinal[1] = !requiredTemps[stemp[1]] && stemp[1] >= numStaticTemps;
+ if (stemp[2] >= 0) sfinal[2] = !requiredTemps[stemp[2]] && stemp[2] >= numStaticTemps;
+
+ if (stemp[0] >= 0) requiredTemps += stemp[0];
+ if (stemp[1] >= 0) requiredTemps += stemp[1];
+ if (stemp[2] >= 0) requiredTemps += stemp[2];
+
+ return changed;
+}
+
+bool InterInstruction::RemoveUnusedStoreInstructions(const GrowingVariableArray& localVars, InterInstruction* pre, NumberSet& requiredTemps)
+{
+ bool changed = false;
+
+ if (code == IC_LOAD)
+ {
+ if (mem == IM_LOCAL)
+ {
+ requiredTemps += vindex;
+ }
+ }
+ else if (code == IC_STORE)
+ {
+ if (mem == IM_LOCAL)
+ {
+ if (localVars[vindex].mAliased)
+ ;
+ else if (requiredTemps[vindex])
+ {
+ if (siconst[1] == 0 && opsize == localVars[vindex].mSize)
+ requiredTemps -= vindex;
+ }
+ else
+ {
+ code = IC_NONE;
+ changed = true;
+ }
+ }
+ }
+
+ return changed;
+}
+
+static void DestroySourceValues(int temp, GrowingInstructionPtrArray& tvalue, FastNumberSet& tvalid)
+{
+ int i, j;
+ const InterInstruction* ins;
+
+ if (temp >= 0)
+ {
+ i = 0;
+ while (i < tvalid.Num())
+ {
+ j = tvalid.Element(i);
+
+ ins = tvalue[j];
+
+ if (ins->stemp[0] == temp || ins->stemp[1] == temp || ins->stemp[2] == temp)
+ {
+ tvalue[j] = NULL;
+ tvalid -= j;
+ }
+ else
+ i++;
+ }
+ }
+}
+
+void InterInstruction::PerformValueForwarding(GrowingInstructionPtrArray& tvalue, FastNumberSet& tvalid)
+{
+ DestroySourceValues(ttemp, tvalue, tvalid);
+
+ if (code == IC_LOAD_TEMPORARY)
+ {
+ if (tvalue[stemp[0]])
+ {
+ tvalue[ttemp] = tvalue[stemp[0]];
+ tvalid += ttemp;
+ }
+ }
+ else
+ {
+ if (ttemp >= 0)
+ {
+ tvalue[ttemp] = this;
+ tvalid += ttemp;
+ }
+ }
+}
+
+void InterInstruction::LocalRenameRegister(GrowingIntArray& renameTable, int& num, int fixed)
+{
+ if (stemp[0] >= 0) stemp[0] = renameTable[stemp[0]];
+ if (stemp[1] >= 0) stemp[1] = renameTable[stemp[1]];
+ if (stemp[2] >= 0) stemp[2] = renameTable[stemp[2]];
+
+ if (ttemp >= fixed)
+ {
+ renameTable[ttemp] = num;
+ ttemp = num++;
+ }
+}
+
+void InterInstruction::GlobalRenameRegister(const GrowingIntArray& renameTable, GrowingTypeArray& temporaries)
+{
+ if (stemp[0] >= 0) stemp[0] = renameTable[stemp[0]];
+ if (stemp[1] >= 0) stemp[1] = renameTable[stemp[1]];
+ if (stemp[2] >= 0) stemp[2] = renameTable[stemp[2]];
+
+ if (ttemp >= 0)
+ {
+ ttemp = renameTable[ttemp];
+ temporaries[ttemp] = ttype;
+ }
+}
+
+static void UpdateCollisionSet(NumberSet& liveTemps, NumberSet* collisionSets, int temp)
+{
+ int i;
+
+ if (temp >= 0 && !liveTemps[temp])
+ {
+ for (i = 0; i < liveTemps.Size(); i++)
+ {
+ if (liveTemps[i])
+ {
+ collisionSets[i] += temp;
+ collisionSets[temp] += i;
+ }
+ }
+
+ liveTemps += temp;
+ }
+}
+
+void InterInstruction::BuildCollisionTable(NumberSet& liveTemps, NumberSet* collisionSets)
+{
+ if (ttemp >= 0)
+ {
+ // if (!liveTemps[ttemp]) __asm int 3
+ liveTemps -= ttemp;
+ }
+
+ UpdateCollisionSet(liveTemps, collisionSets, stemp[0]);
+ UpdateCollisionSet(liveTemps, collisionSets, stemp[1]);
+ UpdateCollisionSet(liveTemps, collisionSets, stemp[2]);
+
+ if (exceptionJump)
+ {
+ int i;
+
+ for (i = 0; i < exceptionJump->entryRequiredTemps.Size(); i++)
+ {
+ if (exceptionJump->entryRequiredTemps[i])
+ UpdateCollisionSet(liveTemps, collisionSets, i);
+ }
+ }
+}
+
+void InterInstruction::ReduceTemporaries(const GrowingIntArray& renameTable, GrowingTypeArray& temporaries)
+{
+ if (stemp[0] >= 0) stemp[0] = renameTable[stemp[0]];
+ if (stemp[1] >= 0) stemp[1] = renameTable[stemp[1]];
+ if (stemp[2] >= 0) stemp[2] = renameTable[stemp[2]];
+
+ if (ttemp >= 0)
+ {
+ ttemp = renameTable[ttemp];
+ temporaries[ttemp] = ttype;
+ }
+}
+
+
+void InterInstruction::CollectActiveTemporaries(FastNumberSet& set)
+{
+ if (ttemp >= 0) set += ttemp;
+ if (stemp[0] >= 0) set += stemp[0];
+ if (stemp[1] >= 0) set += stemp[1];
+ if (stemp[2] >= 0) set += stemp[2];
+}
+
+void InterInstruction::ShrinkActiveTemporaries(FastNumberSet& set, GrowingTypeArray& temporaries)
+{
+ if (ttemp >= 0)
+ {
+ ttemp = set.Index(ttemp);
+ temporaries[ttemp] = ttype;
+ }
+ if (stemp[0] >= 0) stemp[0] = set.Index(stemp[0]);
+ if (stemp[1] >= 0) stemp[1] = set.Index(stemp[1]);
+ if (stemp[2] >= 0) stemp[2] = set.Index(stemp[2]);
+}
+
+void InterInstruction::CollectSimpleLocals(FastNumberSet& complexLocals, FastNumberSet& simpleLocals, GrowingTypeArray& localTypes)
+{
+ switch (code)
+ {
+ case IC_LOAD:
+ if (mem == IM_LOCAL && stemp[0] < 0)
+ {
+ localTypes[vindex] = ttype;
+ if (opsize == 2)
+ simpleLocals += vindex;
+ else
+ complexLocals += vindex;
+ }
+ break;
+ case IC_STORE:
+ if (mem == IM_LOCAL && stemp[1] < 0)
+ {
+ localTypes[vindex] = stype[0];
+ if (opsize == 2)
+ simpleLocals += vindex;
+ else
+ complexLocals += vindex;
+ }
+ break;
+ case IC_LEA:
+ if (mem == IM_LOCAL && stemp[1] < 0)
+ complexLocals += vindex;
+ break;
+ case IC_CONSTANT:
+ if (ttype == IT_POINTER && mem == IM_LOCAL)
+ complexLocals += vindex;
+ break;
+ }
+}
+
+void InterInstruction::SimpleLocalToTemp(int vindex, int temp)
+{
+ switch (code)
+ {
+ case IC_LOAD:
+ if (mem == IM_LOCAL && stemp[0] < 0 && vindex == this->vindex)
+ {
+ code = IC_LOAD_TEMPORARY;
+ stemp[0] = temp;
+ stype[0] = ttype;
+
+ assert(stemp[0] >= 0);
+
+ }
+ break;
+ case IC_STORE:
+ if (mem == IM_LOCAL && stemp[1] < 0 && vindex == this->vindex)
+ {
+ if (stemp[0] < 0)
+ {
+ code = IC_CONSTANT;
+ ivalue = siconst[0];
+ }
+ else
+ {
+ code = IC_LOAD_TEMPORARY;
+ assert(stemp[0] >= 0);
+ }
+
+ ttemp = temp;
+ ttype = stype[0];
+ }
+ break;
+ }
+}
+
+void InterInstruction::Disassemble(FILE* file)
+{
+ if (this->code != IC_NONE)
+ {
+ static char memchars[] = "NPLGFPITA";
+
+ fprintf(file, "\t");
+ switch (this->code)
+ {
+ case IC_LOAD_TEMPORARY:
+ case IC_STORE_TEMPORARY:
+ fprintf(file, "MOVE");
+ break;
+ case IC_BINARY_OPERATOR:
+ fprintf(file, "BINOP");
+ break;
+ case IC_UNARY_OPERATOR:
+ fprintf(file, "UNOP");
+ break;
+ case IC_RELATIONAL_OPERATOR:
+ fprintf(file, "RELOP");
+ break;
+ case IC_CONVERSION_OPERATOR:
+ fprintf(file, "CONV");
+ break;
+ case IC_STORE:
+ fprintf(file, "STORE%c%d", memchars[mem], opsize);
+ break;
+ case IC_LOAD:
+ fprintf(file, "LOAD%c%d", memchars[mem], opsize);
+ break;
+ case IC_COPY:
+ fprintf(file, "COPY%c", memchars[mem]);
+ break;
+ case IC_LEA:
+ fprintf(file, "LEA%c", memchars[mem]);
+ break;
+ case IC_TYPECAST:
+ fprintf(file, "CAST");
+ break;
+ case IC_CONSTANT:
+ fprintf(file, "CONST");
+ break;
+ case IC_BRANCH:
+ fprintf(file, "BRANCH");
+ break;
+ case IC_JUMP:
+ fprintf(file, "JUMP");
+ break;
+ case IC_PUSH_FRAME:
+ fprintf(file, "PUSHF\t%d", int(ivalue));
+ break;
+ case IC_POP_FRAME:
+ fprintf(file, "POPF\t%d", int(ivalue));
+ break;
+ case IC_CALL:
+ fprintf(file, "CALL");
+ break;
+ case IC_JSR:
+ fprintf(file, "JSR");
+ break;
+ case IC_RETURN_VALUE:
+ fprintf(file, "RETV");
+ break;
+ case IC_RETURN_STRUCT:
+ fprintf(file, "RETS");
+ break;
+ case IC_RETURN:
+ fprintf(file, "RET");
+ break;
+ }
+ static char typechars[] = "NUSFPB";
+
+ fprintf(file, "\t");
+ if (ttemp >= 0) fprintf(file, "R%d(%c)", ttemp, typechars[ttype]);
+ fprintf(file, "\t<-\t");
+ if (stemp[2] >= 0) fprintf(file, "R%d(%c%c), ", stemp[2], typechars[stype[2]], sfinal[2] ? 'F' : '-');
+ if (stemp[1] >= 0) fprintf(file, "R%d(%c%c), ", stemp[1], typechars[stype[1]], sfinal[1] ? 'F' : '-');
+ if (stemp[0] >= 0) fprintf(file, "R%d(%c%c)", stemp[0], typechars[stype[0]], sfinal[0] ? 'F' : '-');
+ if (this->code == IC_CONSTANT)
+ {
+ if (ttype == IT_POINTER)
+ fprintf(file, "C%d", opsize);
+ else if (ttype == IT_FLOAT)
+ fprintf(file, "C%f", fvalue);
+ else
+ fprintf(file, "C%I64d", ivalue);
+ }
+ if (this->exceptionJump)
+ {
+ fprintf(file, " EX: %d", this->exceptionJump->num);
+ }
+
+ fprintf(file, "\n");
+ }
+}
+
+InterCodeBasicBlock::InterCodeBasicBlock(void)
+ : code(InterInstruction()), entryRenameTable(-1), exitRenameTable(-1)
+{
+}
+
+InterCodeBasicBlock::~InterCodeBasicBlock(void)
+{
+}
+
+
+void InterCodeBasicBlock::Append(InterInstruction & code)
+{
+ this->code.Push(code);
+}
+
+void InterCodeBasicBlock::Close(InterCodeBasicBlock* trueJump, InterCodeBasicBlock* falseJump)
+{
+ this->trueJump = trueJump;
+ this->falseJump = falseJump;
+ this->numEntries = 0;
+}
+
+
+void InterCodeBasicBlock::CollectEntries(void)
+{
+ numEntries++;
+ if (!visited)
+ {
+ visited = true;
+
+ if (trueJump) trueJump->CollectEntries();
+ if (falseJump) falseJump->CollectEntries();
+ }
+}
+
+void InterCodeBasicBlock::GenerateTraces(void)
+{
+ int i;
+
+ if (!visited)
+ {
+ visited = true;
+
+ for (;;)
+ {
+ if (trueJump && trueJump->code.Size() == 1 && trueJump->code[0].code == IC_JUMP)
+ {
+ trueJump->numEntries--;
+ trueJump = trueJump->trueJump;
+ if (trueJump)
+ trueJump->numEntries++;
+ }
+ else if (falseJump && falseJump->code.Size() == 1 && falseJump->code[0].code == IC_JUMP)
+ {
+ falseJump->numEntries--;
+ falseJump = falseJump->trueJump;
+ if (falseJump)
+ falseJump->numEntries++;
+ }
+ else if (trueJump && !falseJump && ((trueJump->code.Size() < 10 && trueJump->code.Size() > 1) || trueJump->numEntries == 1))
+ {
+ trueJump->numEntries--;
+
+ code.Pop();
+ for (i = 0; i < trueJump->code.Size(); i++)
+ code.Push(trueJump->code[i]);
+
+ falseJump = trueJump->falseJump;
+ trueJump = trueJump->trueJump;
+
+ if (trueJump)
+ trueJump->numEntries++;
+ if (falseJump)
+ falseJump->numEntries++;
+ }
+ else
+ break;
+ }
+
+ if (trueJump) trueJump->GenerateTraces();
+ if (falseJump) falseJump->GenerateTraces();
+ }
+}
+
+static bool IsSimpleAddressMultiply(int val)
+{
+ switch (val)
+ {
+ case 1: // SHR 3
+ case 2: // SHR 2
+ case 4: // SHR 1
+ case 8:
+ case 16: // * 2
+ case 32: // * 4
+ case 64: // * 8
+ case 128: // LEA r * 2, * 8
+ case 192: // LEA r, r * 2, * 8
+ case 256: // LEA r * 4, * 8
+ case 512: // LEA r * 8, * 8
+ return true;
+ }
+
+ return false;
+}
+
+static void OptimizeAddress(InterInstruction& ins, const GrowingInstructionPtrArray& tvalue, int offset)
+{
+ ins.siconst[offset] = 0;
+
+ if (ins.stemp[offset] >= 0 && tvalue[ins.stemp[offset]])
+ {
+ if (tvalue[ins.stemp[offset]]->code == IC_CONSTANT)
+ {
+ ins.siconst[offset] = tvalue[ins.stemp[offset]]->ivalue;
+ ins.vindex = tvalue[ins.stemp[offset]]->vindex;
+ ins.mem = tvalue[ins.stemp[offset]]->mem;
+ ins.stemp[offset] = -1;
+ }
+ }
+}
+
+
+void InterCodeBasicBlock::CheckValueUsage(InterInstruction& ins, const GrowingInstructionPtrArray& tvalue)
+{
+ switch (ins.code)
+ {
+ case IC_CALL:
+ case IC_JSR:
+ if (ins.stemp[0] >= 0 && tvalue[ins.stemp[0]] && tvalue[ins.stemp[0]]->code == IC_CONSTANT)
+ {
+ ins.mem = tvalue[ins.stemp[0]]->mem;
+ ins.vindex = tvalue[ins.stemp[0]]->vindex;
+ ins.opsize = tvalue[ins.stemp[0]]->opsize;
+ ins.stemp[0] = -1;
+ }
+
+ break;
+ case IC_LOAD_TEMPORARY:
+ if (ins.stemp[0] >= 0 && tvalue[ins.stemp[0]] && tvalue[ins.stemp[0]]->code == IC_CONSTANT)
+ {
+ switch (ins.stype[0])
+ {
+ case IT_FLOAT:
+ ins.code = IC_CONSTANT;
+ ins.fvalue = tvalue[ins.stemp[0]]->fvalue;
+ ins.stemp[0] = -1;
+ break;
+ case IT_POINTER:
+ ins.code = IC_CONSTANT;
+ ins.mem = tvalue[ins.stemp[0]]->mem;
+ ins.vindex = tvalue[ins.stemp[0]]->vindex;
+ ins.ivalue = tvalue[ins.stemp[0]]->ivalue;
+ ins.opsize = tvalue[ins.stemp[0]]->opsize;
+ ins.stemp[0] = -1;
+ break;
+ default:
+ ins.code = IC_CONSTANT;
+ ins.ivalue = tvalue[ins.stemp[0]]->ivalue;
+ ins.stemp[0] = -1;
+ break;
+ }
+ }
+ break;
+
+ case IC_LOAD:
+ OptimizeAddress(ins, tvalue, 0);
+ break;
+ case IC_STORE:
+ if (ins.stemp[0] >= 0 && tvalue[ins.stemp[0]] && tvalue[ins.stemp[0]]->code == IC_CONSTANT)
+ {
+ switch (ins.stype[0])
+ {
+ case IT_FLOAT:
+ break;
+ case IT_POINTER:
+ break;
+ default:
+ if (ins.stype[0] == IT_UNSIGNED)
+ ins.siconst[0] = unsigned short (tvalue[ins.stemp[0]]->ivalue);
+ else
+ ins.siconst[0] = tvalue[ins.stemp[0]]->ivalue;
+ ins.stemp[0] = -1;
+ break;
+ }
+ }
+ OptimizeAddress(ins, tvalue, 1);
+ break;
+ case IC_LEA:
+ if (ins.stemp[0] >= 0 && tvalue[ins.stemp[0]] && tvalue[ins.stemp[0]]->code == IC_CONSTANT)
+ {
+ if (ins.stemp[1] >= 0 && tvalue[ins.stemp[1]] && tvalue[ins.stemp[1]]->code == IC_CONSTANT)
+ {
+ ins.code = IC_CONSTANT;
+ ins.ttype = IT_POINTER;
+ ins.mem = tvalue[ins.stemp[1]]->mem;
+ ins.vindex = tvalue[ins.stemp[1]]->vindex;
+ ins.ivalue = tvalue[ins.stemp[1]]->ivalue + tvalue[ins.stemp[0]]->ivalue;
+ ins.stemp[0] = -1;
+ ins.stemp[1] = -1;
+ }
+ else if (tvalue[ins.stemp[0]]->ivalue == 0)
+ {
+ ins.code = IC_LOAD_TEMPORARY;
+ ins.stype[0] = ins.stype[1];
+ ins.stemp[0] = ins.stemp[1];
+ ins.stemp[1] = -1;
+ assert(ins.stemp[0] >= 0);
+ }
+ }
+ break;
+ case IC_TYPECAST:
+ if (ins.stype[0] == ins.ttype)
+ {
+ ins.code = IC_LOAD_TEMPORARY;
+ assert(ins.stemp[0] >= 0);
+ }
+ else if ((ins.stype[0] == IT_SIGNED || ins.stype[0] == IT_UNSIGNED) && ins.ttype == IT_POINTER)
+ {
+ if (ins.stemp[0] >= 0 && tvalue[ins.stemp[0]] && tvalue[ins.stemp[0]]->code == IC_CONSTANT)
+ {
+ ins.code = IC_CONSTANT;
+ ins.ttype = IT_POINTER;
+ ins.mem = IM_ABSOLUTE;
+ ins.vindex = 0;
+ ins.ivalue = tvalue[ins.stemp[0]]->ivalue;
+ ins.stemp[0] = -1;
+ }
+ }
+ break;
+ case IC_RETURN_VALUE:
+ if (ins.stemp[0] >= 0 && tvalue[ins.stemp[0]] && tvalue[ins.stemp[0]]->code == IC_CONSTANT)
+ {
+ switch (ins.stype[0])
+ {
+ case IT_FLOAT:
+ break;
+ case IT_POINTER:
+ break;
+ default:
+ if (ins.stype[0] == IT_UNSIGNED)
+ ins.siconst[0] = unsigned short(tvalue[ins.stemp[0]]->ivalue);
+ else
+ ins.siconst[0] = tvalue[ins.stemp[0]]->ivalue;
+ ins.stemp[0] = -1;
+ break;
+ }
+ }
+ break;
+ case IC_BINARY_OPERATOR:
+ switch (ins.stype[0])
+ {
+ case IT_FLOAT:
+ if (ins.stemp[1] >= 0 && tvalue[ins.stemp[1]] && tvalue[ins.stemp[1]]->code == IC_CONSTANT)
+ {
+ if (ins.stemp[0] >= 0 && tvalue[ins.stemp[0]] && tvalue[ins.stemp[0]]->code == IC_CONSTANT)
+ {
+ ins.code = IC_CONSTANT;
+ ins.ivalue = ConstantFolding(ins.oper, tvalue[ins.stemp[1]]->fvalue, tvalue[ins.stemp[0]]->fvalue);
+ ins.stemp[0] = -1;
+ ins.stemp[1] = -1;
+ }
+ else
+ {
+ if (ins.oper == IA_ADD && tvalue[ins.stemp[1]]->fvalue == 0)
+ {
+ ins.code = IC_LOAD_TEMPORARY;
+ assert(ins.stemp[0] >= 0);
+ }
+ else if (ins.oper == IA_MUL)
+ {
+ if (tvalue[ins.stemp[1]]->fvalue == 1.0)
+ {
+ ins.code = IC_LOAD_TEMPORARY;
+ assert(ins.stemp[0] >= 0);
+ }
+ else if (tvalue[ins.stemp[1]]->fvalue == 0.0)
+ {
+ ins.code = IC_CONSTANT;
+ ins.fvalue = 0.0;
+ ins.stemp[0] = -1;
+ ins.stemp[1] = -1;
+ }
+ else if (tvalue[ins.stemp[1]]->fvalue == 2.0)
+ {
+ ins.oper = IA_ADD;
+ ins.stemp[1] = ins.stemp[0];
+ assert(ins.stemp[0] >= 0);
+ }
+ }
+ }
+ }
+ else if (ins.stemp[0] >= 0 && tvalue[ins.stemp[0]] && tvalue[ins.stemp[0]]->code == IC_CONSTANT)
+ {
+ if (ins.oper == IA_ADD && tvalue[ins.stemp[0]]->fvalue == 0)
+ {
+ ins.code = IC_LOAD_TEMPORARY;
+ ins.stemp[0] = ins.stemp[1];
+ ins.stemp[1] = -1;
+ assert(ins.stemp[0] >= 0);
+ }
+ else if (ins.oper == IA_MUL)
+ {
+ if (tvalue[ins.stemp[0]]->fvalue == 1.0)
+ {
+ ins.code = IC_LOAD_TEMPORARY;
+ ins.stemp[0] = ins.stemp[1];
+ ins.stemp[1] = -1;
+ assert(ins.stemp[0] >= 0);
+ }
+ else if (tvalue[ins.stemp[0]]->fvalue == 0.0)
+ {
+ ins.code = IC_CONSTANT;
+ ins.fvalue = 0.0;
+ ins.stemp[0] = -1;
+ ins.stemp[1] = -1;
+ }
+ else if (tvalue[ins.stemp[0]]->fvalue == 2.0)
+ {
+ ins.oper = IA_ADD;
+ ins.stemp[0] = ins.stemp[1];
+ assert(ins.stemp[0] >= 0);
+ }
+ }
+ }
+ break;
+ case IT_POINTER:
+ break;
+ default:
+ if (ins.stemp[1] >= 0 && tvalue[ins.stemp[1]] && tvalue[ins.stemp[1]]->code == IC_CONSTANT)
+ {
+ if (ins.stemp[0] >= 0 && tvalue[ins.stemp[0]] && tvalue[ins.stemp[0]]->code == IC_CONSTANT)
+ {
+ ins.code = IC_CONSTANT;
+ ins.ivalue = ConstantFolding(ins.oper, tvalue[ins.stemp[1]]->ivalue, tvalue[ins.stemp[0]]->ivalue);
+ ins.stemp[0] = -1;
+ ins.stemp[1] = -1;
+ }
+ else
+ {
+ ins.siconst[1] = tvalue[ins.stemp[1]]->ivalue;
+ ins.stemp[1] = -1;
+#if 1
+ if (ins.oper == IA_ADD && ins.siconst[1] == 0)
+ {
+ ins.code = IC_LOAD_TEMPORARY;
+ assert(ins.stemp[0] >= 0);
+ }
+ else if (ins.oper == IA_MUL)
+ {
+ if (ins.siconst[1] == 1)
+ {
+ ins.code = IC_LOAD_TEMPORARY;
+ assert(ins.stemp[0] >= 0);
+ }
+ else if (ins.siconst[1] == 2)
+ {
+ ins.oper = IA_SHL;
+ins.stemp[1] = ins.stemp[0];
+ins.stype[1] = ins.stype[0];
+ins.stemp[0] = -1;
+ins.siconst[0] = 1;
+ }
+ else if (ins.siconst[1] == 4)
+ {
+ ins.oper = IA_SHL;
+ ins.stemp[1] = ins.stemp[0];
+ ins.stype[1] = ins.stype[0];
+ ins.stemp[0] = -1;
+ ins.siconst[0] = 2;
+ }
+ else if (ins.siconst[1] == 8)
+ {
+ ins.oper = IA_SHL;
+ ins.stemp[1] = ins.stemp[0];
+ ins.stype[1] = ins.stype[0];
+ ins.stemp[0] = -1;
+ ins.siconst[0] = 3;
+ }
+
+ }
+#endif
+ }
+ }
+ else if (ins.stemp[0] >= 0 && tvalue[ins.stemp[0]] && tvalue[ins.stemp[0]]->code == IC_CONSTANT)
+ {
+ ins.siconst[0] = tvalue[ins.stemp[0]]->ivalue;
+ ins.stemp[0] = -1;
+#if 1
+ if (ins.oper == IA_ADD && ins.siconst[0] == 0)
+ {
+ ins.code = IC_LOAD_TEMPORARY;
+ ins.stemp[0] = ins.stemp[1];
+ ins.stemp[1] = -1;
+ assert(ins.stemp[0] >= 0);
+ }
+ else if (ins.oper == IA_MUL)
+ {
+ if (ins.siconst[0] == 1)
+ {
+ ins.code = IC_LOAD_TEMPORARY;
+ ins.stemp[0] = ins.stemp[1];
+ ins.stemp[1] = -1;
+ assert(ins.stemp[0] >= 0);
+ }
+ else if (ins.siconst[0] == 2)
+ {
+ ins.oper = IA_SHL;
+ ins.siconst[0] = 1;
+ }
+ else if (ins.siconst[0] == 4)
+ {
+ ins.oper = IA_SHL;
+ ins.siconst[0] = 2;
+ }
+ else if (ins.siconst[0] == 8)
+ {
+ ins.oper = IA_SHL;
+ ins.siconst[0] = 3;
+ }
+ }
+#endif
+ }
+
+ if (ins.stemp[1] < 0 && ins.stemp[0] >= 0 && tvalue[ins.stemp[0]] && tvalue[ins.stemp[0]]->code == IC_BINARY_OPERATOR)
+ {
+ InterInstruction* pins = tvalue[ins.stemp[0]];
+ if (ins.oper == pins->oper && (ins.oper == IA_ADD || ins.oper == IA_MUL || ins.oper == IA_AND || ins.oper == IA_OR))
+ {
+ if (pins->stemp[1] < 0)
+ {
+ ins.siconst[1] = ConstantFolding(ins.oper, ins.siconst[1], pins->siconst[1]);
+ ins.stemp[0] = pins->stemp[0];
+ }
+ else if (pins->stemp[0] < 0)
+ {
+ ins.siconst[1] = ConstantFolding(ins.oper, ins.siconst[1], pins->siconst[0]);
+ ins.stemp[0] = pins->stemp[1];
+ }
+ }
+ }
+ else if (ins.stemp[0] < 0 && ins.stemp[1] >= 0 && tvalue[ins.stemp[1]] && tvalue[ins.stemp[1]]->code == IC_BINARY_OPERATOR)
+ {
+ InterInstruction* pins = tvalue[ins.stemp[1]];
+ if (ins.oper == pins->oper && (ins.oper == IA_ADD || ins.oper == IA_MUL || ins.oper == IA_AND || ins.oper == IA_OR))
+ {
+ if (pins->stemp[1] < 0)
+ {
+ ins.siconst[0] = ConstantFolding(ins.oper, ins.siconst[0], pins->siconst[1]);
+ ins.stemp[1] = pins->stemp[0];
+ }
+ else if (pins->stemp[0] < 0)
+ {
+ ins.siconst[0] = ConstantFolding(ins.oper, ins.siconst[0], pins->siconst[0]);
+ ins.stemp[1] = pins->stemp[1];
+ }
+ }
+ else if (ins.oper == IA_SHL && (pins->oper == IA_SHR || pins->oper == IA_SAR) && pins->stemp[0] < 0 && ins.siconst[0] == pins->siconst[0])
+ {
+ ins.oper = IA_AND;
+ ins.siconst[0] = -1LL << ins.siconst[0];
+ ins.stemp[1] = pins->stemp[1];
+ }
+ }
+
+ break;
+ }
+ break;
+ case IC_UNARY_OPERATOR:
+ switch (ins.stype[0])
+ {
+ case IT_FLOAT:
+ if (ins.stemp[0] >= 0 && tvalue[ins.stemp[0]] && tvalue[ins.stemp[0]]->code == IC_CONSTANT)
+ {
+ ins.code = IC_CONSTANT;
+ ins.fvalue = ConstantFolding(ins.oper, tvalue[ins.stemp[0]]->fvalue);
+ ins.stemp[0] = -1;
+ }
+ break;
+ case IT_POINTER:
+ break;
+ default:
+ break;
+ }
+ break;
+ case IC_RELATIONAL_OPERATOR:
+ switch (ins.stype[1])
+ {
+ case IT_FLOAT:
+ break;
+ case IT_POINTER:
+ if (ins.oper == IA_CMPEQ || ins.oper == IA_CMPNE)
+ {
+ if (ins.stemp[0] >= 0 && tvalue[ins.stemp[0]] && tvalue[ins.stemp[0]]->code == IC_CONSTANT)
+ {
+ ins.opsize = tvalue[ins.stemp[0]]->opsize;
+ ins.stemp[0] = -1;
+ }
+ else if (ins.stemp[1] >= 0 && tvalue[ins.stemp[1]] && tvalue[ins.stemp[1]]->code == IC_CONSTANT)
+ {
+ ins.opsize = tvalue[ins.stemp[1]]->opsize;
+ ins.stemp[1] = -1;
+ }
+ }
+ break;
+ default:
+ if (ins.stemp[1] >= 0 && tvalue[ins.stemp[1]] && tvalue[ins.stemp[1]]->code == IC_CONSTANT &&
+ ins.stemp[0] >= 0 && tvalue[ins.stemp[0]] && tvalue[ins.stemp[0]]->code == IC_CONSTANT)
+ {
+ ins.code = IC_CONSTANT;
+ ins.ivalue = ConstantFolding(ins.oper, tvalue[ins.stemp[1]]->ivalue, tvalue[ins.stemp[0]]->ivalue);
+ ins.stemp[0] = -1;
+ ins.stemp[1] = -1;
+ }
+ else
+ {
+ if (ins.stemp[1] >= 0 && tvalue[ins.stemp[1]] && tvalue[ins.stemp[1]]->code == IC_CONSTANT)
+ {
+ ins.siconst[1] = tvalue[ins.stemp[1]]->ivalue;
+ ins.stemp[1] = -1;
+ }
+ else if (ins.stemp[0] >= 0 && tvalue[ins.stemp[0]] && tvalue[ins.stemp[0]]->code == IC_CONSTANT)
+ {
+ ins.siconst[0] = tvalue[ins.stemp[0]]->ivalue;
+ ins.stemp[0] = -1;
+ }
+ }
+ break;
+ }
+ break;
+ case IC_BRANCH:
+ if (ins.stemp[0] >= 0 && tvalue[ins.stemp[0]] && tvalue[ins.stemp[0]]->code == IC_CONSTANT)
+ {
+ ins.siconst[0] = tvalue[ins.stemp[0]]->ivalue;
+ ins.stemp[0] = -1;
+ }
+ break;
+ case IC_PUSH_FRAME:
+ if (ins.stemp[0] >= 0 && tvalue[ins.stemp[0]] && tvalue[ins.stemp[0]]->code == IC_CONSTANT)
+ {
+ ins.spconst[0] = tvalue[ins.stemp[0]]->opsize;
+ ins.stemp[0] = -1;
+ }
+ break;
+ }
+}
+
+
+void InterCodeBasicBlock::CollectLocalAddressTemps(GrowingIntArray& localTable)
+{
+ int i;
+
+ if (!visited)
+ {
+ visited = true;
+
+ for (i = 0; i < code.Size(); i++)
+ code[i].CollectLocalAddressTemps(localTable);
+
+ if (trueJump) trueJump->CollectLocalAddressTemps(localTable);
+ if (falseJump) falseJump->CollectLocalAddressTemps(localTable);
+ }
+}
+
+void InterCodeBasicBlock::MarkAliasedLocalTemps(const GrowingIntArray& localTable, NumberSet& aliasedLocals)
+{
+ int i;
+
+ if (!visited)
+ {
+ visited = true;
+
+ for (i = 0; i < code.Size(); i++)
+ code[i].MarkAliasedLocalTemps(localTable, aliasedLocals);
+
+ if (trueJump) trueJump->MarkAliasedLocalTemps(localTable, aliasedLocals);
+ if (falseJump) falseJump->MarkAliasedLocalTemps(localTable, aliasedLocals);
+ }
+}
+
+void InterCodeBasicBlock::BuildLocalTempSets(int num, int numFixed)
+{
+ int i;
+
+ if (!visited)
+ {
+ visited = true;
+
+ localRequiredTemps = NumberSet(num);
+ localProvidedTemps = NumberSet(num);
+
+ entryRequiredTemps = NumberSet(num);
+ entryProvidedTemps = NumberSet(num);
+ exitRequiredTemps = NumberSet(num);
+ exitProvidedTemps = NumberSet(num);
+
+ for (i = 0; i < code.Size(); i++)
+ {
+ code[i].FilterTempUsage(localRequiredTemps, localProvidedTemps);
+ }
+
+ entryRequiredTemps = localRequiredTemps;
+ exitProvidedTemps = localProvidedTemps;
+
+ for (i = 0; i < numFixed; i++)
+ {
+ entryRequiredTemps += i;
+ exitProvidedTemps += i;
+ }
+
+ if (trueJump) trueJump->BuildLocalTempSets(num, numFixed);
+ if (falseJump) falseJump->BuildLocalTempSets(num, numFixed);
+ }
+}
+
+void InterCodeBasicBlock::BuildGlobalProvidedTempSet(NumberSet fromProvidedTemps)
+{
+ if (!visited || !(fromProvidedTemps <= entryProvidedTemps))
+ {
+ entryProvidedTemps |= fromProvidedTemps;
+ fromProvidedTemps |= exitProvidedTemps;
+
+ visited = true;
+
+ if (trueJump) trueJump->BuildGlobalProvidedTempSet(fromProvidedTemps);
+ if (falseJump) falseJump->BuildGlobalProvidedTempSet(fromProvidedTemps);
+ }
+}
+
+void InterCodeBasicBlock::PerformTempForwarding(TempForwardingTable& forwardingTable)
+{
+ int i;
+
+ if (!visited)
+ {
+ visited = true;
+
+ TempForwardingTable localForwardingTable(forwardingTable);
+
+ if (numEntries > 1)
+ localForwardingTable.Reset();
+
+ for (i = 0; i < code.Size(); i++)
+ {
+ code[i].PerformTempForwarding(localForwardingTable);
+ }
+
+ if (trueJump) trueJump->PerformTempForwarding(localForwardingTable);
+ if (falseJump) falseJump->PerformTempForwarding(localForwardingTable);
+ }
+}
+
+bool InterCodeBasicBlock::BuildGlobalRequiredTempSet(NumberSet& fromRequiredTemps)
+{
+ bool revisit = false;
+ int i;
+
+ if (!visited)
+ {
+ visited = true;
+
+ NumberSet newRequiredTemps(exitRequiredTemps);
+
+ if (trueJump && trueJump->BuildGlobalRequiredTempSet(newRequiredTemps)) revisit = true;
+ if (falseJump && falseJump->BuildGlobalRequiredTempSet(newRequiredTemps)) revisit = true;
+
+ if (!(newRequiredTemps <= exitRequiredTemps))
+ {
+ revisit = true;
+
+ exitRequiredTemps = newRequiredTemps;
+ newRequiredTemps -= localProvidedTemps;
+ entryRequiredTemps |= newRequiredTemps;
+ }
+
+ }
+
+ fromRequiredTemps |= entryRequiredTemps;
+
+ return revisit;
+}
+
+bool InterCodeBasicBlock::RemoveUnusedResultInstructions(int numStaticTemps)
+{
+ bool changed = false;
+
+ if (!visited)
+ {
+ visited = true;
+
+ NumberSet requiredTemps(exitRequiredTemps);
+ int i;
+
+ for (i = 0; i < numStaticTemps; i++)
+ requiredTemps += i;
+
+ for (i = code.Size() - 1; i > 0; i--)
+ {
+ if (code[i].RemoveUnusedResultInstructions(&(code[i - 1]), requiredTemps, numStaticTemps))
+ changed = true;
+ }
+ if (code[0].RemoveUnusedResultInstructions(NULL, requiredTemps, numStaticTemps))
+ changed = true;
+
+ if (trueJump)
+ {
+ if (trueJump->RemoveUnusedResultInstructions(numStaticTemps))
+ changed = true;
+ }
+ if (falseJump)
+ {
+ if (falseJump->RemoveUnusedResultInstructions(numStaticTemps))
+ changed = true;
+ }
+ }
+
+ return changed;
+}
+
+
+void InterCodeBasicBlock::BuildLocalVariableSets(const GrowingVariableArray& localVars)
+{
+ int i;
+
+ if (!visited)
+ {
+ visited = true;
+
+ mLocalRequiredVars = NumberSet(localVars.Size());
+ mLocalProvidedVars = NumberSet(localVars.Size());
+
+ mEntryRequiredVars = NumberSet(localVars.Size());
+ mEntryProvidedVars = NumberSet(localVars.Size());
+ mExitRequiredVars = NumberSet(localVars.Size());
+ mExitProvidedVars = NumberSet(localVars.Size());
+
+ for (i = 0; i < code.Size(); i++)
+ {
+ code[i].FilterVarsUsage(localVars, mLocalRequiredVars, mLocalProvidedVars);
+ }
+
+ mEntryRequiredVars = mLocalRequiredVars;
+ mExitProvidedVars = mLocalProvidedVars;
+
+ if (trueJump) trueJump->BuildLocalVariableSets(localVars);
+ if (falseJump) falseJump->BuildLocalVariableSets(localVars);
+ }
+}
+
+void InterCodeBasicBlock::BuildGlobalProvidedVariableSet(const GrowingVariableArray& localVars, NumberSet fromProvidedVars)
+{
+ if (!visited || !(fromProvidedVars <= mEntryProvidedVars))
+ {
+ mEntryProvidedVars |= fromProvidedVars;
+ fromProvidedVars |= mExitProvidedVars;
+
+ visited = true;
+
+ if (trueJump) trueJump->BuildGlobalProvidedVariableSet(localVars, fromProvidedVars);
+ if (falseJump) falseJump->BuildGlobalProvidedVariableSet(localVars, fromProvidedVars);
+ }
+}
+
+bool InterCodeBasicBlock::BuildGlobalRequiredVariableSet(const GrowingVariableArray& localVars, NumberSet& fromRequiredVars)
+{
+ bool revisit = false;
+ int i;
+
+ if (!visited)
+ {
+ visited = true;
+
+ NumberSet newRequiredVars(mExitRequiredVars);
+
+ if (trueJump && trueJump->BuildGlobalRequiredVariableSet(localVars, newRequiredVars)) revisit = true;
+ if (falseJump && falseJump->BuildGlobalRequiredVariableSet(localVars, newRequiredVars)) revisit = true;
+
+ if (!(newRequiredVars <= mExitRequiredVars))
+ {
+ revisit = true;
+
+ mExitRequiredVars = newRequiredVars;
+ newRequiredVars -= mLocalProvidedVars;
+ mEntryRequiredVars |= newRequiredVars;
+ }
+
+ }
+
+ fromRequiredVars |= mEntryRequiredVars;
+
+ return revisit;
+}
+
+bool InterCodeBasicBlock::RemoveUnusedStoreInstructions(const GrowingVariableArray& localVars)
+{
+ bool changed = false;
+
+ if (!visited)
+ {
+ visited = true;
+
+ NumberSet requiredVars(mExitRequiredVars);
+ int i;
+
+ for (i = code.Size() - 1; i > 0; i--)
+ {
+ if (code[i].RemoveUnusedStoreInstructions(localVars, &(code[i - 1]), requiredVars))
+ changed = true;
+ }
+ if (code[0].RemoveUnusedStoreInstructions(localVars, nullptr, requiredVars))
+ changed = true;
+
+ if (trueJump)
+ {
+ if (trueJump->RemoveUnusedStoreInstructions(localVars))
+ changed = true;
+ }
+ if (falseJump)
+ {
+ if (falseJump->RemoveUnusedStoreInstructions(localVars))
+ changed = true;
+ }
+ }
+
+ return changed;
+
+}
+
+void InterCodeBasicBlock::PerformValueForwarding(const GrowingInstructionPtrArray& tvalue, const ValueSet& values, FastNumberSet& tvalid, const NumberSet& aliasedLocals)
+{
+ int i;
+
+ if (!visited)
+ {
+ GrowingInstructionPtrArray ltvalue(tvalue);
+ ValueSet lvalues(values);
+
+ visited = true;
+
+ tvalid.Clear();
+
+ if (numEntries != 1)
+ {
+ lvalues.FlushAll();
+ ltvalue.Clear();
+ }
+ else
+ {
+ for (i = 0; i < ltvalue.Size(); i++)
+ {
+ if (ltvalue[i])
+ tvalid += i;
+ }
+ }
+
+ for (i = 0; i < code.Size(); i++)
+ {
+ lvalues.UpdateValue(code[i], ltvalue, aliasedLocals);
+ code[i].PerformValueForwarding(ltvalue, tvalid);
+ }
+
+ if (trueJump) trueJump->PerformValueForwarding(ltvalue, lvalues, tvalid, aliasedLocals);
+ if (falseJump) falseJump->PerformValueForwarding(ltvalue, lvalues, tvalid, aliasedLocals);
+ }
+}
+
+void InterCodeBasicBlock::PerformMachineSpecificValueUsageCheck(const GrowingInstructionPtrArray& tvalue, FastNumberSet& tvalid)
+{
+ int i;
+
+ if (!visited)
+ {
+ visited = true;
+
+ GrowingInstructionPtrArray ltvalue(tvalue);
+
+ tvalid.Clear();
+
+ if (numEntries != 1)
+ ltvalue.Clear();
+ else
+ {
+ for (i = 0; i < tvalue.Size(); i++)
+ {
+ if (ltvalue[i])
+ tvalid += i;
+ }
+ }
+
+ for (i = 0; i < code.Size(); i++)
+ {
+ CheckValueUsage(code[i], ltvalue);
+ code[i].PerformValueForwarding(ltvalue, tvalid);
+ }
+
+ if (trueJump) trueJump->PerformMachineSpecificValueUsageCheck(ltvalue, tvalid);
+ if (falseJump) falseJump->PerformMachineSpecificValueUsageCheck(ltvalue, tvalid);
+ }
+}
+
+static void Union(GrowingIntArray& table, int i, int j)
+{
+ int k, l;
+
+ k = table[j];
+ while (j != k)
+ {
+ l = table[k];
+ table[j] = l;
+ j = k; k = l;
+ }
+
+ table[j] = table[i];
+}
+
+static int Find(GrowingIntArray& table, int i)
+{
+ int j, k, l;
+
+ j = i;
+ k = table[j];
+ while (j != k)
+ {
+ l = table[k];
+ table[j] = l;
+ j = k; k = l;
+ }
+
+ return j;
+}
+
+
+void InterCodeBasicBlock::LocalRenameRegister(const GrowingIntArray& renameTable, int& num, int fixed)
+{
+ int i;
+
+ if (!visited)
+ {
+ visited = true;
+
+ entryRenameTable.SetSize(renameTable.Size());
+ exitRenameTable.SetSize(renameTable.Size());
+
+ for (i = 0; i < renameTable.Size(); i++)
+ {
+ if (i < fixed)
+ {
+ entryRenameTable[i] = i;
+ exitRenameTable[i] = i;
+ }
+ else if (entryRequiredTemps[i])
+ {
+ entryRenameTable[i] = renameTable[i];
+ exitRenameTable[i] = renameTable[i];
+ }
+ else
+ {
+ entryRenameTable[i] = -1;
+ exitRenameTable[i] = -1;
+ }
+ }
+
+ for (i = 0; i < code.Size(); i++)
+ {
+ code[i].LocalRenameRegister(exitRenameTable, num, fixed);
+ }
+
+ if (trueJump) trueJump->LocalRenameRegister(exitRenameTable, num, fixed);
+ if (falseJump) falseJump->LocalRenameRegister(exitRenameTable, num, fixed);
+ }
+}
+
+void InterCodeBasicBlock::BuildGlobalRenameRegisterTable(const GrowingIntArray& renameTable, GrowingIntArray& globalRenameTable)
+{
+ int i;
+
+ for (i = 0; i < renameTable.Size(); i++)
+ {
+ if (renameTable[i] >= 0 && entryRenameTable[i] >= 0 && renameTable[i] != entryRenameTable[i])
+ {
+ Union(globalRenameTable, renameTable[i], entryRenameTable[i]);
+ }
+ }
+
+ if (!visited)
+ {
+ visited = true;
+
+ if (trueJump) trueJump->BuildGlobalRenameRegisterTable(exitRenameTable, globalRenameTable);
+ if (falseJump) falseJump->BuildGlobalRenameRegisterTable(exitRenameTable, globalRenameTable);
+ }
+}
+
+void InterCodeBasicBlock::GlobalRenameRegister(const GrowingIntArray& renameTable, GrowingTypeArray& temporaries)
+{
+ int i;
+
+ if (!visited)
+ {
+ visited = true;
+
+ for (i = 0; i < code.Size(); i++)
+ {
+ code[i].GlobalRenameRegister(renameTable, temporaries);
+ }
+
+ if (trueJump) trueJump->GlobalRenameRegister(renameTable, temporaries);
+ if (falseJump) falseJump->GlobalRenameRegister(renameTable, temporaries);
+ }
+}
+
+void InterCodeBasicBlock::BuildCollisionTable(NumberSet* collisionSets)
+{
+ if (!visited)
+ {
+ visited = true;
+
+ NumberSet requiredTemps(exitRequiredTemps);
+ int i, j;
+
+ for (i = 0; i < exitRequiredTemps.Size(); i++)
+ {
+ if (exitRequiredTemps[i])
+ {
+ for (j = 0; j < exitRequiredTemps.Size(); j++)
+ {
+ if (exitRequiredTemps[j])
+ {
+ collisionSets[i] += j;
+ }
+ }
+ }
+ }
+
+ for (i = code.Size() - 1; i >= 0; i--)
+ {
+ code[i].BuildCollisionTable(requiredTemps, collisionSets);
+ }
+
+ if (trueJump) trueJump->BuildCollisionTable(collisionSets);
+ if (falseJump) falseJump->BuildCollisionTable(collisionSets);
+ }
+}
+
+void InterCodeBasicBlock::ReduceTemporaries(const GrowingIntArray& renameTable, GrowingTypeArray& temporaries)
+{
+ int i;
+
+ if (!visited)
+ {
+ visited = true;
+
+ for (i = 0; i < code.Size(); i++)
+ {
+ code[i].ReduceTemporaries(renameTable, temporaries);
+ }
+
+ if (trueJump) trueJump->ReduceTemporaries(renameTable, temporaries);
+ if (falseJump) falseJump->ReduceTemporaries(renameTable, temporaries);
+ }
+}
+
+static void UseGlobal(GrowingVariableArray& globalVars, int index)
+{
+ if (!globalVars[index].mUsed)
+ {
+ globalVars[index].mUsed = true;
+ for (int i = 0; i < globalVars[index].mNumReferences; i++)
+ {
+ if (!globalVars[index].mReferences[i].mFunction)
+ UseGlobal(globalVars, globalVars[index].mReferences[i].mIndex);
+ }
+ }
+}
+
+void InterCodeModule::UseGlobal(int index)
+{
+ if (!mGlobalVars[index].mUsed)
+ {
+ mGlobalVars[index].mUsed = true;
+ for (int i = 0; i < mGlobalVars[index].mNumReferences; i++)
+ {
+ if (!mGlobalVars[index].mReferences[i].mFunction)
+ UseGlobal( mGlobalVars[index].mReferences[i].mIndex);
+ }
+ }
+}
+
+void InterCodeBasicBlock::MapVariables(GrowingVariableArray& globalVars, GrowingVariableArray& localVars)
+{
+ int i;
+
+ if (!visited)
+ {
+ visited = true;
+
+ for (i = 0; i < code.Size(); i++)
+ {
+ bool found = false;
+
+ switch (code[i].code)
+ {
+ case IC_STORE:
+ case IC_LOAD:
+ case IC_CONSTANT:
+ case IC_JSR:
+ if (code[i].mem == IM_GLOBAL)
+ {
+ UseGlobal(globalVars, code[i].vindex);
+ }
+ else if (code[i].mem == IM_LOCAL)
+ {
+ localVars[code[i].vindex].mUsed = true;
+ }
+ break;
+ }
+ }
+
+ if (trueJump) trueJump->MapVariables(globalVars, localVars);
+ if (falseJump) falseJump->MapVariables(globalVars, localVars);
+ }
+}
+
+void InterCodeBasicBlock::CollectOuterFrame(int level, int& size)
+{
+ int i;
+
+ if (!visited)
+ {
+ visited = true;
+
+ for (i = 0; i < code.Size(); i++)
+ {
+ if (code[i].code == IC_PUSH_FRAME)
+ {
+ level++;
+ if (level == 1)
+ {
+ if (code[i].ivalue > size)
+ size = code[i].ivalue;
+ code[i].code = IC_NONE;
+ }
+ }
+ else if (code[i].code == IC_POP_FRAME)
+ {
+ if (level == 1)
+ {
+ code[i].code = IC_NONE;
+ }
+ level--;
+ }
+ }
+
+ if (trueJump) trueJump->CollectOuterFrame(level, size);
+ if (falseJump) falseJump->CollectOuterFrame(level, size);
+ }
+}
+
+bool InterCodeBasicBlock::IsLeafProcedure(void)
+{
+ int i;
+
+ if (!visited)
+ {
+ visited = true;
+
+ for (i = 0; i < code.Size(); i++)
+ if (code[i].code == IC_CALL)
+ return false;
+
+ if (trueJump && !trueJump->IsLeafProcedure())
+ return false;
+ if (falseJump && !falseJump->IsLeafProcedure())
+ return false;
+ }
+
+ return true;
+}
+
+void InterCodeBasicBlock::CollectVariables(GrowingVariableArray& globalVars, GrowingVariableArray& localVars)
+{
+ int i;
+
+ if (!visited)
+ {
+ visited = true;
+
+ for (i = 0; i < code.Size(); i++)
+ {
+ bool found = false;
+
+ switch (code[i].code)
+ {
+ case IC_STORE:
+ case IC_LOAD:
+ case IC_CONSTANT:
+ case IC_JSR:
+ if (code[i].mem == IM_LOCAL)
+ {
+ int size = code[i].opsize + code[i].ivalue;
+ if (size > localVars[code[i].vindex].mSize)
+ localVars[code[i].vindex].mSize = size;
+ if (code[i].code == IC_CONSTANT)
+ localVars[code[i].vindex].mAliased = true;
+ }
+ break;
+ }
+ }
+
+ if (trueJump) trueJump->CollectVariables(globalVars, localVars);
+ if (falseJump) falseJump->CollectVariables(globalVars, localVars);
+ }
+}
+
+void InterCodeBasicBlock::CollectSimpleLocals(FastNumberSet& complexLocals, FastNumberSet& simpleLocals, GrowingTypeArray& localTypes)
+{
+ int i;
+
+ if (!visited)
+ {
+ visited = true;
+
+ for (i = 0; i < code.Size(); i++)
+ {
+ code[i].CollectSimpleLocals(complexLocals, simpleLocals, localTypes);
+ }
+
+ if (trueJump) trueJump->CollectSimpleLocals(complexLocals, simpleLocals, localTypes);
+ if (falseJump) falseJump->CollectSimpleLocals(complexLocals, simpleLocals, localTypes);
+ }
+}
+
+void InterCodeBasicBlock::SimpleLocalToTemp(int vindex, int temp)
+{
+ int i;
+
+ if (!visited)
+ {
+ visited = true;
+
+ for (i = 0; i < code.Size(); i++)
+ {
+ code[i].SimpleLocalToTemp(vindex, temp);
+ }
+
+ if (trueJump) trueJump->SimpleLocalToTemp(vindex, temp);
+ if (falseJump) falseJump->SimpleLocalToTemp(vindex, temp);
+ }
+
+}
+
+void InterCodeBasicBlock::CollectActiveTemporaries(FastNumberSet& set)
+{
+ int i;
+
+ if (!visited)
+ {
+ visited = true;
+
+ for (i = 0; i < code.Size(); i++)
+ {
+ code[i].CollectActiveTemporaries(set);
+ }
+
+ if (trueJump) trueJump->CollectActiveTemporaries(set);
+ if (falseJump) falseJump->CollectActiveTemporaries(set);
+ }
+}
+
+void InterCodeBasicBlock::ShrinkActiveTemporaries(FastNumberSet& set, GrowingTypeArray& temporaries)
+{
+ int i;
+
+ if (!visited)
+ {
+ visited = true;
+
+ for (i = 0; i < code.Size(); i++)
+ {
+ code[i].ShrinkActiveTemporaries(set, temporaries);
+ }
+
+ if (trueJump) trueJump->ShrinkActiveTemporaries(set, temporaries);
+ if (falseJump) falseJump->ShrinkActiveTemporaries(set, temporaries);
+ }
+}
+
+void InterCodeBasicBlock::Disassemble(FILE* file, bool dumpSets)
+{
+ int i;
+
+ if (!visited)
+ {
+ visited = true;
+
+ fprintf(file, "L%d: (%d)\n", num, numEntries);
+
+ if (dumpSets)
+ {
+ fprintf(file, "Entry required temps : ");
+ for (i = 0; i < entryRequiredTemps.Size(); i++)
+ {
+ if (entryRequiredTemps[i])
+ fprintf(file, "#");
+ else
+ fprintf(file, "-");
+ }
+ fprintf(file, "\n\n");
+ }
+
+ for (i = 0; i < code.Size(); i++)
+ {
+ if (code[i].code != IT_NONE)
+ {
+ fprintf(file, "%04x\t", i);
+ code[i].Disassemble(file);
+ }
+ }
+
+ if (trueJump) fprintf(file, "\t\t==> %d\n", trueJump->num);
+ if (falseJump) fprintf(file, "\t\t==> %d\n", falseJump->num);
+
+ if (trueJump) trueJump->Disassemble(file, dumpSets);
+ if (falseJump) falseJump->Disassemble(file, dumpSets);
+ }
+}
+
+InterCodeProcedure::InterCodeProcedure(InterCodeModule * mod, const Location & location, const Ident* ident)
+ : temporaries(IT_NONE), blocks(nullptr), mLocation(location), mTempOffset(-1),
+ renameTable(-1), renameUnionTable(-1), globalRenameTable(-1),
+ valueForwardingTable(NULL), mLocalVars(InterVariable()), mModule(mod),
+ mIdent(ident)
+{
+ mID = mModule->mProcedures.Size();
+ mModule->mProcedures.Push(this);
+}
+
+InterCodeProcedure::~InterCodeProcedure(void)
+{
+}
+
+void InterCodeProcedure::ResetVisited(void)
+{
+ int i;
+
+ for (i = 0; i < blocks.Size(); i++)
+ blocks[i]->visited = false;
+}
+
+void InterCodeProcedure::Append(InterCodeBasicBlock* block)
+{
+ block->num = blocks.Size();
+ blocks.Push(block);
+}
+
+int InterCodeProcedure::AddTemporary(InterType type)
+{
+ int temp = temporaries.Size();
+ temporaries.Push(type);
+ return temp;
+}
+
+void InterCodeProcedure::DisassembleDebug(const char* name)
+{
+ Disassemble(name);
+}
+
+void InterCodeProcedure::BuildTraces(void)
+{
+ // Count number of entries
+//
+ ResetVisited();
+ for (int i = 0; i < blocks.Size(); i++)
+ blocks[i]->numEntries = 0;
+ blocks[0]->CollectEntries();
+
+ //
+ // Build traces
+ //
+ ResetVisited();
+ blocks[0]->GenerateTraces();
+
+ ResetVisited();
+ for (int i = 0; i < blocks.Size(); i++)
+ blocks[i]->numEntries = 0;
+ blocks[0]->CollectEntries();
+
+ DisassembleDebug("BuildTraces");
+}
+
+void InterCodeProcedure::BuildDataFlowSets(void)
+{
+ int numTemps = temporaries.Size();
+
+ //
+ // Build set with local provided/required temporaries
+ //
+ ResetVisited();
+ blocks[0]->BuildLocalTempSets(numTemps, numFixedTemporaries);
+
+ //
+ // Build set of globaly provided temporaries
+ //
+ ResetVisited();
+ blocks[0]->BuildGlobalProvidedTempSet(NumberSet(numTemps));
+
+ //
+ // Build set of globaly required temporaries, might need
+ // multiple iterations until it stabilizes
+ //
+ NumberSet totalRequired(numTemps);
+
+ do {
+ ResetVisited();
+ } while (blocks[0]->BuildGlobalRequiredTempSet(totalRequired));
+}
+
+void InterCodeProcedure::RenameTemporaries(void)
+{
+ int numTemps = temporaries.Size();
+
+ //
+ // Now we can rename temporaries to remove false dependencies
+ //
+ renameTable.SetSize(numTemps, true);
+
+ int i, j, numRename;
+
+ numRename = numFixedTemporaries;
+ for (i = 0; i < numRename; i++)
+ renameTable[i] = i;
+
+ //
+ // First localy rename all temporaries
+ //
+ ResetVisited();
+ blocks[0]->LocalRenameRegister(renameTable, numRename, numFixedTemporaries);
+
+ DisassembleDebug("local renamed temps");
+
+ //
+ // Build a union find data structure for rename merging, this
+ // merges renames temporaries back, that have been renamed differently
+ // on separate paths.
+ //
+ renameUnionTable.SetSize(numRename);
+ for (i = 0; i < numRename; i++)
+ renameUnionTable[i] = i;
+
+ //
+ // Build global rename table using a union/find algorithm
+ //
+ renameTable.SetSize(numTemps, true);
+
+ ResetVisited();
+ blocks[0]->BuildGlobalRenameRegisterTable(renameTable, renameUnionTable);
+
+ //
+ // Now calculate the global temporary IDs for all local ids
+ //
+ int numRenamedTemps;
+
+ globalRenameTable.SetSize(numRename, true);
+
+ for (i = 0; i < numFixedTemporaries; i++)
+ globalRenameTable[i] = i;
+
+ numRenamedTemps = numFixedTemporaries;
+
+ for (i = numFixedTemporaries; i < numRename; i++)
+ {
+ j = Find(renameUnionTable, i);
+
+ if (globalRenameTable[j] < 0)
+ globalRenameTable[j] = numRenamedTemps++;
+
+ globalRenameTable[i] = globalRenameTable[j];
+ }
+
+ temporaries.SetSize(numRenamedTemps);
+
+ //
+ // Set global temporary IDs
+ //
+ ResetVisited();
+ blocks[0]->GlobalRenameRegister(globalRenameTable, temporaries);
+
+ numTemps = numRenamedTemps;
+
+ DisassembleDebug("global renamed temps");
+}
+
+void InterCodeProcedure::TempForwarding(void)
+{
+ int numTemps = temporaries.Size();
+
+ ValueSet valueSet;
+ FastNumberSet tvalidSet(numTemps);
+
+ //
+ // Now remove needless temporary moves, that apear due to
+ // stack evaluation
+ //
+ tempForwardingTable.SetSize(numTemps);
+
+ tempForwardingTable.Reset();
+ ResetVisited();
+ blocks[0]->PerformTempForwarding(tempForwardingTable);
+
+ DisassembleDebug("temp forwarding");
+}
+
+void InterCodeProcedure::Close(void)
+{
+ int i, j, k, start;
+ GrowingTypeArray tstack(IT_NONE);
+
+ _CrtCheckMemory();
+
+ numFixedTemporaries = 0;
+
+ DisassembleDebug("start");
+
+ BuildTraces();
+
+ ResetVisited();
+ mLeafProcedure = blocks[0]->IsLeafProcedure();
+
+ if (!mLeafProcedure)
+ {
+ int size = 0;
+
+ ResetVisited();
+ blocks[0]->CollectOuterFrame(0, size);
+ mCommonFrameSize = size;
+ }
+ else
+ mCommonFrameSize = 0;
+
+ BuildDataFlowSets();
+
+ RenameTemporaries();
+
+ TempForwarding();
+
+ int numTemps = temporaries.Size();
+
+ //
+ // Find all local variables that are never aliased
+ //
+ GrowingIntArray localTable(-1);
+ ResetVisited();
+ blocks[0]->CollectLocalAddressTemps(localTable);
+
+ int nlocals = 0;
+ for (int i = 0; i < localTable.Size(); i++)
+ if (localTable[i] + 1 > nlocals)
+ nlocals = localTable[i] + 1;
+
+ localAliasedSet.Reset(nlocals);
+ ResetVisited();
+ blocks[0]->MarkAliasedLocalTemps(localTable, localAliasedSet);
+
+ //
+ // Now forward constant values
+ //
+ ValueSet valueSet;
+ FastNumberSet tvalidSet(numTemps);
+
+ valueForwardingTable.SetSize(numTemps, true);
+
+ ResetVisited();
+ blocks[0]->PerformValueForwarding(valueForwardingTable, valueSet, tvalidSet, localAliasedSet);
+
+ DisassembleDebug("value forwarding");
+
+ valueForwardingTable.Clear();
+
+ ResetVisited();
+ blocks[0]->PerformMachineSpecificValueUsageCheck(valueForwardingTable, tvalidSet);
+
+ DisassembleDebug("machine value forwarding");
+
+ //
+ // Now remove needless temporary moves, that apear due to
+ // stack evaluation
+ //
+ tempForwardingTable.Reset();
+ tempForwardingTable.SetSize(numTemps);
+
+ ResetVisited();
+ blocks[0]->PerformTempForwarding(tempForwardingTable);
+
+ DisassembleDebug("temp forwarding 2");
+
+
+ //
+ // Now remove unused instructions
+ //
+
+ do {
+ ResetVisited();
+ blocks[0]->BuildLocalTempSets(numTemps, numFixedTemporaries);
+
+ ResetVisited();
+ blocks[0]->BuildGlobalProvidedTempSet(NumberSet(numTemps));
+
+ NumberSet totalRequired2(numTemps);
+
+ do {
+ ResetVisited();
+ } while (blocks[0]->BuildGlobalRequiredTempSet(totalRequired2));
+
+ ResetVisited();
+ } while (blocks[0]->RemoveUnusedResultInstructions(numFixedTemporaries));
+
+ DisassembleDebug("removed unused instructions");
+
+ ResetVisited();
+ blocks[0]->CollectVariables(mModule->mGlobalVars, mLocalVars);
+
+
+ if (mLocalVars.Size() > 0)
+ {
+ for (int i = 0; i < mLocalVars.Size(); i++)
+ {
+ if (localAliasedSet[i])
+ mLocalVars[i].mAliased = true;
+ }
+
+ //
+ // Now remove unused stores
+ //
+
+ do {
+ ResetVisited();
+ blocks[0]->BuildLocalVariableSets(mLocalVars);
+
+ ResetVisited();
+ blocks[0]->BuildGlobalProvidedVariableSet(mLocalVars, NumberSet(mLocalVars.Size()));
+
+ NumberSet totalRequired2(mLocalVars.Size());
+
+ do {
+ ResetVisited();
+ } while (blocks[0]->BuildGlobalRequiredVariableSet(mLocalVars, totalRequired2));
+
+ ResetVisited();
+ } while (blocks[0]->RemoveUnusedStoreInstructions(mLocalVars));
+
+ DisassembleDebug("removed unused local stores");
+ }
+
+ //
+ // Promote local variables to temporaries
+ //
+
+ FastNumberSet simpleLocals(nlocals), complexLocals(nlocals);
+ GrowingTypeArray localTypes(IT_NONE);
+
+ ResetVisited();
+ blocks[0]->CollectSimpleLocals(complexLocals, simpleLocals, localTypes);
+
+ for (int i = 0; i < simpleLocals.Num(); i++)
+ {
+ int vi = simpleLocals.Element(i);
+ if (!complexLocals[vi])
+ {
+ ResetVisited();
+ blocks[0]->SimpleLocalToTemp(vi, AddTemporary(localTypes[vi]));
+ }
+ }
+
+ DisassembleDebug("local variables to temps");
+
+ BuildTraces();
+
+ BuildDataFlowSets();
+
+ RenameTemporaries();
+
+ TempForwarding();
+
+ //
+ // Now remove unused instructions
+ //
+
+ do {
+ ResetVisited();
+ blocks[0]->BuildLocalTempSets(numTemps, numFixedTemporaries);
+
+ ResetVisited();
+ blocks[0]->BuildGlobalProvidedTempSet(NumberSet(numTemps));
+
+ NumberSet totalRequired2(numTemps);
+
+ do {
+ ResetVisited();
+ } while (blocks[0]->BuildGlobalRequiredTempSet(totalRequired2));
+
+ ResetVisited();
+ } while (blocks[0]->RemoveUnusedResultInstructions(numFixedTemporaries));
+
+ DisassembleDebug("removed unused instructions 2");
+
+
+
+ FastNumberSet activeSet(numTemps);
+
+ //
+ // And remove unused temporaries
+ //
+ for (i = 0; i < numFixedTemporaries; i++)
+ activeSet += i;
+
+ ResetVisited();
+ blocks[0]->CollectActiveTemporaries(activeSet);
+
+
+ temporaries.SetSize(activeSet.Num());
+
+ ResetVisited();
+ blocks[0]->ShrinkActiveTemporaries(activeSet, temporaries);
+
+ MapVariables();
+
+ DisassembleDebug("mapped variabled");
+
+ _CrtCheckMemory();
+}
+
+void InterCodeProcedure::MapVariables(void)
+{
+ ResetVisited();
+ blocks[0]->MapVariables(mModule->mGlobalVars, mLocalVars);
+ mLocalSize = 0;
+ for (int i = 0; i < mLocalVars.Size(); i++)
+ {
+ if (mLocalVars[i].mUsed)
+ {
+ mLocalVars[i].mOffset = mLocalSize;
+ mLocalSize += mLocalVars[i].mSize;
+ }
+ }
+}
+
+void InterCodeProcedure::ReduceTemporaries(void)
+{
+ NumberSet* collisionSet;
+ int i, j, numRenamedTemps;
+ int numTemps = temporaries.Size();
+
+ ResetVisited();
+ blocks[0]->BuildLocalTempSets(numTemps, numFixedTemporaries);
+
+ ResetVisited();
+ blocks[0]->BuildGlobalProvidedTempSet(NumberSet(numTemps));
+
+ NumberSet totalRequired2(numTemps);
+
+ do {
+ ResetVisited();
+ } while (blocks[0]->BuildGlobalRequiredTempSet(totalRequired2));
+
+ collisionSet = new NumberSet[numTemps];
+
+ for (i = 0; i < numTemps; i++)
+ collisionSet[i].Reset(numTemps);
+
+ ResetVisited();
+ blocks[0]->BuildCollisionTable(collisionSet);
+
+ renameTable.SetSize(numTemps, true);
+
+ for (i = 0; i < numFixedTemporaries; i++)
+ renameTable[i] = i;
+
+ numRenamedTemps = numFixedTemporaries;
+
+ NumberSet usedTemps(numTemps);
+
+ for (i = numFixedTemporaries; i < numTemps; i++)
+ {
+ usedTemps.Clear();
+
+ for (j = numFixedTemporaries; j < numTemps; j++)
+ {
+ if (renameTable[j] >= 0 && (collisionSet[i][j] || !TypeCompatible(temporaries[j], temporaries[i])))
+ {
+ usedTemps += renameTable[j];
+ }
+ }
+
+ j = numFixedTemporaries;
+ while (usedTemps[j])
+ j++;
+
+ renameTable[i] = j;
+ if (j >= numRenamedTemps) numRenamedTemps = j + 1;
+ }
+
+ temporaries.SetSize(numRenamedTemps);
+
+ ResetVisited();
+ blocks[0]->GlobalRenameRegister(renameTable, temporaries);
+
+ delete[] collisionSet;
+
+ ResetVisited();
+ blocks[0]->BuildLocalTempSets(numRenamedTemps, numFixedTemporaries);
+
+ ResetVisited();
+ blocks[0]->BuildGlobalProvidedTempSet(NumberSet(numRenamedTemps));
+
+ NumberSet totalRequired3(numRenamedTemps);
+
+ do {
+ ResetVisited();
+ } while (blocks[0]->BuildGlobalRequiredTempSet(totalRequired3));
+
+ mTempOffset.SetSize(0);
+ int offset = 0;
+ if (!mLeafProcedure)
+ offset += 16;
+
+ for (int i = 0; i < temporaries.Size(); i++)
+ {
+ mTempOffset.Push(offset);
+ switch (temporaries[i])
+ {
+ case IT_FLOAT:
+ offset += 4;
+ break;
+ default:
+ offset += 2;
+ break;
+ }
+ }
+ mTempSize = offset;
+}
+
+void InterCodeProcedure::Disassemble(const char* name, bool dumpSets)
+{
+ FILE* file;
+ static bool initial = true;
+
+ if (!initial)
+ {
+ fopen_s(&file, "r:\\cldiss.txt", "a");
+ }
+ else
+ {
+ fopen_s(&file, "r:\\cldiss.txt", "w");
+ initial = false;
+ }
+
+ if (file)
+ {
+ fprintf(file, "--------------------------------------------------------------------\n");
+ fprintf(file, "%s : %s:%d\n", name, mLocation.mFileName, mLocation.mLine);
+
+ ResetVisited();
+ blocks[0]->Disassemble(file, dumpSets);
+
+ fclose(file);
+ }
+}
+
+InterCodeModule::InterCodeModule(void)
+ : mGlobalVars(InterVariable()), mProcedures(nullptr)
+{
+}
+
+InterCodeModule::~InterCodeModule(void)
+{
+
+}
diff --git a/oscar64/InterCode.h b/oscar64/InterCode.h
new file mode 100644
index 0000000..21c7467
--- /dev/null
+++ b/oscar64/InterCode.h
@@ -0,0 +1,486 @@
+#pragma once
+
+#include "Array.h"
+#include "NumberSet.h"
+#include "Errors.h"
+#include "BitVector.h"
+#include
+#include "MachineTypes.h"
+#include "Ident.h"
+
+enum InterCode
+{
+ IC_NONE,
+ IC_LOAD_TEMPORARY,
+ IC_STORE_TEMPORARY,
+ IC_BINARY_OPERATOR,
+ IC_UNARY_OPERATOR,
+ IC_RELATIONAL_OPERATOR,
+ IC_CONVERSION_OPERATOR,
+ IC_STORE,
+ IC_LOAD,
+ IC_LEA,
+ IC_COPY,
+ IC_TYPECAST,
+ IC_CONSTANT,
+ IC_BRANCH,
+ IC_JUMP,
+ IC_PUSH_FRAME,
+ IC_POP_FRAME,
+ IC_CALL,
+ IC_JSR,
+ IC_RETURN_VALUE,
+ IC_RETURN_STRUCT,
+ IC_RETURN
+};
+
+enum InterType
+{
+ IT_NONE,
+ IT_UNSIGNED,
+ IT_SIGNED,
+ IT_FLOAT,
+ IT_POINTER,
+ IT_BOOL
+};
+
+enum InterMemory
+{
+ IM_NONE,
+ IM_PARAM,
+ IM_LOCAL,
+ IM_GLOBAL,
+ IM_FRAME,
+ IM_PROCEDURE,
+ IM_INDIRECT,
+ IM_TEMPORARY,
+ IM_ABSOLUTE
+};
+
+enum InterOperator
+{
+ IA_NONE,
+ IA_ADD,
+ IA_SUB,
+ IA_MUL,
+ IA_DIVU,
+ IA_DIVS,
+ IA_MODU,
+ IA_MODS,
+ IA_OR,
+ IA_AND,
+ IA_XOR,
+ IA_NEG,
+ IA_ABS,
+ IA_FLOOR,
+ IA_CEIL,
+ IA_NOT,
+ IA_SHL,
+ IA_SHR,
+ IA_SAR,
+ IA_CMPEQ,
+ IA_CMPNE,
+ IA_CMPGES,
+ IA_CMPLES,
+ IA_CMPGS,
+ IA_CMPLS,
+ IA_CMPGEU,
+ IA_CMPLEU,
+ IA_CMPGU,
+ IA_CMPLU,
+ IA_FLOAT2INT,
+ IA_INT2FLOAT
+};
+
+class InterInstruction;
+class InterCodeBasicBlock;
+class InterCodeProcedure;
+class InterVariable;
+
+typedef InterInstruction* InterInstructionPtr;
+typedef InterCodeBasicBlock* InterCodeBasicBlockPtr;
+typedef InterCodeProcedure* InterCodeProcedurePtr;
+
+typedef GrowingArray GrowingTypeArray;
+typedef GrowingArray GrowingIntArray;
+typedef GrowingArray GrowingInstructionPtrArray;
+typedef GrowingArray GrowingInterCodeBasicBlockPtrArray;
+typedef GrowingArray GrowingInstructionArray;
+typedef GrowingArray GrowingInterCodeProcedurePtrArray;
+
+
+typedef GrowingArray GrowingVariableArray;
+
+#define INVALID_TEMPORARY (-1)
+
+class ValueSet
+{
+protected:
+ InterInstructionPtr * instructions;
+ int num, size;
+public:
+ ValueSet(void);
+ ValueSet(const ValueSet& values);
+ ~ValueSet(void);
+
+ void FlushAll(void);
+ void FlushCallAliases(void);
+
+ void RemoveValue(int index);
+ void InsertValue(InterInstruction& ins);
+
+ void UpdateValue(InterInstruction& ins, const GrowingInstructionPtrArray& tvalue, const NumberSet& aliasedLocals);
+};
+
+class TempForwardingTable
+{
+protected:
+ struct Assoc
+ {
+ int assoc, succ, pred;
+
+ Assoc(void) {}
+ Assoc(int assoc, int succ, int pred) { this->assoc = assoc; this->succ = succ; this->pred = pred; }
+ Assoc(const Assoc& assoc) { this->assoc = assoc.assoc; this->succ = assoc.succ; this->pred = assoc.pred; }
+ };
+
+ GrowingArray assoc;
+
+public:
+ TempForwardingTable(void) : assoc(Assoc(-1, -1, -1))
+ {
+ }
+
+ TempForwardingTable(const TempForwardingTable & table) : assoc(Assoc(-1, -1, -1))
+ {
+ for (int i = 0; i < table.assoc.Size(); i++)
+ {
+ assoc[i].assoc = table.assoc[i].assoc;
+ assoc[i].succ = table.assoc[i].succ;
+ assoc[i].pred = table.assoc[i].pred;
+ }
+ }
+
+ void SetSize(int size)
+ {
+ int i;
+ assoc.SetSize(size);
+
+ for (i = 0; i < size; i++)
+ assoc[i] = Assoc(i, i, i);
+ }
+
+ void Reset(void)
+ {
+ int i;
+
+ for (i = 0; i < assoc.Size(); i++)
+ assoc[i] = Assoc(i, i, i);
+ }
+
+ int operator[](int n)
+ {
+ return assoc[n].assoc;
+ }
+
+ void Destroy(int n)
+ {
+ int i, j;
+
+ if (assoc[n].assoc == n)
+ {
+ i = assoc[n].succ;
+ while (i != n)
+ {
+ j = assoc[i].succ;
+ assoc[i] = Assoc(i, i, i);
+ i = j;
+ }
+ }
+ else
+ {
+ assoc[assoc[n].pred].succ = assoc[n].succ;
+ assoc[assoc[n].succ].pred = assoc[n].pred;
+ }
+
+ assoc[n] = Assoc(n, n, n);
+ }
+
+ void Build(int from, int to)
+ {
+ int i;
+
+ from = assoc[from].assoc;
+ to = assoc[to].assoc;
+
+ if (from != to)
+ {
+ i = assoc[from].succ;
+ while (i != from)
+ {
+ assoc[i].assoc = to;
+ i = assoc[i].succ;
+ }
+ assoc[from].assoc = to;
+
+ assoc[assoc[to].succ].pred = assoc[from].pred;
+ assoc[assoc[from].pred].succ = assoc[to].succ;
+ assoc[to].succ = from;
+ assoc[from].pred = to;
+ }
+ }
+};
+
+class InterVariable
+{
+public:
+ bool mUsed, mAliased, mPlaced, mAssembler;
+ int mIndex, mSize, mOffset, mAddr;
+ int mNumReferences;
+ const uint8 * mData;
+ const Ident * mIdent;
+
+ struct Reference
+ {
+ uint16 mAddr;
+ bool mFunction, mLower, mUpper;
+ uint16 mIndex, mOffset;
+ } *mReferences;
+
+ InterVariable(void)
+ : mUsed(false), mAliased(false), mPlaced(false), mIndex(-1), mSize(0), mOffset(0), mNumReferences(0), mData(nullptr), mIdent(nullptr), mReferences(nullptr), mAssembler(false)
+ {
+ }
+};
+
+class InterInstruction
+{
+public:
+ InterCode code;
+ InterType ttype, stype[3];
+ int ttemp, stemp[3];
+ bool sfinal[3];
+ __int64 siconst[3];
+ double sfconst[3];
+ int spconst[3];
+ InterMemory mem;
+ InterOperator oper;
+ int opsize;
+ int vindex;
+ __int64 ivalue;
+ double fvalue;
+ bool zeroFrame;
+ Location loc;
+ InterCodeBasicBlock * exceptionJump;
+
+ InterInstruction(void);
+ void SetCode(const Location & loc, InterCode code);
+
+ void CollectLocalAddressTemps(GrowingIntArray& localTable);
+ void MarkAliasedLocalTemps(const GrowingIntArray& localTable, NumberSet& aliasedLocals);
+
+ void FilterTempUsage(NumberSet& requiredVars, NumberSet& providedVars);
+ void FilterVarsUsage(const GrowingVariableArray& localVars, NumberSet& requiredTemps, NumberSet& providedTemps);
+ bool RemoveUnusedResultInstructions(InterInstruction* pre, NumberSet& requiredTemps, int numStaticTemps);
+ bool RemoveUnusedStoreInstructions(const GrowingVariableArray& localVars, InterInstruction* pre, NumberSet& requiredTemps);
+ void PerformValueForwarding(GrowingInstructionPtrArray& tvalue, FastNumberSet& tvalid);
+
+ void LocalRenameRegister(GrowingIntArray& renameTable, int& num, int fixed);
+ void GlobalRenameRegister(const GrowingIntArray& renameTable, GrowingTypeArray& temporaries);
+
+ void PerformTempForwarding(TempForwardingTable& forwardingTable);
+
+ void BuildCollisionTable(NumberSet& liveTemps, NumberSet* collisionSets);
+ void ReduceTemporaries(const GrowingIntArray& renameTable, GrowingTypeArray& temporaries);
+
+ void CollectActiveTemporaries(FastNumberSet& set);
+ void ShrinkActiveTemporaries(FastNumberSet& set, GrowingTypeArray& temporaries);
+
+ void CollectSimpleLocals(FastNumberSet& complexLocals, FastNumberSet& simpleLocals, GrowingTypeArray& localTypes);
+ void SimpleLocalToTemp(int vindex, int temp);
+
+ void Disassemble(FILE* file);
+};
+
+
+class InterCodeException
+{
+public:
+ InterCodeException()
+ {
+ }
+};
+
+class InterCodeStackException : public InterCodeException
+{
+public:
+ InterCodeStackException()
+ : InterCodeException()
+ {
+ }
+};
+
+class InterCodeUndefinedException : public InterCodeException
+{
+public:
+ InterCodeUndefinedException()
+ : InterCodeException()
+ {
+ }
+};
+
+class InterCodeTypeMismatchException : public InterCodeException
+{
+public:
+ InterCodeTypeMismatchException()
+ : InterCodeException()
+ {
+ }
+};
+
+class InterCodeUninitializedException : public InterCodeException
+{
+public:
+ InterCodeUninitializedException()
+ : InterCodeException()
+ {
+ }
+};
+
+class InterCodeBasicBlock
+{
+public:
+ int num, numEntries;
+ InterCodeBasicBlock* trueJump, * falseJump;
+ GrowingInstructionArray code;
+
+ bool visited;
+ int entryISP, entryPSP, entryFSP;
+
+ NumberSet localRequiredTemps, localProvidedTemps;
+ NumberSet entryRequiredTemps, entryProvidedTemps;
+ NumberSet exitRequiredTemps, exitProvidedTemps;
+
+ NumberSet mLocalRequiredVars, mLocalProvidedVars;
+ NumberSet mEntryRequiredVars, mEntryProvidedVars;
+ NumberSet mExitRequiredVars, mExitProvidedVars;
+
+ InterCodeBasicBlock(void);
+ ~InterCodeBasicBlock(void);
+
+ void Append(InterInstruction & code);
+ void Close(InterCodeBasicBlock* trueJump, InterCodeBasicBlock* falseJump);
+
+ void CollectEntries(void);
+ void GenerateTraces(void);
+
+ void LocalToTemp(int vindex, int temp);
+
+ void CollectLocalAddressTemps(GrowingIntArray& localTable);
+ void MarkAliasedLocalTemps(const GrowingIntArray& localTable, NumberSet& aliasedLocals);
+
+ void BuildLocalTempSets(int num, int numFixed);
+ void BuildGlobalProvidedTempSet(NumberSet fromProvidedTemps);
+ bool BuildGlobalRequiredTempSet(NumberSet& fromRequiredTemps);
+ bool RemoveUnusedResultInstructions(int numStaticTemps);
+
+ void BuildLocalVariableSets(const GrowingVariableArray& localVars);
+ void BuildGlobalProvidedVariableSet(const GrowingVariableArray& localVars, NumberSet fromProvidedVars);
+ bool BuildGlobalRequiredVariableSet(const GrowingVariableArray& localVars, NumberSet& fromRequiredVars);
+ bool RemoveUnusedStoreInstructions(const GrowingVariableArray& localVars);
+
+ GrowingIntArray entryRenameTable;
+ GrowingIntArray exitRenameTable;
+
+ void LocalRenameRegister(const GrowingIntArray& renameTable, int& num, int fixed);
+ void BuildGlobalRenameRegisterTable(const GrowingIntArray& renameTable, GrowingIntArray& globalRenameTable);
+ void GlobalRenameRegister(const GrowingIntArray& renameTable, GrowingTypeArray& temporaries);
+
+ void CheckValueUsage(InterInstruction& ins, const GrowingInstructionPtrArray& tvalue);
+ void PerformTempForwarding(TempForwardingTable& forwardingTable);
+ void PerformValueForwarding(const GrowingInstructionPtrArray& tvalue, const ValueSet& values, FastNumberSet& tvalid, const NumberSet& aliasedLocals);
+ void PerformMachineSpecificValueUsageCheck(const GrowingInstructionPtrArray& tvalue, FastNumberSet& tvalid);
+
+ void BuildCollisionTable(NumberSet* collisionSets);
+ void ReduceTemporaries(const GrowingIntArray& renameTable, GrowingTypeArray& temporaries);
+
+ void CollectSimpleLocals(FastNumberSet& complexLocals, FastNumberSet& simpleLocals, GrowingTypeArray & localTypes);
+ void SimpleLocalToTemp(int vindex, int temp);
+
+ void CollectActiveTemporaries(FastNumberSet& set);
+ void ShrinkActiveTemporaries(FastNumberSet& set, GrowingTypeArray& temporaries);
+
+ void ApplyExceptionStackChanges(GrowingInterCodeBasicBlockPtrArray& exceptionStack);
+
+ void Disassemble(FILE* file, bool dumpSets);
+
+ void CollectVariables(GrowingVariableArray & globalVars, GrowingVariableArray & localVars);
+ void MapVariables(GrowingVariableArray& globalVars, GrowingVariableArray& localVars);
+
+ void CollectOuterFrame(int level, int& size);
+
+ bool IsLeafProcedure(void);
+};
+
+class InterCodeModule;
+
+class InterCodeProcedure
+{
+protected:
+ GrowingIntArray renameTable, renameUnionTable, globalRenameTable;
+ TempForwardingTable tempForwardingTable;
+ GrowingInstructionPtrArray valueForwardingTable;
+ int numFixedTemporaries;
+ NumberSet localAliasedSet;
+
+ void ResetVisited(void);
+public:
+ GrowingInterCodeBasicBlockPtrArray blocks;
+ GrowingTypeArray temporaries;
+ GrowingIntArray mTempOffset;
+ int mTempSize, mCommonFrameSize;
+ bool mLeafProcedure;
+
+ InterCodeModule * mModule;
+ int mID;
+
+ int mLocalSize;
+ GrowingVariableArray mLocalVars;
+
+ Location mLocation;
+ const Ident * mIdent;
+
+ InterCodeProcedure(InterCodeModule * module, const Location & location, const Ident * ident);
+ ~InterCodeProcedure(void);
+
+ int AddTemporary(InterType type);
+
+ void Append(InterCodeBasicBlock * block);
+ void Close(void);
+
+// void Set(InterCodeIDMapper* mapper, BitVector localStructure, Scanner scanner, bool debug);
+
+ void MapVariables(void);
+ void ReduceTemporaries(void);
+ void Disassemble(const char* name, bool dumpSets = false);
+protected:
+ void BuildTraces(void);
+ void BuildDataFlowSets(void);
+ void RenameTemporaries(void);
+ void TempForwarding(void);
+
+ void DisassembleDebug(const char* name);
+};
+
+class InterCodeModule
+{
+public:
+ InterCodeModule(void);
+ ~InterCodeModule(void);
+
+ GrowingInterCodeProcedurePtrArray mProcedures;
+
+ GrowingVariableArray mGlobalVars;
+
+ void UseGlobal(int index);
+};
diff --git a/oscar64/InterCodeGenerator.cpp b/oscar64/InterCodeGenerator.cpp
new file mode 100644
index 0000000..9d01778
--- /dev/null
+++ b/oscar64/InterCodeGenerator.cpp
@@ -0,0 +1,2194 @@
+#include "InterCodeGenerator.h"
+#include
+
+InterCodeGenerator::InterCodeGenerator(Errors* errors)
+ : mErrors(errors)
+{
+
+}
+
+InterCodeGenerator::~InterCodeGenerator(void)
+{
+
+}
+
+static inline InterType InterTypeOf(const Declaration* dec)
+{
+ switch (dec->mType)
+ {
+ default:
+ case DT_TYPE_VOID:
+ return IT_NONE;
+ case DT_TYPE_INTEGER:
+ case DT_TYPE_ENUM:
+ return (dec->mFlags & DTF_SIGNED) ? IT_SIGNED : IT_UNSIGNED;
+ case DT_TYPE_BOOL:
+ return IT_BOOL;
+ case DT_TYPE_FLOAT:
+ return IT_FLOAT;
+ case DT_TYPE_POINTER:
+ case DT_TYPE_FUNCTION:
+ case DT_TYPE_ARRAY:
+ return IT_POINTER;
+ }
+}
+
+InterCodeGenerator::ExValue InterCodeGenerator::Dereference(InterCodeProcedure* proc, InterCodeBasicBlock*& block, ExValue v, int level)
+{
+ while (v.mReference > level)
+ {
+ InterInstruction ins;
+ ins.code = IC_LOAD;
+ ins.mem = IM_INDIRECT;
+ ins.stype[0] = IT_POINTER;
+ ins.stemp[0] = v.mTemp;
+ ins.ttype = v.mReference == 1 ? InterTypeOf(v.mType) : IT_POINTER;
+ ins.ttemp = proc->AddTemporary(ins.ttype);
+ ins.opsize = v.mReference == 1 ? v.mType->mSize : 2;
+ block->Append(ins);
+
+ v = ExValue(v.mType, ins.ttemp, v.mReference - 1);
+ }
+
+ return v;
+}
+
+InterCodeGenerator::ExValue InterCodeGenerator::CoerceType(InterCodeProcedure* proc, InterCodeBasicBlock*& block, ExValue v, Declaration* type)
+{
+ if (v.mType->IsIntegerType() && type->mType == DT_TYPE_FLOAT)
+ {
+ InterInstruction cins;
+ cins.code = IC_CONVERSION_OPERATOR;
+ cins.oper = IA_INT2FLOAT;
+ cins.stype[0] = InterTypeOf(v.mType);
+ cins.stemp[0] = v.mTemp;
+ cins.ttype = IT_FLOAT;
+ cins.ttemp = proc->AddTemporary(cins.ttype);
+ v.mTemp = cins.ttemp;
+ v.mType = type;
+ block->Append(cins);
+ }
+ else if (v.mType->mType == DT_TYPE_FLOAT && type->IsIntegerType())
+ {
+ InterInstruction cins;
+ cins.code = IC_CONVERSION_OPERATOR;
+ cins.oper = IA_FLOAT2INT;
+ cins.stype[0] = InterTypeOf(v.mType);
+ cins.stemp[0] = v.mTemp;
+ cins.ttype = InterTypeOf(type);
+ cins.ttemp = proc->AddTemporary(cins.ttype);
+ v.mTemp = cins.ttemp;
+ v.mType = type;
+ block->Append(cins);
+ }
+
+ return v;
+}
+
+static inline bool InterTypeTypeInteger(InterType t)
+{
+ return t == IT_UNSIGNED || t == IT_SIGNED || t == IT_BOOL;
+}
+
+static inline InterType InterTypeOfArithmetic(InterType t1, InterType t2)
+{
+ if (t1 == IT_FLOAT || t2 == IT_FLOAT)
+ return IT_FLOAT;
+ else if (t1 == IT_SIGNED && t2 == IT_SIGNED)
+ return IT_SIGNED;
+ else if (t1 == IT_POINTER && t2 == IT_POINTER)
+ return IT_SIGNED;
+ else if (t1 == IT_POINTER || t2 == IT_POINTER)
+ return IT_POINTER;
+ else
+ return IT_UNSIGNED;
+}
+
+void InterCodeGenerator::InitGlobalVariable(InterCodeModule * mod, Declaration* dec)
+{
+ if (dec->mVarIndex < 0)
+ {
+ InterVariable var;
+ var.mOffset = 0;
+ var.mSize = dec->mSize;
+ var.mData = nullptr;
+ var.mIdent = dec->mIdent;
+ if (dec->mValue)
+ {
+ if (dec->mValue->mType == EX_CONSTANT)
+ {
+ uint8* d = new uint8[dec->mSize];
+ memset(d, 0, dec->mSize);
+ var.mData = d;
+
+ GrowingArray references({ 0 });
+ BuildInitializer(mod, d, 0, dec->mValue->mDecValue, references);
+ var.mNumReferences = references.Size();
+ if (var.mNumReferences)
+ {
+ var.mReferences = new InterVariable::Reference[var.mNumReferences];
+ for (int i = 0; i < var.mNumReferences; i++)
+ var.mReferences[i] = references[i];
+ }
+ }
+ else
+ mErrors->Error(dec->mLocation, "Non constant initializer");
+ }
+ dec->mVarIndex = mod->mGlobalVars.Size();
+ var.mIndex = dec->mVarIndex;
+ mod->mGlobalVars.Push(var);
+ }
+}
+
+void InterCodeGenerator::TranslateAssembler(InterCodeModule* mod, Expression * exp)
+{
+ int offset = 0, osize = 0;
+ Expression* cexp = exp;
+ while (cexp)
+ {
+ osize += AsmInsSize(cexp->mAsmInsType, cexp->mAsmInsMode);
+ cexp = cexp->mRight;
+ }
+
+ InterVariable var;
+ var.mOffset = 0;
+ var.mSize = osize;
+ uint8* d = new uint8[osize];
+ var.mData = d;
+ var.mAssembler = true;
+
+ var.mIndex = mod->mGlobalVars.Size();
+ if (exp->mDecValue)
+ {
+ exp->mDecValue->mVarIndex = var.mIndex;
+ var.mIdent = exp->mDecValue->mIdent;
+ }
+ mod->mGlobalVars.Push(var);
+
+ GrowingArray references({ 0 });
+
+ cexp = exp;
+ while (cexp)
+ {
+ if (cexp->mAsmInsType != ASMIT_BYTE)
+ {
+ int opcode = AsmInsOpcodes[cexp->mAsmInsType][cexp->mAsmInsMode];
+ d[offset++] = opcode;
+ }
+
+ Declaration* aexp = nullptr;
+ if (cexp->mLeft)
+ aexp = cexp->mLeft->mDecValue;
+
+ switch (cexp->mAsmInsMode)
+ {
+ case ASMIM_IMPLIED:
+ break;
+ case ASMIM_IMMEDIATE:
+ case ASMIM_ZERO_PAGE:
+ case ASMIM_ZERO_PAGE_X:
+ case ASMIM_INDIRECT_X:
+ case ASMIM_INDIRECT_Y:
+ d[offset++] = aexp->mInteger;
+ break;
+ case ASMIM_ABSOLUTE:
+ case ASMIM_INDIRECT:
+ case ASMIM_ABSOLUTE_X:
+ case ASMIM_ABSOLUTE_Y:
+ if (aexp->mType == DT_CONST_INTEGER)
+ {
+ d[offset++] = cexp->mLeft->mDecValue->mInteger & 255;
+ d[offset++] = cexp->mLeft->mDecValue->mInteger >> 8;
+ }
+ else if (aexp->mType == DT_LABEL)
+ {
+ if (aexp->mBase->mVarIndex < 0)
+ TranslateAssembler(mod, aexp->mBase->mValue);
+
+ InterVariable::Reference ref;
+ ref.mFunction = false;
+ ref.mUpper = true;
+ ref.mLower = true;
+ ref.mAddr = offset;
+ ref.mIndex = aexp->mBase->mVarIndex;
+ ref.mOffset = aexp->mInteger;
+
+ references.Push(ref);
+
+ offset += 2;
+ }
+ else if (aexp->mType == DT_LABEL_REF)
+ {
+ if (aexp->mBase->mBase->mVarIndex < 0)
+ TranslateAssembler(mod, aexp->mBase->mBase->mValue);
+
+ InterVariable::Reference ref;
+ ref.mFunction = false;
+ ref.mUpper = true;
+ ref.mLower = true;
+ ref.mAddr = offset;
+ ref.mIndex = aexp->mBase->mBase->mVarIndex;
+ ref.mOffset = aexp->mOffset + aexp->mBase->mInteger;
+
+ references.Push(ref);
+
+ offset += 2;
+ }
+ else if (aexp->mType == DT_CONST_ASSEMBLER)
+ {
+ if (aexp->mVarIndex < 0)
+ TranslateAssembler(mod, aexp->mValue);
+
+ InterVariable::Reference ref;
+ ref.mFunction = false;
+ ref.mUpper = true;
+ ref.mLower = true;
+ ref.mAddr = offset;
+ ref.mIndex = aexp->mVarIndex;
+ ref.mOffset = 0;
+
+ references.Push(ref);
+
+ offset += 2;
+ }
+ else if (aexp->mType == DT_VARIABLE)
+ {
+ if (aexp->mFlags & DTF_GLOBAL)
+ {
+ InitGlobalVariable(mod, aexp);
+
+ InterVariable::Reference ref;
+ ref.mFunction = false;
+ ref.mUpper = true;
+ ref.mLower = true;
+ ref.mAddr = offset;
+ ref.mIndex = aexp->mVarIndex;
+ ref.mOffset = 0;
+
+ references.Push(ref);
+
+ offset += 2;
+ }
+ }
+ else if (aexp->mType == DT_VARIABLE_REF)
+ {
+ if (aexp->mBase->mFlags & DTF_GLOBAL)
+ {
+ InitGlobalVariable(mod, aexp->mBase);
+
+ InterVariable::Reference ref;
+ ref.mFunction = false;
+ ref.mUpper = true;
+ ref.mLower = true;
+ ref.mAddr = offset;
+ ref.mIndex = aexp->mBase->mVarIndex;
+ ref.mOffset = aexp->mOffset;
+
+ references.Push(ref);
+
+ offset += 2;
+ }
+ }
+ break;
+ case ASMIM_RELATIVE:
+ d[offset] = aexp->mInteger - offset - 1;
+ offset++;
+ break;
+ }
+
+ cexp = cexp->mRight;
+ }
+
+ assert(offset == osize);
+
+ InterVariable& ivar(mod->mGlobalVars[var.mIndex]);
+
+ ivar.mNumReferences = references.Size();
+ if (ivar.mNumReferences)
+ {
+ ivar.mReferences = new InterVariable::Reference[ivar.mNumReferences];
+ for (int i = 0; i < ivar.mNumReferences; i++)
+ ivar.mReferences[i] = references[i];
+ }
+}
+
+InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* procType, InterCodeProcedure* proc, InterCodeBasicBlock*& block, Expression* exp, InterCodeBasicBlock* breakBlock, InterCodeBasicBlock* continueBlock)
+{
+ Declaration* dec;
+ ExValue vl, vr;
+
+ for (;;)
+ {
+ switch (exp->mType)
+ {
+ case EX_VOID:
+ return ExValue(TheVoidTypeDeclaration);
+
+ case EX_SEQUENCE:
+ vr = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock);
+ exp = exp->mRight;
+ if (!exp)
+ return ExValue(TheVoidTypeDeclaration);
+ break;
+ case EX_CONSTANT:
+ dec = exp->mDecValue;
+ switch (dec->mType)
+ {
+ case DT_CONST_INTEGER:
+ {
+ InterInstruction ins;
+ ins.code = IC_CONSTANT;
+ ins.ttype = InterTypeOf(dec->mBase);
+ ins.ttemp = proc->AddTemporary(ins.ttype);
+ if (ins.ttype == IT_SIGNED)
+ ins.ivalue = short(dec->mInteger);
+ else
+ ins.ivalue = unsigned short(dec->mInteger);
+ block->Append(ins);
+ return ExValue(dec->mBase, ins.ttemp);
+
+ } break;
+
+ case DT_CONST_FLOAT:
+ {
+ InterInstruction ins;
+ ins.code = IC_CONSTANT;
+ ins.ttype = InterTypeOf(dec->mBase);
+ ins.ttemp = proc->AddTemporary(ins.ttype);
+ ins.fvalue = dec->mNumber;
+ block->Append(ins);
+ return ExValue(dec->mBase, ins.ttemp);
+
+ } break;
+
+ case DT_CONST_ADDRESS:
+ {
+ InterInstruction ins;
+ ins.code = IC_CONSTANT;
+ ins.ttype = IT_POINTER;
+ ins.ttemp = proc->AddTemporary(IT_POINTER);
+ ins.ivalue = dec->mInteger;
+ ins.mem = IM_ABSOLUTE;
+ block->Append(ins);
+ return ExValue(dec->mBase, ins.ttemp);
+
+ } break;
+
+ case DT_CONST_FUNCTION:
+ {
+ if (dec->mVarIndex < 0)
+ {
+ InterCodeProcedure* cproc = this->TranslateProcedure(proc->mModule, dec->mValue, dec);
+ cproc->ReduceTemporaries();
+ }
+
+ InterInstruction ins;
+ ins.code = IC_CONSTANT;
+ ins.ttype = InterTypeOf(dec->mBase);
+ ins.ttemp = proc->AddTemporary(ins.ttype);
+ ins.vindex = dec->mVarIndex;
+ ins.mem = IM_PROCEDURE;
+ ins.ivalue = 0;
+ block->Append(ins);
+ return ExValue(dec->mBase, ins.ttemp);
+
+ } break;
+
+ case DT_CONST_POINTER:
+ {
+ vl = TranslateExpression(procType, proc, block, dec->mValue, breakBlock, continueBlock);
+ return vl;
+ }
+ case DT_CONST_DATA:
+ {
+ if (dec->mVarIndex < 0)
+ {
+ dec->mVarIndex = proc->mModule->mGlobalVars.Size();
+ InterVariable var;
+ var.mIndex = dec->mVarIndex;
+ var.mIdent = dec->mIdent;
+ var.mOffset = 0;
+ var.mSize = dec->mSize;
+ var.mData = dec->mData;
+ proc->mModule->mGlobalVars.Push(var);
+ }
+
+ InterInstruction ins;
+ ins.code = IC_CONSTANT;
+ ins.ttype = IT_POINTER;
+ ins.ttemp = proc->AddTemporary(IT_POINTER);
+ ins.ivalue = 0;
+ ins.vindex = dec->mVarIndex;
+ ins.mem = IM_GLOBAL;
+ block->Append(ins);
+ return ExValue(dec->mBase, ins.ttemp);
+ }
+
+ default:
+ mErrors->Error(dec->mLocation, "Unimplemented constant type");
+ }
+
+ return ExValue(TheVoidTypeDeclaration);
+
+ case EX_VARIABLE:
+ {
+ dec = exp->mDecValue;
+
+ InterInstruction ins;
+ ins.code = IC_CONSTANT;
+ ins.ttype = IT_POINTER;
+ ins.ttemp = proc->AddTemporary(ins.ttype);
+ ins.opsize = dec->mSize;
+ ins.ivalue = dec->mOffset;
+ if (dec->mType == DT_ARGUMENT)
+ ins.mem = IM_PARAM;
+ else if (dec->mFlags & DTF_GLOBAL)
+ {
+ InitGlobalVariable(proc->mModule, dec);
+ ins.mem = IM_GLOBAL;
+ }
+ else
+ ins.mem = IM_LOCAL;
+ ins.vindex = dec->mVarIndex;
+
+ block->Append(ins);
+
+ if (!(dec->mBase->mFlags & DTF_DEFINED))
+ mErrors->Error(dec->mLocation, "Undefined variable type");
+
+ return ExValue(dec->mBase, ins.ttemp, 1);
+ }
+
+
+ case EX_ASSIGNMENT:
+ {
+ vr = TranslateExpression(procType, proc, block, exp->mRight, breakBlock, continueBlock);
+ vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock);
+
+ if (!vl.mType->CanAssign(vr.mType))
+ mErrors->Error(exp->mLocation, "Cannot assign incompatible types");
+
+ if (vl.mType->mFlags & DTF_CONST)
+ mErrors->Error(exp->mLocation, "Cannot assign to const type");
+
+ if (vl.mType->mType == DT_TYPE_STRUCT || vl.mType->mType == DT_TYPE_ARRAY)
+ {
+ vr = Dereference(proc, block, vr, 1);
+ vl = Dereference(proc, block, vl, 1);
+
+ if (vl.mReference != 1)
+ mErrors->Error(exp->mLeft->mLocation, "Not a left hand expression");
+ if (vr.mReference != 1)
+ mErrors->Error(exp->mLeft->mLocation, "Not an adressable expression");
+
+
+ InterInstruction ins;
+ ins.code = IC_COPY;
+ ins.mem = IM_INDIRECT;
+ ins.stype[0] = IT_POINTER;
+ ins.stemp[0] = vr.mTemp;
+ ins.stype[1] = IT_POINTER;
+ ins.stemp[1] = vl.mTemp;
+ ins.opsize = vl.mType->mSize;
+ block->Append(ins);
+ }
+ else
+ {
+ if (vl.mType->mType == DT_TYPE_POINTER && (vr.mType->mType == DT_TYPE_ARRAY || vr.mType->mType == DT_TYPE_FUNCTION))
+ vr = Dereference(proc, block, vr, 1);
+ else
+ vr = Dereference(proc, block, vr);
+
+ vl = Dereference(proc, block, vl, 1);
+
+ if (vl.mReference != 1)
+ mErrors->Error(exp->mLeft->mLocation, "Not a left hand expression");
+
+ InterInstruction ins;
+
+ if (exp->mToken != TK_ASSIGN)
+ {
+ ExValue vll = Dereference(proc, block, vl);
+
+ if (vl.mType->mType == DT_TYPE_POINTER)
+ {
+ InterInstruction cins;
+ cins.code = IC_CONSTANT;
+
+ if (exp->mToken == TK_ASSIGN_ADD)
+ {
+ cins.ivalue = vl.mType->mBase->mSize;
+ }
+ else if (exp->mToken == TK_ASSIGN_SUB)
+ {
+ cins.ivalue = -vl.mType->mBase->mSize;
+ }
+ else
+ mErrors->Error(exp->mLocation, "Invalid pointer assignment");
+
+ if (!vr.mType->IsIntegerType())
+ mErrors->Error(exp->mLocation, "Invalid argument for pointer inc/dec");
+
+ cins.ttype = IT_SIGNED;
+ cins.ttemp = proc->AddTemporary(cins.ttype);
+ block->Append(cins);
+
+ InterInstruction mins;
+ mins.code = IC_BINARY_OPERATOR;
+ mins.oper = IA_MUL;
+ mins.stype[0] = IT_SIGNED;
+ mins.stemp[0] = vr.mTemp;
+ mins.stype[1] = IT_SIGNED;
+ mins.stemp[1] = cins.ttemp;
+ mins.ttype = IT_SIGNED;
+ mins.ttemp = proc->AddTemporary(mins.ttype);
+ block->Append(mins);
+
+ InterInstruction ains;
+ ains.code = IC_LEA;
+ ains.mem = IM_INDIRECT;
+ ains.stype[0] = IT_SIGNED;
+ ains.stemp[0] = mins.ttemp;
+ ains.stype[1] = IT_POINTER;
+ ains.stemp[1] = vl.mTemp;
+ ains.ttype = IT_POINTER;
+ ains.ttemp = proc->AddTemporary(ains.ttype);
+ block->Append(ains);
+ }
+ else
+ {
+ if (vll.mType->IsIntegerType() && vr.mType->mType == DT_TYPE_FLOAT)
+ {
+ InterInstruction cins;
+ cins.code = IC_CONVERSION_OPERATOR;
+ cins.oper = IA_FLOAT2INT;
+ cins.stype[0] = InterTypeOf(vr.mType);
+ cins.stemp[0] = vr.mTemp;
+ cins.ttype = InterTypeOf(vll.mType);
+ cins.ttemp = proc->AddTemporary(cins.ttype);
+ vr.mTemp = cins.ttemp;
+ vr.mType = TheSignedIntTypeDeclaration;
+ block->Append(cins);
+ }
+ else if (vll.mType->mType == DT_TYPE_FLOAT && vr.mType->IsIntegerType())
+ {
+ InterInstruction cins;
+ cins.code = IC_CONVERSION_OPERATOR;
+ cins.oper = IA_INT2FLOAT;
+ cins.stype[0] = InterTypeOf(vr.mType);
+ cins.stemp[0] = vr.mTemp;
+ cins.ttype = InterTypeOf(vll.mType);;
+ cins.ttemp = proc->AddTemporary(cins.ttype);
+ vr.mTemp = cins.ttemp;
+ vr.mType = TheFloatTypeDeclaration;
+ block->Append(cins);
+ }
+
+ InterInstruction oins;
+ oins.code = IC_BINARY_OPERATOR;
+ oins.stype[0] = InterTypeOf(vr.mType);
+ oins.stemp[0] = vr.mTemp;
+ oins.stype[1] = InterTypeOf(vll.mType);
+ oins.stemp[1] = vll.mTemp;
+ oins.ttype = InterTypeOf(vll.mType);
+ oins.ttemp = proc->AddTemporary(oins.ttype);
+
+ if (!vll.mType->IsNumericType())
+ mErrors->Error(exp->mLocation, "Left hand element type is not numeric");
+ if (!vr.mType->IsNumericType())
+ mErrors->Error(exp->mLocation, "Right hand element type is not numeric");
+
+ switch (exp->mToken)
+ {
+ case TK_ASSIGN_ADD:
+ oins.oper = IA_ADD;
+ break;
+ case TK_ASSIGN_SUB:
+ oins.oper = IA_SUB;
+ break;
+ case TK_ASSIGN_MUL:
+ oins.oper = IA_MUL;
+ break;
+ case TK_ASSIGN_DIV:
+ oins.oper = IA_DIVS;
+ break;
+ case TK_ASSIGN_MOD:
+ oins.oper = IA_MODS;
+ break;
+ case TK_ASSIGN_SHL:
+ oins.oper = IA_SHL;
+ break;
+ case TK_ASSIGN_SHR:
+ oins.oper = IA_SHR;
+ break;
+ case TK_ASSIGN_AND:
+ oins.oper = IA_AND;
+ break;
+ case TK_ASSIGN_XOR:
+ oins.oper = IA_XOR;
+ break;
+ case TK_ASSIGN_OR:
+ oins.oper = IA_OR;
+ break;
+ }
+
+ vr.mTemp = oins.ttemp;
+ vr.mType = vll.mType;
+
+ block->Append(oins);
+ }
+ }
+ else
+ {
+ if (vl.mType->IsIntegerType() && vr.mType->mType == DT_TYPE_FLOAT)
+ {
+ InterInstruction cins;
+ cins.code = IC_CONVERSION_OPERATOR;
+ cins.oper = IA_FLOAT2INT;
+ cins.stype[0] = InterTypeOf(vr.mType);
+ cins.stemp[0] = vr.mTemp;
+ cins.ttype = InterTypeOf(vl.mType);
+ cins.ttemp = proc->AddTemporary(cins.ttype);
+ vr.mTemp = cins.ttemp;
+ vr.mType = TheSignedIntTypeDeclaration;
+ block->Append(cins);
+ }
+ else if (vl.mType->mType == DT_TYPE_FLOAT && vr.mType->IsIntegerType())
+ {
+ InterInstruction cins;
+ cins.code = IC_CONVERSION_OPERATOR;
+ cins.oper = IA_INT2FLOAT;
+ cins.stype[0] = InterTypeOf(vr.mType);
+ cins.stemp[0] = vr.mTemp;
+ cins.ttype = InterTypeOf(vl.mType);;
+ cins.ttemp = proc->AddTemporary(cins.ttype);
+ vr.mTemp = cins.ttemp;
+ vr.mType = TheFloatTypeDeclaration;
+ block->Append(cins);
+ }
+ }
+
+ ins.code = IC_STORE;
+ ins.mem = IM_INDIRECT;
+ ins.stype[0] = InterTypeOf(vr.mType);
+ ins.stemp[0] = vr.mTemp;
+ ins.stype[1] = IT_POINTER;
+ ins.stemp[1] = vl.mTemp;
+ ins.opsize = vl.mType->mSize;
+ block->Append(ins);
+ }
+ }
+
+ return vr;
+
+ case EX_INDEX:
+ {
+ vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock);
+ vr = TranslateExpression(procType, proc, block, exp->mRight, breakBlock, continueBlock);
+
+ vl = Dereference(proc, block, vl, vl.mType->mType == DT_TYPE_POINTER ? 0 : 1);
+ vr = Dereference(proc, block, vr);
+
+ if (vl.mType->mType != DT_TYPE_ARRAY && vl.mType->mType != DT_TYPE_POINTER)
+ mErrors->Error(exp->mLocation, "Invalid type for indexing");
+
+ if (!vr.mType->IsIntegerType())
+ mErrors->Error(exp->mLocation, "Index operand is not integral number");
+
+ InterInstruction cins;
+ cins.code = IC_CONSTANT;
+ cins.ivalue = vl.mType->mBase->mSize;
+ cins.ttype = IT_SIGNED;
+ cins.ttemp = proc->AddTemporary(cins.ttype);
+ block->Append(cins);
+
+ InterInstruction mins;
+ mins.code = IC_BINARY_OPERATOR;
+ mins.oper = IA_MUL;
+ mins.stype[0] = IT_SIGNED;
+ mins.stemp[0] = vr.mTemp;
+ mins.stype[1] = IT_SIGNED;
+ mins.stemp[1] = cins.ttemp;
+ mins.ttype = IT_SIGNED;
+ mins.ttemp = proc->AddTemporary(mins.ttype);
+ block->Append(mins);
+
+ InterInstruction ains;
+ ains.code = IC_LEA;
+ ains.mem = IM_INDIRECT;
+ ains.stype[0] = IT_SIGNED;
+ ains.stemp[0] = mins.ttemp;
+ ains.stype[1] = IT_POINTER;
+ ains.stemp[1] = vl.mTemp;
+ ains.ttype = IT_POINTER;
+ ains.ttemp = proc->AddTemporary(ains.ttype);
+ block->Append(ains);
+
+ return ExValue(vl.mType->mBase, ains.ttemp, 1);
+ }
+
+ case EX_QUALIFY:
+ {
+ vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock);
+ vl = Dereference(proc, block, vl, 1);
+
+ if (vl.mReference != 1)
+ mErrors->Error(exp->mLocation, "Not an addressable expression");
+
+ InterInstruction cins;
+ cins.code = IC_CONSTANT;
+ cins.ivalue = exp->mDecValue->mOffset;
+ cins.ttype = IT_SIGNED;
+ cins.ttemp = proc->AddTemporary(cins.ttype);
+ block->Append(cins);
+
+ InterInstruction ains;
+ ains.code = IC_LEA;
+ ains.mem = IM_INDIRECT;
+ ains.stype[0] = IT_SIGNED;
+ ains.stemp[0] = cins.ttemp;
+ ains.stype[1] = IT_POINTER;
+ ains.stemp[1] = vl.mTemp;
+ ains.ttype = IT_POINTER;
+ ains.ttemp = proc->AddTemporary(ains.ttype);
+ block->Append(ains);
+
+ return ExValue(exp->mDecValue->mBase, ains.ttemp, 1);
+ }
+
+ case EX_BINARY:
+ {
+ vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock);
+ vr = TranslateExpression(procType, proc, block, exp->mRight, breakBlock, continueBlock);
+ vr = Dereference(proc, block, vr);
+
+ InterInstruction ins;
+
+ if (vl.mType->mType == DT_TYPE_POINTER || vl.mType->mType == DT_TYPE_ARRAY)
+ {
+ if (vl.mType->mType == DT_TYPE_POINTER)
+ vl = Dereference(proc, block, vl);
+ else
+ {
+ vl = Dereference(proc, block, vl, 1);
+
+ Declaration* ptype = new Declaration(exp->mLocation, DT_TYPE_POINTER);
+ ptype->mBase = vl.mType->mBase;
+ ptype->mSize = 2;
+ vl.mType = ptype;
+ }
+
+ if (vr.mType->IsIntegerType())
+ {
+ InterInstruction cins;
+ cins.code = IC_CONSTANT;
+
+ if (exp->mToken == TK_ADD)
+ {
+ cins.ivalue = vl.mType->mBase->mSize;
+ }
+ else if (exp->mToken == TK_SUB)
+ {
+ cins.ivalue = -vl.mType->mBase->mSize;
+ }
+ else
+ mErrors->Error(exp->mLocation, "Invalid pointer operation");
+
+ cins.ttype = IT_SIGNED;
+ cins.ttemp = proc->AddTemporary(cins.ttype);
+ block->Append(cins);
+
+ InterInstruction mins;
+ mins.code = IC_BINARY_OPERATOR;
+ mins.oper = IA_MUL;
+ mins.stype[0] = IT_SIGNED;
+ mins.stemp[0] = vr.mTemp;
+ mins.stype[1] = IT_SIGNED;
+ mins.stemp[1] = cins.ttemp;
+ mins.ttype = IT_SIGNED;
+ mins.ttemp = proc->AddTemporary(mins.ttype);
+ block->Append(mins);
+
+ ins.code = IC_LEA;
+ ins.mem = IM_INDIRECT;
+ ins.stype[0] = IT_SIGNED;
+ ins.stemp[0] = mins.ttemp;
+ ins.stype[1] = IT_POINTER;
+ ins.stemp[1] = vl.mTemp;
+ ins.ttype = IT_POINTER;
+ ins.ttemp = proc->AddTemporary(ins.ttype);
+ block->Append(ins);
+ }
+ else if (vr.mType->IsSame(vl.mType))
+ {
+ if (exp->mToken == TK_SUB)
+ {
+ InterInstruction clins, crins;
+ clins.code = IC_TYPECAST;
+ clins.stemp[0] = vl.mTemp;
+ clins.stype[0] = IT_POINTER;
+ clins.ttype = IT_SIGNED;
+ clins.ttemp = proc->AddTemporary(clins.ttype);
+ block->Append(clins);
+
+ crins.code = IC_TYPECAST;
+ crins.stemp[0] = vr.mTemp;
+ crins.stype[0] = IT_POINTER;
+ crins.ttype = IT_SIGNED;
+ crins.ttemp = proc->AddTemporary(crins.ttype);
+ block->Append(crins);
+
+ InterInstruction cins;
+ cins.code = IC_CONSTANT;
+ cins.ivalue = vl.mType->mBase->mSize;
+ cins.ttype = IT_SIGNED;
+ cins.ttemp = proc->AddTemporary(cins.ttype);
+ block->Append(cins);
+
+ InterInstruction sins, dins;
+ sins.code = IC_BINARY_OPERATOR;
+ sins.oper = IA_SUB;
+ sins.stype[0] = IT_SIGNED;
+ sins.stemp[0] = crins.ttemp;
+ sins.stype[1] = IT_SIGNED;
+ sins.stemp[1] = clins.ttemp;
+ sins.ttype = IT_SIGNED;
+ sins.ttemp = proc->AddTemporary(sins.ttype);
+ block->Append(sins);
+
+ dins.code = IC_BINARY_OPERATOR;
+ dins.oper = IA_DIVS;
+ dins.stype[0] = IT_SIGNED;
+ dins.stemp[0] = cins.ttemp;
+ dins.stype[1] = IT_SIGNED;
+ dins.stemp[1] = sins.ttemp;
+ dins.ttype = IT_SIGNED;
+ dins.ttemp = proc->AddTemporary(dins.ttype);
+ block->Append(dins);
+
+ return ExValue(TheSignedIntTypeDeclaration, dins.ttemp);
+ }
+ else
+ mErrors->Error(exp->mLocation, "Invalid pointer operation");
+ }
+ }
+ else
+ {
+ vl = Dereference(proc, block, vl);
+
+ if (!vl.mType->IsNumericType())
+ mErrors->Error(exp->mLocation, "Left hand operand type is not numeric");
+ if (!vr.mType->IsNumericType())
+ mErrors->Error(exp->mLocation, "Right hand operand type is not numeric");
+
+ if (vl.mType->IsIntegerType() && vr.mType->mType == DT_TYPE_FLOAT)
+ {
+ InterInstruction cins;
+ cins.code = IC_CONVERSION_OPERATOR;
+ cins.oper = IA_INT2FLOAT;
+ cins.stype[0] = InterTypeOf(vl.mType);
+ cins.stemp[0] = vl.mTemp;
+ cins.ttype = IT_FLOAT;
+ cins.ttemp = proc->AddTemporary(cins.ttype);
+ vl.mTemp = cins.ttemp;
+ vl.mType = TheFloatTypeDeclaration;
+ block->Append(cins);
+ }
+ else if (vl.mType->mType == DT_TYPE_FLOAT && vr.mType->IsIntegerType())
+ {
+ InterInstruction cins;
+ cins.code = IC_CONVERSION_OPERATOR;
+ cins.oper = IA_INT2FLOAT;
+ cins.stype[0] = InterTypeOf(vr.mType);
+ cins.stemp[0] = vr.mTemp;
+ cins.ttype = IT_FLOAT;
+ cins.ttemp = proc->AddTemporary(cins.ttype);
+ vr.mTemp = cins.ttemp;
+ vr.mType = TheFloatTypeDeclaration;
+ block->Append(cins);
+ }
+
+ bool signedOP = (vl.mType->mFlags & DTF_SIGNED) && (vr.mType->mFlags & DTF_SIGNED);
+
+ ins.code = IC_BINARY_OPERATOR;
+ switch (exp->mToken)
+ {
+ case TK_ADD:
+ ins.oper = IA_ADD;
+ break;
+ case TK_SUB:
+ ins.oper = IA_SUB;
+ break;
+ case TK_MUL:
+ ins.oper = IA_MUL;
+ break;
+ case TK_DIV:
+ ins.oper = signedOP ? IA_DIVS : IA_DIVU;
+ break;
+ case TK_MOD:
+ ins.oper = signedOP ? IA_MODS : IA_MODU;
+ break;
+ case TK_LEFT_SHIFT:
+ ins.oper = IA_SHL;
+ break;
+ case TK_RIGHT_SHIFT:
+ ins.oper = (vl.mType->mFlags & DTF_SIGNED) ? IA_SAR : IA_SHR;
+ break;
+ case TK_BINARY_AND:
+ ins.oper = IA_AND;
+ break;
+ case TK_BINARY_OR:
+ ins.oper = IA_OR;
+ break;
+ case TK_BINARY_XOR:
+ ins.oper = IA_XOR;
+ break;
+ }
+
+ ins.stype[0] = InterTypeOf(vr.mType);;
+ ins.stemp[0] = vr.mTemp;
+ ins.stype[1] = InterTypeOf(vl.mType);;
+ ins.stemp[1] = vl.mTemp;
+ ins.ttype = InterTypeOfArithmetic(ins.stype[0], ins.stype[1]);
+ ins.ttemp = proc->AddTemporary(ins.ttype);
+ block->Append(ins);
+ }
+
+ return ExValue(vl.mType, ins.ttemp);
+ }
+
+
+ case EX_PREINCDEC:
+ {
+ vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock);
+ vl = Dereference(proc, block, vl, 1);
+
+ if (vl.mReference != 1)
+ mErrors->Error(exp->mLeft->mLocation, "Not a left hand expression");
+
+ if (vl.mType->mFlags & DTF_CONST)
+ mErrors->Error(exp->mLocation, "Cannot change const value");
+
+ InterInstruction cins, ains, rins, sins;
+
+ ExValue vdl = Dereference(proc, block, vl);
+
+ bool ftype = vl.mType->mType == DT_TYPE_FLOAT;
+
+ cins.code = IC_CONSTANT;
+ cins.ttype = ftype ? IT_FLOAT : IT_SIGNED;
+ cins.ttemp = proc->AddTemporary(cins.ttype);
+ if (vdl.mType->mType == DT_TYPE_POINTER)
+ cins.ivalue = exp->mToken == TK_INC ? vdl.mType->mBase->mSize : -(vdl.mType->mBase->mSize);
+ else if (vdl.mType->IsNumericType())
+ cins.ivalue = exp->mToken == TK_INC ? 1 : -1;
+ else
+ mErrors->Error(exp->mLocation, "Not a numeric value or pointer");
+
+ block->Append(cins);
+
+ ains.code = IC_BINARY_OPERATOR;
+ ains.oper = IA_ADD;
+ ains.stype[0] = cins.ttype;
+ ains.stemp[0] = cins.ttemp;
+ ains.stype[1] = InterTypeOf(vdl.mType);
+ ains.stemp[1] = vdl.mTemp;
+ ains.ttype = ains.stype[1];
+ ains.ttemp = proc->AddTemporary(ains.ttype);
+ block->Append(ains);
+
+ sins.code = IC_STORE;
+ sins.mem = IM_INDIRECT;
+ sins.stype[0] = ains.ttype;
+ sins.stemp[0] = ains.ttemp;
+ sins.stype[1] = IT_POINTER;
+ sins.stemp[1] = vl.mTemp;
+ sins.opsize = vl.mType->mSize;
+ block->Append(sins);
+
+ return ExValue(vdl.mType, ains.ttemp);
+ }
+ break;
+
+ case EX_POSTINCDEC:
+ {
+ vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock);
+ vl = Dereference(proc, block, vl, 1);
+
+ if (vl.mReference != 1)
+ mErrors->Error(exp->mLeft->mLocation, "Not a left hand expression");
+
+ if (vl.mType->mFlags & DTF_CONST)
+ mErrors->Error(exp->mLocation, "Cannot change const value");
+
+ InterInstruction cins, ains, rins, sins;
+
+ ExValue vdl = Dereference(proc, block, vl);
+
+ bool ftype = vl.mType->mType == DT_TYPE_FLOAT;
+
+ cins.code = IC_CONSTANT;
+ cins.ttype = ftype ? IT_FLOAT : IT_SIGNED;
+ cins.ttemp = proc->AddTemporary(cins.ttype);
+ if (vdl.mType->mType == DT_TYPE_POINTER)
+ cins.ivalue = exp->mToken == TK_INC ? vdl.mType->mBase->mSize : -(vdl.mType->mBase->mSize);
+ else if (vdl.mType->IsNumericType())
+ cins.ivalue = exp->mToken == TK_INC ? 1 : -1;
+ else
+ mErrors->Error(exp->mLocation, "Not a numeric value or pointer");
+ block->Append(cins);
+
+ ains.code = IC_BINARY_OPERATOR;
+ ains.oper = IA_ADD;
+ ains.stype[0] = cins.ttype;
+ ains.stemp[0] = cins.ttemp;
+ ains.stype[1] = InterTypeOf(vdl.mType);
+ ains.stemp[1] = vdl.mTemp;
+ ains.ttype = ains.stype[1];
+ ains.ttemp = proc->AddTemporary(ains.ttype);
+ block->Append(ains);
+
+ sins.code = IC_STORE;
+ sins.mem = IM_INDIRECT;
+ sins.stype[0] = ains.ttype;
+ sins.stemp[0] = ains.ttemp;
+ sins.stype[1] = IT_POINTER;
+ sins.stemp[1] = vl.mTemp;
+ sins.opsize = vl.mType->mSize;
+ block->Append(sins);
+
+ return ExValue(vdl.mType, vdl.mTemp);
+ }
+ break;
+
+ case EX_PREFIX:
+ {
+ vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock);
+
+ InterInstruction ins;
+
+ ins.code = IC_UNARY_OPERATOR;
+
+ switch (exp->mToken)
+ {
+ case TK_ADD:
+ vl = Dereference(proc, block, vl);
+ ins.oper = IA_NONE;
+ break;
+ case TK_SUB:
+ vl = Dereference(proc, block, vl);
+ if (!vl.mType->IsNumericType())
+ mErrors->Error(exp->mLocation, "Not a numeric type");
+ ins.oper = IA_NEG;
+ break;
+ case TK_BINARY_NOT:
+ vl = Dereference(proc, block, vl);
+ if (!(vl.mType->mType == DT_TYPE_POINTER || vl.mType->IsNumericType()))
+ mErrors->Error(exp->mLocation, "Not a numeric or pointer type");
+ ins.oper = IA_NOT;
+ break;
+ case TK_MUL:
+ if (vl.mType->mType != DT_TYPE_POINTER)
+ mErrors->Error(exp->mLocation, "Not a pointer type");
+ return ExValue(vl.mType->mBase, vl.mTemp, vl.mReference + 1);
+ case TK_BINARY_AND:
+ {
+ if (vl.mReference < 1)
+ mErrors->Error(exp->mLocation, "Not an addressable value");
+
+ Declaration* dec = new Declaration(exp->mLocation, DT_TYPE_POINTER);
+ dec->mBase = vl.mType;
+ dec->mSize = 2;
+ dec->mFlags = DTF_DEFINED;
+ return ExValue(dec, vl.mTemp, vl.mReference - 1);
+ }
+ }
+
+ ins.stype[0] = InterTypeOf(vl.mType);
+ ins.stemp[0] = vl.mTemp;
+ ins.ttype = ins.stype[0];
+ ins.ttemp = proc->AddTemporary(ins.ttype);
+
+ block->Append(ins);
+
+ return ExValue(vl.mType, ins.ttemp);
+ }
+
+ case EX_RELATIONAL:
+ {
+ vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock);
+ vl = Dereference(proc, block, vl);
+ vr = TranslateExpression(procType, proc, block, exp->mRight, breakBlock, continueBlock);
+ vr = Dereference(proc, block, vr);
+
+ InterInstruction ins;
+
+ bool signedCompare = (vl.mType->mFlags & DTF_SIGNED) && (vr.mType->mFlags & DTF_SIGNED);
+
+ if (!(vl.mType->mType == DT_TYPE_POINTER || vl.mType->IsNumericType()))
+ mErrors->Error(exp->mLocation, "Not a numeric or pointer type");
+
+ if (vl.mType->IsIntegerType() && vr.mType->mType == DT_TYPE_FLOAT)
+ {
+ InterInstruction cins;
+ cins.code = IC_CONVERSION_OPERATOR;
+ cins.oper = IA_INT2FLOAT;
+ cins.stype[0] = InterTypeOf(vl.mType);
+ cins.stemp[0] = vl.mTemp;
+ cins.ttype = IT_FLOAT;
+ cins.ttemp = proc->AddTemporary(cins.ttype);
+ vl.mTemp = cins.ttemp;
+ vl.mType = TheFloatTypeDeclaration;
+ block->Append(cins);
+ }
+ else if (vl.mType->mType == DT_TYPE_FLOAT && vr.mType->IsIntegerType())
+ {
+ InterInstruction cins;
+ cins.code = IC_CONVERSION_OPERATOR;
+ cins.oper = IA_INT2FLOAT;
+ cins.stype[0] = InterTypeOf(vr.mType);
+ cins.stemp[0] = vr.mTemp;
+ cins.ttype = IT_FLOAT;
+ cins.ttemp = proc->AddTemporary(cins.ttype);
+ vr.mTemp = cins.ttemp;
+ vr.mType = TheFloatTypeDeclaration;
+ block->Append(cins);
+ }
+
+ ins.code = IC_RELATIONAL_OPERATOR;
+ switch (exp->mToken)
+ {
+ case TK_EQUAL:
+ ins.oper = IA_CMPEQ;
+ break;
+ case TK_NOT_EQUAL:
+ ins.oper = IA_CMPNE;
+ break;
+ case TK_GREATER_THAN:
+ ins.oper = signedCompare ? IA_CMPGS : IA_CMPGU;
+ break;
+ case TK_GREATER_EQUAL:
+ ins.oper = signedCompare ? IA_CMPGES : IA_CMPGEU;
+ break;
+ case TK_LESS_THAN:
+ ins.oper = signedCompare ? IA_CMPLS : IA_CMPLU;
+ break;
+ case TK_LESS_EQUAL:
+ ins.oper = signedCompare ? IA_CMPLES : IA_CMPLEU;
+ break;
+ }
+ ins.stype[0] = InterTypeOf(vr.mType);;
+ ins.stemp[0] = vr.mTemp;
+ ins.stype[1] = InterTypeOf(vl.mType);;
+ ins.stemp[1] = vl.mTemp;
+ ins.ttype = IT_BOOL;
+ ins.ttemp = proc->AddTemporary(ins.ttype);
+
+ block->Append(ins);
+
+ return ExValue(TheBoolTypeDeclaration, ins.ttemp);
+ }
+
+ case EX_CALL:
+ {
+ if (exp->mLeft->mType == EX_CONSTANT && exp->mLeft->mDecValue->mType == DT_CONST_FUNCTION && (exp->mLeft->mDecValue->mFlags & DTF_INTRINSIC))
+ {
+ Declaration* decf = exp->mLeft->mDecValue;
+ const Ident * iname = decf->mIdent;
+
+ if (!strcmp(iname->mString, "fabs"))
+ {
+ vr = TranslateExpression(procType, proc, block, exp->mRight, breakBlock, continueBlock);
+ vr = Dereference(proc, block, vr);
+
+ if (decf->mBase->mParams->CanAssign(vr.mType))
+ mErrors->Error(exp->mLocation, "Cannot assign incompatible types");
+ vr = CoerceType(proc, block, vr, decf->mBase->mParams);
+
+ InterInstruction ins;
+ ins.code = IC_UNARY_OPERATOR;
+ ins.oper = IA_ABS;
+ ins.stype[0] = IT_FLOAT;
+ ins.stemp[0] = vr.mTemp;
+ ins.ttype = IT_FLOAT;
+ ins.ttemp = proc->AddTemporary(ins.ttype);
+ block->Append(ins);
+
+ return ExValue(TheFloatTypeDeclaration, ins.ttemp);
+ }
+ else if (!strcmp(iname->mString, "floor"))
+ {
+ vr = TranslateExpression(procType, proc, block, exp->mRight, breakBlock, continueBlock);
+ vr = Dereference(proc, block, vr);
+
+ if (decf->mBase->mParams->CanAssign(vr.mType))
+ mErrors->Error(exp->mLocation, "Cannot assign incompatible types");
+ vr = CoerceType(proc, block, vr, decf->mBase->mParams);
+
+ InterInstruction ins;
+ ins.code = IC_UNARY_OPERATOR;
+ ins.oper = IA_FLOOR;
+ ins.stype[0] = IT_FLOAT;
+ ins.stemp[0] = vr.mTemp;
+ ins.ttype = IT_FLOAT;
+ ins.ttemp = proc->AddTemporary(ins.ttype);
+ block->Append(ins);
+
+ return ExValue(TheFloatTypeDeclaration, ins.ttemp);
+ }
+ else if (!strcmp(iname->mString, "ceil"))
+ {
+ vr = TranslateExpression(procType, proc, block, exp->mRight, breakBlock, continueBlock);
+ vr = Dereference(proc, block, vr);
+
+ if (decf->mBase->mParams->CanAssign(vr.mType))
+ mErrors->Error(exp->mLocation, "Cannot assign incompatible types");
+ vr = CoerceType(proc, block, vr, decf->mBase->mParams);
+
+ InterInstruction ins;
+ ins.code = IC_UNARY_OPERATOR;
+ ins.oper = IA_CEIL;
+ ins.stype[0] = IT_FLOAT;
+ ins.stemp[0] = vr.mTemp;
+ ins.ttype = IT_FLOAT;
+ ins.ttemp = proc->AddTemporary(ins.ttype);
+ block->Append(ins);
+
+ return ExValue(TheFloatTypeDeclaration, ins.ttemp);
+ }
+ else
+ mErrors->Error(exp->mLeft->mDecValue->mLocation, "Unknown intrinsic function", iname->mString);
+
+ return ExValue(TheVoidTypeDeclaration);
+ }
+ else
+ {
+ vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock);
+ vl = Dereference(proc, block, vl);
+
+ int atotal = 0;
+
+ int findex = block->code.Size();
+ InterCodeBasicBlock* fblock = block;
+
+ InterInstruction fins;
+ fins.code = IC_PUSH_FRAME;
+ fins.ivalue = atotal;
+ block->Append(fins);
+
+ Declaration * ftype = vl.mType;
+ if (ftype->mType == DT_TYPE_POINTER)
+ ftype = ftype->mBase;
+
+ Declaration* pdec = ftype->mParams;
+ Expression* pex = exp->mRight;
+ while (pex)
+ {
+ InterInstruction ains;
+ ains.code = IC_CONSTANT;
+ ains.ttype = IT_POINTER;
+ ains.ttemp = proc->AddTemporary(ains.ttype);
+ ains.mem = IM_FRAME;
+ if (pdec)
+ {
+ ains.vindex = pdec->mVarIndex;
+ ains.ivalue = pdec->mOffset;
+ ains.opsize = pdec->mSize;
+ }
+ else if (ftype->mFlags & DTF_VARIADIC)
+ {
+ ains.vindex = atotal;
+ ains.ivalue = 0;
+ ains.opsize = 2;
+ }
+ else
+ {
+ mErrors->Error(pex->mLocation, "Too many arguments for function call");
+ }
+ block->Append(ains);
+
+ Expression* texp;
+
+ if (pex->mType == EX_LIST)
+ {
+ texp = pex->mLeft;
+ pex = pex->mRight;
+ }
+ else
+ {
+ texp = pex;
+ pex = nullptr;
+ }
+
+ vr = TranslateExpression(procType, proc, block, texp, breakBlock, continueBlock);
+
+ if (vr.mType->mType != DT_TYPE_ARRAY)
+ vr = Dereference(proc, block, vr);
+
+ if (pdec)
+ {
+ if (!pdec->mBase->CanAssign(vr.mType))
+ mErrors->Error(texp->mLocation, "Cannot assign incompatible types");
+ vr = CoerceType(proc, block, vr, pdec->mBase);
+ }
+
+ InterInstruction wins;
+ wins.code = IC_STORE;
+ wins.mem = IM_INDIRECT;
+ wins.stype[0] = InterTypeOf(vr.mType);;
+ wins.stemp[0] = vr.mTemp;
+ wins.stype[1] = IT_POINTER;
+ wins.stemp[1] = ains.ttemp;
+ if (pdec)
+ wins.opsize = pdec->mSize;
+ else if (vr.mType->mSize > 2 && vr.mType->mType != DT_TYPE_ARRAY)
+ wins.opsize = vr.mType->mSize;
+ else
+ wins.opsize = 2;
+
+ block->Append(wins);
+
+ atotal += wins.opsize;
+ if (pdec)
+ pdec = pdec->mNext;
+ }
+
+ if (pdec)
+ mErrors->Error(exp->mLocation, "Not enough arguments for function call");
+
+ InterInstruction cins;
+ cins.code = IC_CALL;
+ cins.stype[0] = IT_POINTER;
+ cins.stemp[0] = vl.mTemp;
+ if (ftype->mBase->mType != DT_TYPE_VOID)
+ {
+ cins.ttype = InterTypeOf(ftype->mBase);
+ cins.ttemp = proc->AddTemporary(cins.ttype);
+ }
+
+ block->Append(cins);
+
+ fblock->code[findex].ivalue = atotal;
+
+ InterInstruction xins;
+ xins.code = IC_POP_FRAME;
+ xins.ivalue = atotal;
+ block->Append(xins);
+
+ return ExValue(vl.mType->mBase, cins.ttemp);
+ }
+
+ }
+
+ case EX_ASSEMBLER:
+ {
+ int offset = 0, osize = 0;
+ Expression* cexp = exp;
+ while (cexp)
+ {
+ osize += AsmInsSize(cexp->mAsmInsType, cexp->mAsmInsMode);
+ cexp = cexp->mRight;
+ }
+
+ InterInstruction ins;
+ ins.code = IC_CONSTANT;
+ ins.ttype = IT_POINTER;
+ ins.ttemp = proc->AddTemporary(ins.ttype);
+ ins.opsize = osize;
+ ins.ivalue = 0;
+
+ InterVariable var;
+ var.mOffset = 0;
+ var.mSize = osize;
+ uint8* d = new uint8[osize];
+ var.mData = d;
+ var.mAssembler = true;
+
+
+ var.mIndex = proc->mModule->mGlobalVars.Size();
+ if (exp->mDecValue)
+ {
+ exp->mDecValue->mVarIndex = var.mIndex;
+ var.mIdent = exp->mDecValue->mIdent;
+ }
+ proc->mModule->mGlobalVars.Push(var);
+
+ GrowingArray references({ 0 });
+
+ cexp = exp;
+ while (cexp)
+ {
+ if (cexp->mAsmInsType != ASMIT_BYTE)
+ {
+ int opcode = AsmInsOpcodes[cexp->mAsmInsType][cexp->mAsmInsMode];
+ d[offset++] = opcode;
+ }
+
+ Declaration* aexp = nullptr;
+ if (cexp->mLeft)
+ aexp = cexp->mLeft->mDecValue;
+
+ switch (cexp->mAsmInsMode)
+ {
+ case ASMIM_IMPLIED:
+ break;
+ case ASMIM_IMMEDIATE:
+ case ASMIM_ZERO_PAGE:
+ case ASMIM_ZERO_PAGE_X:
+ case ASMIM_INDIRECT_X:
+ case ASMIM_INDIRECT_Y:
+ d[offset++] = aexp->mInteger;
+ break;
+ case ASMIM_ABSOLUTE:
+ case ASMIM_INDIRECT:
+ case ASMIM_ABSOLUTE_X:
+ case ASMIM_ABSOLUTE_Y:
+ if (aexp->mType == DT_CONST_INTEGER)
+ {
+ d[offset++] = cexp->mLeft->mDecValue->mInteger & 255;
+ d[offset++] = cexp->mLeft->mDecValue->mInteger >> 8;
+ }
+ else if (aexp->mType == DT_LABEL)
+ {
+ if (aexp->mBase->mVarIndex < 0)
+ {
+ InterCodeBasicBlock* bblock = nullptr;
+ TranslateExpression(procType, proc, bblock, aexp->mBase->mValue, breakBlock, continueBlock);
+ }
+
+ InterVariable::Reference ref;
+ ref.mFunction = false;
+ ref.mUpper = true;
+ ref.mLower = true;
+ ref.mAddr = offset;
+ ref.mIndex = aexp->mBase->mVarIndex;
+ ref.mOffset = aexp->mInteger;
+
+ references.Push(ref);
+
+ offset += 2;
+ }
+ else if (aexp->mType == DT_LABEL_REF)
+ {
+ if (aexp->mBase->mBase->mVarIndex < 0)
+ {
+ InterCodeBasicBlock* bblock = nullptr;
+ TranslateExpression(procType, proc, bblock, aexp->mBase->mBase->mValue, breakBlock, continueBlock);
+ }
+
+ InterVariable::Reference ref;
+ ref.mFunction = false;
+ ref.mUpper = true;
+ ref.mLower = true;
+ ref.mAddr = offset;
+ ref.mIndex = aexp->mBase->mBase->mVarIndex;
+ ref.mOffset = aexp->mOffset + aexp->mBase->mInteger;
+
+ references.Push(ref);
+
+ offset += 2;
+ }
+ else if (aexp->mType == DT_CONST_ASSEMBLER)
+ {
+ if (aexp->mVarIndex < 0)
+ {
+ InterCodeBasicBlock* bblock = nullptr;
+ TranslateExpression(procType, proc, bblock, aexp->mValue, breakBlock, continueBlock);
+ }
+
+ InterVariable::Reference ref;
+ ref.mFunction = false;
+ ref.mUpper = true;
+ ref.mLower = true;
+ ref.mAddr = offset;
+ ref.mIndex = aexp->mVarIndex;
+ ref.mOffset = 0;
+
+ references.Push(ref);
+
+ offset += 2;
+ }
+ else if (aexp->mType == DT_VARIABLE)
+ {
+ if (aexp->mFlags & DTF_GLOBAL)
+ {
+ InitGlobalVariable(proc->mModule, aexp);
+
+ InterVariable::Reference ref;
+ ref.mFunction = false;
+ ref.mUpper = true;
+ ref.mLower = true;
+ ref.mAddr = offset;
+ ref.mIndex = aexp->mVarIndex;
+ ref.mOffset = 0;
+
+ references.Push(ref);
+
+ offset += 2;
+ }
+ }
+ break;
+ case ASMIM_RELATIVE:
+ d[offset] = aexp->mInteger - offset - 1;
+ offset++;
+ break;
+ }
+
+ cexp = cexp->mRight;
+ }
+
+ assert(offset == osize);
+
+ InterVariable& ivar(proc->mModule->mGlobalVars[var.mIndex]);
+
+ ivar.mNumReferences = references.Size();
+ if (ivar.mNumReferences)
+ {
+ ivar.mReferences = new InterVariable::Reference[ivar.mNumReferences];
+ for (int i = 0; i < ivar.mNumReferences; i++)
+ ivar.mReferences[i] = references[i];
+ }
+
+ if (block)
+ {
+ ins.mem = IM_GLOBAL;
+ ins.vindex = var.mIndex;
+ block->Append(ins);
+
+ InterInstruction jins;
+ jins.code = IC_JSR;
+ jins.stype[0] = IT_POINTER;
+ jins.stemp[0] = ins.ttemp;
+
+ block->Append(jins);
+ }
+
+ return ExValue(TheVoidTypeDeclaration);
+ }
+
+ case EX_RETURN:
+ {
+ InterInstruction ins;
+ if (exp->mLeft)
+ {
+ vr = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock);
+ vr = Dereference(proc, block, vr);
+
+ if (!procType->mBase || procType->mBase->mType == DT_TYPE_VOID)
+ mErrors->Error(exp->mLocation, "Function has void return type");
+ else if (!procType->mBase->CanAssign(vr.mType))
+ mErrors->Error(exp->mLocation, "Cannot return incompatible type");
+
+ ins.stype[0] = InterTypeOf(vr.mType);
+ ins.stemp[0] = vr.mTemp;
+ ins.code = IC_RETURN_VALUE;
+ }
+ else
+ {
+ if (procType->mBase && procType->mBase->mType != DT_TYPE_VOID)
+ mErrors->Error(exp->mLocation, "Function has non void return type");
+
+ ins.code = IC_RETURN;
+ }
+
+ block->Append(ins);
+ block->Close(nullptr, nullptr);
+ block = new InterCodeBasicBlock();
+ proc->Append(block);
+
+ return ExValue(TheVoidTypeDeclaration);
+ }
+
+ case EX_BREAK:
+ {
+ if (breakBlock)
+ {
+ InterInstruction jins;
+ jins.code = IC_JUMP;
+ block->Append(jins);
+
+ block->Close(breakBlock, nullptr);
+ block = new InterCodeBasicBlock();
+ proc->Append(block);
+ }
+ else
+ mErrors->Error(exp->mLocation, "No break target");
+
+ return ExValue(TheVoidTypeDeclaration);
+ }
+
+ case EX_CONTINUE:
+ {
+ if (continueBlock)
+ {
+ InterInstruction jins;
+ jins.code = IC_JUMP;
+ block->Append(jins);
+
+ block->Close(continueBlock, nullptr);
+ block = new InterCodeBasicBlock();
+ proc->Append(block);
+ }
+ else
+ mErrors->Error(exp->mLocation, "No continue target");
+
+ return ExValue(TheVoidTypeDeclaration);
+ }
+
+ case EX_LOGICAL_NOT:
+ {
+ vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock);
+ vl = Dereference(proc, block, vl);
+
+ InterInstruction zins;
+ zins.code = IC_CONSTANT;
+ zins.ttype = InterTypeOf(vr.mType);
+ zins.ttemp = proc->AddTemporary(zins.ttype);
+ zins.ivalue = 0;
+ block->Append(zins);
+
+ InterInstruction ins;
+ ins.code = IC_RELATIONAL_OPERATOR;
+ ins.oper = IA_CMPNE;
+ ins.stype[0] = InterTypeOf(vr.mType);
+ ins.stemp[0] = zins.ttemp;
+ ins.stype[1] = InterTypeOf(vr.mType);
+ ins.stemp[1] = vl.mTemp;
+ ins.ttype = IT_BOOL;
+ ins.ttemp = proc->AddTemporary(ins.ttype);
+ block->Append(ins);
+
+ return ExValue(TheBoolTypeDeclaration, ins.ttemp);
+ }
+
+ case EX_CONDITIONAL:
+ {
+ InterInstruction jins;
+ jins.code = IC_JUMP;
+
+ InterCodeBasicBlock* tblock = new InterCodeBasicBlock();
+ proc->Append(tblock);
+ InterCodeBasicBlock* fblock = new InterCodeBasicBlock();
+ proc->Append(fblock);
+ InterCodeBasicBlock* eblock = new InterCodeBasicBlock();
+ proc->Append(eblock);
+
+ TranslateLogic(procType, proc, block, tblock, fblock, exp->mLeft);
+
+ vl = TranslateExpression(procType, proc, tblock, exp->mRight->mLeft, breakBlock, continueBlock);
+ vl = Dereference(proc, tblock, vl);
+
+ vr = TranslateExpression(procType, proc, fblock, exp->mRight->mRight, breakBlock, continueBlock);
+ vr = Dereference(proc, fblock, vr);
+
+ int ttemp;
+ InterType ttype;
+ Declaration* dtype;
+ if (vl.mType->mType == DT_TYPE_FLOAT || vr.mType->mType == DT_TYPE_FLOAT)
+ {
+ ttype = IT_FLOAT;
+ dtype = TheFloatTypeDeclaration;
+ }
+ else if (vl.mType->IsIntegerType() && vr.mType->IsIntegerType())
+ {
+ ttype = ((vl.mType->mFlags & DTF_SIGNED) && (vr.mType->mFlags & DTF_SIGNED)) ? IT_SIGNED : IT_UNSIGNED;
+ dtype = vl.mType;
+ }
+ else if (vl.mType->mType == DT_TYPE_POINTER && vl.mType->IsSame(vr.mType))
+ {
+ ttype = IT_POINTER;
+ dtype = vl.mType;
+ }
+ else
+ {
+ mErrors->Error(exp->mLocation, "Incompatible conditional types");
+ ttype = IT_SIGNED;
+ dtype = TheVoidTypeDeclaration;
+ }
+ ttemp = proc->AddTemporary(ttype);
+
+ if (ttype == IT_FLOAT && vr.mType->IsIntegerType())
+ {
+ InterInstruction ins;
+ ins.code = IC_CONVERSION_OPERATOR;
+ ins.oper = IA_INT2FLOAT;
+ ins.stype[0] = InterTypeOf(vr.mType);
+ ins.stemp[0] = vr.mTemp;
+ ins.ttype = ttype;
+ ins.ttemp = ttemp;
+ fblock->Append(ins);
+ }
+ else
+ {
+ InterInstruction ins;
+ ins.code = IC_LOAD_TEMPORARY;
+ ins.stype[0] = InterTypeOf(vr.mType);
+ ins.stemp[0] = vr.mTemp;
+ ins.ttype = ttype;
+ ins.ttemp = ttemp;
+ fblock->Append(ins);
+ }
+
+ if (ttype == IT_FLOAT && vl.mType->IsIntegerType())
+ {
+ InterInstruction ins;
+ ins.code = IC_CONVERSION_OPERATOR;
+ ins.oper = IA_INT2FLOAT;
+ ins.stype[0] = InterTypeOf(vl.mType);
+ ins.stemp[0] = vl.mTemp;
+ ins.ttype = ttype;
+ ins.ttemp = ttemp;
+ tblock->Append(ins);
+ }
+ else
+ {
+ InterInstruction ins;
+ ins.code = IC_LOAD_TEMPORARY;
+ ins.stype[0] = InterTypeOf(vl.mType);
+ ins.stemp[0] = vl.mTemp;
+ ins.ttype = ttype;
+ ins.ttemp = ttemp;
+ tblock->Append(ins);
+ }
+
+ tblock->Append(jins);
+ tblock->Close(eblock, nullptr);
+
+ fblock->Append(jins);
+ fblock->Close(eblock, nullptr);
+
+ block = eblock;
+
+ return ExValue(dtype, ttemp);
+
+ break;
+ }
+
+ case EX_TYPECAST:
+ {
+ vr = TranslateExpression(procType, proc, block, exp->mRight, breakBlock, continueBlock);
+
+ InterInstruction ins;
+
+ if (exp->mLeft->mDecType->mType == DT_TYPE_FLOAT && vr.mType->IsIntegerType())
+ {
+ vr = Dereference(proc, block, vr);
+ ins.code = IC_CONVERSION_OPERATOR;
+ ins.oper = IA_INT2FLOAT;
+ ins.stype[0] = InterTypeOf(vr.mType);
+ ins.stemp[0] = vr.mTemp;
+ ins.ttype = InterTypeOf(exp->mLeft->mDecType);
+ ins.ttemp = proc->AddTemporary(ins.ttype);
+ block->Append(ins);
+ }
+ else if (exp->mLeft->mDecType->IsIntegerType() && vr.mType->mType == DT_TYPE_FLOAT)
+ {
+ vr = Dereference(proc, block, vr);
+ ins.code = IC_CONVERSION_OPERATOR;
+ ins.oper = IA_FLOAT2INT;
+ ins.stype[0] = InterTypeOf(vr.mType);
+ ins.stemp[0] = vr.mTemp;
+ ins.ttype = InterTypeOf(exp->mLeft->mDecType);
+ ins.ttemp = proc->AddTemporary(ins.ttype);
+ block->Append(ins);
+ }
+ else if (exp->mLeft->mDecType->mType == DT_TYPE_POINTER && vr.mType->mType == DT_TYPE_POINTER)
+ {
+ // no need for actual operation when casting pointer to pointer
+ return ExValue(exp->mLeft->mDecType, vr.mTemp, vr.mReference);
+ }
+ else
+ {
+ vr = Dereference(proc, block, vr);
+ ins.code = IC_TYPECAST;
+ ins.stype[0] = InterTypeOf(vr.mType);
+ ins.stemp[0] = vr.mTemp;
+ ins.ttype = InterTypeOf(exp->mLeft->mDecType);
+ ins.ttemp = proc->AddTemporary(ins.ttype);
+ block->Append(ins);
+ }
+
+ return ExValue(exp->mLeft->mDecType, ins.ttemp);
+ }
+ break;
+
+ case EX_LOGICAL_AND:
+ {
+
+ }
+ case EX_WHILE:
+ {
+ InterInstruction jins;
+ jins.code = IC_JUMP;
+
+ InterCodeBasicBlock* cblock = new InterCodeBasicBlock();
+ InterCodeBasicBlock* lblock = cblock;
+ proc->Append(cblock);
+ InterCodeBasicBlock* bblock = new InterCodeBasicBlock();
+ proc->Append(bblock);
+ InterCodeBasicBlock* eblock = new InterCodeBasicBlock();
+ proc->Append(eblock);
+
+ block->Append(jins);
+ block->Close(cblock, nullptr);
+
+ TranslateLogic(procType, proc, cblock, bblock, eblock, exp->mLeft);
+
+ vr = TranslateExpression(procType, proc, bblock, exp->mRight, eblock, lblock);
+ bblock->Append(jins);
+ bblock->Close(lblock, nullptr);
+
+ block = eblock;
+
+ return ExValue(TheVoidTypeDeclaration);
+ }
+
+ case EX_IF:
+ {
+ InterInstruction jins;
+ jins.code = IC_JUMP;
+
+ InterCodeBasicBlock* tblock = new InterCodeBasicBlock();
+ proc->Append(tblock);
+ InterCodeBasicBlock* fblock = new InterCodeBasicBlock();
+ proc->Append(fblock);
+ InterCodeBasicBlock* eblock = new InterCodeBasicBlock();
+ proc->Append(eblock);
+
+ TranslateLogic(procType, proc, block, tblock, fblock, exp->mLeft);
+
+ vr = TranslateExpression(procType, proc, tblock, exp->mRight->mLeft, breakBlock, continueBlock);
+ tblock->Append(jins);
+ tblock->Close(eblock, nullptr);
+
+ if (exp->mRight->mRight)
+ vr = TranslateExpression(procType, proc, fblock, exp->mRight->mRight, breakBlock, continueBlock);
+ fblock->Append(jins);
+ fblock->Close(eblock, nullptr);
+
+ block = eblock;
+
+ return ExValue(TheVoidTypeDeclaration);
+ }
+
+ case EX_FOR:
+ {
+ // assignment
+ if (exp->mLeft->mRight)
+ TranslateExpression(procType, proc, block, exp->mLeft->mRight, breakBlock, continueBlock);
+
+ InterInstruction jins;
+ jins.code = IC_JUMP;
+
+ InterCodeBasicBlock* cblock = new InterCodeBasicBlock();
+ InterCodeBasicBlock* lblock = cblock;
+ proc->Append(cblock);
+ InterCodeBasicBlock* bblock = new InterCodeBasicBlock();
+ proc->Append(bblock);
+ InterCodeBasicBlock* iblock = new InterCodeBasicBlock();
+ proc->Append(iblock);
+ InterCodeBasicBlock* eblock = new InterCodeBasicBlock();
+ proc->Append(eblock);
+
+ block->Append(jins);
+ block->Close(cblock, nullptr);
+
+ // condition
+ if (exp->mLeft->mLeft->mLeft)
+ TranslateLogic(procType, proc, cblock, bblock, eblock, exp->mLeft->mLeft->mLeft);
+ else
+ {
+ cblock->Append(jins);
+ cblock->Close(bblock, nullptr);
+ }
+
+ vr = TranslateExpression(procType, proc, bblock, exp->mRight, eblock, iblock);
+
+ bblock->Append(jins);
+ bblock->Close(iblock, nullptr);
+
+ // increment
+ if (exp->mLeft->mLeft->mRight)
+ TranslateExpression(procType, proc, iblock, exp->mLeft->mLeft->mRight, breakBlock, continueBlock);
+
+ iblock->Append(jins);
+ iblock->Close(lblock, nullptr);
+
+ block = eblock;
+
+ return ExValue(TheVoidTypeDeclaration);
+ }
+
+ case EX_DO:
+ {
+ InterInstruction jins;
+ jins.code = IC_JUMP;
+
+ InterCodeBasicBlock* cblock = new InterCodeBasicBlock();
+ InterCodeBasicBlock* lblock = cblock;
+ proc->Append(cblock);
+ InterCodeBasicBlock* eblock = new InterCodeBasicBlock();
+ proc->Append(eblock);
+
+ block->Append(jins);
+ block->Close(cblock, nullptr);
+
+ vr = TranslateExpression(procType, proc, cblock, exp->mRight, eblock, cblock);
+
+ TranslateLogic(procType, proc, cblock, lblock, eblock, exp->mLeft);
+
+ block = eblock;
+
+ return ExValue(TheVoidTypeDeclaration);
+ }
+
+ case EX_SWITCH:
+ {
+ InterInstruction jins;
+ jins.code = IC_JUMP;
+
+ vl = TranslateExpression(procType, proc, block, exp->mLeft, breakBlock, continueBlock);
+ vl = Dereference(proc, block, vl);
+
+ InterCodeBasicBlock * dblock = nullptr;
+ InterCodeBasicBlock* sblock = block;
+
+ block = nullptr;
+
+ InterCodeBasicBlock* eblock = new InterCodeBasicBlock();
+ proc->Append(eblock);
+
+ Expression* sexp = exp->mRight;
+ while (sexp)
+ {
+ Expression* cexp = sexp->mLeft;
+ if (cexp->mType == EX_CASE)
+ {
+ InterCodeBasicBlock* cblock = new InterCodeBasicBlock();
+ proc->Append(cblock);
+
+ InterCodeBasicBlock* nblock = new InterCodeBasicBlock();
+ proc->Append(nblock);
+
+ vr = TranslateExpression(procType, proc, sblock, cexp->mLeft, breakBlock, continueBlock);
+ vr = Dereference(proc, sblock, vr);
+
+ InterInstruction cins;
+ cins.code = IC_RELATIONAL_OPERATOR;
+ cins.oper = IA_CMPEQ;
+ cins.stype[0] = InterTypeOf(vr.mType);;
+ cins.stemp[0] = vr.mTemp;
+ cins.stype[1] = InterTypeOf(vl.mType);;
+ cins.stemp[1] = vl.mTemp;
+ cins.ttype = IT_BOOL;
+ cins.ttemp = proc->AddTemporary(cins.ttype);
+
+ sblock->Append(cins);
+
+ InterInstruction bins;
+ bins.code = IC_BRANCH;
+ bins.stype[0] = IT_BOOL;
+ bins.stemp[0] = cins.ttemp;
+ sblock->Append(bins);
+
+ sblock->Close(nblock, cblock);
+
+ if (block)
+ {
+ block->Append(jins);
+ block->Close(nblock, nullptr);
+ }
+
+ sblock = cblock;
+ block = nblock;
+ }
+ else if (cexp->mType == EX_DEFAULT)
+ {
+ if (!dblock)
+ {
+ dblock = new InterCodeBasicBlock();
+ proc->Append(dblock);
+
+ if (block)
+ {
+ block->Append(jins);
+ block->Close(dblock, nullptr);
+ }
+
+ block = dblock;
+ }
+ else
+ mErrors->Error(cexp->mLocation, "Duplicate default");
+ }
+
+ if (cexp->mRight)
+ TranslateExpression(procType, proc, block, cexp->mRight, eblock, continueBlock);
+
+ sexp = sexp->mRight;
+ }
+
+ sblock->Append(jins);
+ if (dblock)
+ sblock->Close(dblock, nullptr);
+ else
+ sblock->Close(eblock, nullptr);
+
+ if (block)
+ {
+ block->Append(jins);
+ block->Close(eblock, nullptr);
+ }
+
+ block = eblock;
+
+ return ExValue(TheVoidTypeDeclaration);
+ }
+ default:
+ mErrors->Error(exp->mLocation, "Unimplemented expression");
+ return ExValue(TheVoidTypeDeclaration);
+ }
+ }
+}
+
+void InterCodeGenerator::BuildInitializer(InterCodeModule * mod, uint8* dp, int offset, Declaration* data, GrowingArray& references)
+{
+ if (data->mType == DT_CONST_DATA)
+ {
+ memcpy(dp + offset, data->mData, data->mBase->mSize);
+ }
+ else if (data->mType == DT_CONST_STRUCT)
+ {
+ Declaration* mdec = data->mParams;
+ while (mdec)
+ {
+ BuildInitializer(mod, dp, offset + mdec->mOffset, mdec, references);
+ mdec = mdec->mNext;
+ }
+ }
+ else if (data->mType == DT_CONST_INTEGER)
+ {
+ __int64 t = data->mInteger;
+ for (int i = 0; i < data->mBase->mSize; i++)
+ {
+ dp[offset + i] = uint8(t & 0xff);
+ t >>= 8;
+ }
+ }
+ else if (data->mType == DT_CONST_ADDRESS)
+ {
+ __int64 t = data->mInteger;
+ dp[offset + 0] = uint8(t & 0xff);
+ dp[offset + 1] = t >> 8;
+ }
+ else if (data->mType == DT_CONST_FLOAT)
+ {
+ union { float f; uint32 i; } cast;
+ cast.f = data->mNumber;
+ __int64 t = cast.i;
+ for (int i = 0; i < 4; i++)
+ {
+ dp[i] = t & 0xff;
+ t >>= 8;
+ }
+ }
+ else if (data->mType == DT_CONST_POINTER)
+ {
+ Expression* exp = data->mValue;
+ Declaration* dec = exp->mDecValue;
+
+ InterVariable::Reference ref;
+ ref.mAddr = offset;
+ ref.mLower = true;
+ ref.mUpper = true;
+ switch (dec->mType)
+ {
+ case DT_CONST_DATA:
+ {
+ if (dec->mVarIndex < 0)
+ {
+ dec->mVarIndex = mod->mGlobalVars.Size();
+ InterVariable var;
+ var.mIndex = dec->mVarIndex;
+ var.mOffset = 0;
+ var.mSize = dec->mSize;
+ var.mData = dec->mData;
+ var.mIdent = dec->mIdent;
+ mod->mGlobalVars.Push(var);
+ }
+ ref.mFunction = false;
+ ref.mIndex = dec->mVarIndex;
+ ref.mOffset = 0;
+ references.Push(ref);
+ break;
+ }
+ }
+ }
+}
+
+void InterCodeGenerator::TranslateLogic(Declaration* procType, InterCodeProcedure* proc, InterCodeBasicBlock* block, InterCodeBasicBlock* tblock, InterCodeBasicBlock* fblock, Expression* exp)
+{
+ switch (exp->mType)
+ {
+ case EX_LOGICAL_NOT:
+ TranslateLogic(procType, proc, block, fblock, tblock, exp->mLeft);
+ break;
+ case EX_LOGICAL_AND:
+ {
+ InterCodeBasicBlock* ablock = new InterCodeBasicBlock();
+ proc->Append(ablock);
+ TranslateLogic(procType, proc, block, ablock, fblock, exp->mLeft);
+ TranslateLogic(procType, proc, ablock, tblock, fblock, exp->mRight);
+ break;
+ }
+ case EX_LOGICAL_OR:
+ {
+ InterCodeBasicBlock* oblock = new InterCodeBasicBlock();
+ proc->Append(oblock);
+ TranslateLogic(procType, proc, block, tblock, oblock, exp->mLeft);
+ TranslateLogic(procType, proc, oblock, tblock, fblock, exp->mRight);
+ break;
+ }
+ default:
+ {
+ ExValue vr = TranslateExpression(procType, proc, block, exp, nullptr, nullptr);
+ vr = Dereference(proc, block, vr);
+
+ InterInstruction ins;
+ ins.code = IC_BRANCH;
+ ins.stype[0] = IT_BOOL;
+ ins.stemp[0] = vr.mTemp;
+ block->Append(ins);
+
+ block->Close(tblock, fblock);
+ }
+
+ }
+}
+
+InterCodeProcedure* InterCodeGenerator::TranslateProcedure(InterCodeModule * mod, Expression* exp, Declaration * dec)
+{
+ InterCodeProcedure* proc = new InterCodeProcedure(mod, dec->mLocation, dec->mIdent);
+ dec->mVarIndex = proc->mID;
+
+ InterCodeBasicBlock* entryBlock = new InterCodeBasicBlock();
+
+ proc->Append(entryBlock);
+
+ InterCodeBasicBlock* exitBlock = entryBlock;
+
+ if (dec->mFlags & DTF_DEFINED)
+ TranslateExpression(dec->mBase, proc, exitBlock, exp, nullptr, nullptr);
+ else
+ mErrors->Error(dec->mLocation, "Calling undefined function", dec->mIdent->mString);
+
+ InterInstruction ins;
+ ins.code = IC_RETURN;
+ exitBlock->Append(ins);
+ exitBlock->Close(nullptr, nullptr);
+
+ _CrtCheckMemory();
+
+ proc->Close();
+
+ return proc;
+}
diff --git a/oscar64/InterCodeGenerator.h b/oscar64/InterCodeGenerator.h
new file mode 100644
index 0000000..dc9082a
--- /dev/null
+++ b/oscar64/InterCodeGenerator.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include "Parser.h"
+#include "InterCode.h"
+
+class InterCodeGenerator
+{
+public:
+ InterCodeGenerator(Errors * errors);
+ ~InterCodeGenerator(void);
+
+ struct ExValue
+ {
+ Declaration* mType;
+ int mTemp, mReference;
+
+ ExValue(Declaration* type = nullptr, int temp = -1, int reference = 0)
+ : mType(type), mTemp(temp), mReference(reference)
+ {}
+ };
+
+
+ InterCodeProcedure* TranslateProcedure(InterCodeModule* mod, Expression* exp, Declaration * dec);
+ void TranslateAssembler(InterCodeModule* mod, Expression * exp);
+protected:
+
+ Errors* mErrors;
+
+ ExValue Dereference(InterCodeProcedure* proc, InterCodeBasicBlock*& block, ExValue v, int level = 0);
+ ExValue CoerceType(InterCodeProcedure* proc, InterCodeBasicBlock*& block, ExValue v, Declaration * type);
+ ExValue TranslateExpression(Declaration * procType, InterCodeProcedure * proc, InterCodeBasicBlock*& block, Expression* exp, InterCodeBasicBlock* breakBlock, InterCodeBasicBlock* continueBlock);
+ void TranslateLogic(Declaration* procType, InterCodeProcedure* proc, InterCodeBasicBlock* block, InterCodeBasicBlock* tblock, InterCodeBasicBlock* fblock, Expression* exp);
+ void InitGlobalVariable(InterCodeModule* mod, Declaration* dec);
+
+ void BuildInitializer(InterCodeModule* mod, uint8 * dp, int offset, Declaration* data, GrowingArray & references);
+};
diff --git a/oscar64/MachineTypes.h b/oscar64/MachineTypes.h
new file mode 100644
index 0000000..13b1275
--- /dev/null
+++ b/oscar64/MachineTypes.h
@@ -0,0 +1,18 @@
+#pragma once
+
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+typedef unsigned int uint32;
+typedef signed char int8;
+typedef signed short int16;
+typedef signed short int32;
+
+static const uint8 BC_REG_IP = 0x19;
+static const uint8 BC_REG_ACCU = 0x1b;
+static const uint8 BC_REG_ADDR = 0x1f;
+static const uint8 BC_REG_STACK = 0x23;
+static const uint8 BC_REG_LOCALS = 0x25;
+
+static const uint8 BC_REG_TMP = 0x43;
+static const uint8 BC_REG_TMP_SAVED = 0x53;
+
diff --git a/oscar64/NumberSet.cpp b/oscar64/NumberSet.cpp
new file mode 100644
index 0000000..8a73256
--- /dev/null
+++ b/oscar64/NumberSet.cpp
@@ -0,0 +1,242 @@
+#include "NumberSet.h"
+
+NumberSet::NumberSet(void)
+{
+ size = 0;
+ dwsize = 0;
+ bits = 0;
+}
+
+NumberSet::NumberSet(int size, bool set)
+{
+ int i;
+
+ this->size = size;
+ dwsize = (size + 31) >> 5;
+
+ bits = new uint32[dwsize];
+
+ if (set)
+ {
+ for (i = 0; i < dwsize; i++)
+ bits[i] = 0xffffffff;
+ }
+ else
+ {
+ for (i = 0; i < dwsize; i++)
+ bits[i] = 0;
+ }
+}
+
+NumberSet::NumberSet(const NumberSet& set)
+{
+ int i;
+
+ this->size = set.size;
+ this->dwsize = set.dwsize;
+ this->bits = new uint32[dwsize];
+
+ for (i = 0; i < dwsize; i++)
+ bits[i] = set.bits[i];
+}
+
+NumberSet::~NumberSet(void)
+{
+ delete[] bits;
+}
+
+void NumberSet::Reset(int size, bool set)
+{
+ int i;
+
+ delete[] bits;
+
+ this->size = size;
+ dwsize = (size + 31) >> 5;
+
+ bits = new uint32[dwsize];
+
+ if (set)
+ {
+ for (i = 0; i < dwsize; i++)
+ bits[i] = 0xffffffff;
+ }
+ else
+ {
+ for (i = 0; i < dwsize; i++)
+ bits[i] = 0;
+ }
+}
+
+void NumberSet::Clear(void)
+{
+ int i;
+
+ for (i = 0; i < dwsize; i++)
+ bits[i] = 0;
+}
+
+NumberSet& NumberSet::operator=(const NumberSet& set)
+{
+ int i;
+
+ this->size = set.size;
+
+ if (dwsize != set.dwsize)
+ {
+ delete[] bits;
+ this->dwsize = set.dwsize;
+ this->bits = new uint32[dwsize];
+ }
+
+ for (i = 0; i < dwsize; i++)
+ bits[i] = set.bits[i];
+
+ return *this;
+}
+
+NumberSet& NumberSet::operator&=(const NumberSet& set)
+{
+ int i;
+
+ for (i = 0; i < dwsize; i++)
+ bits[i] &= set.bits[i];
+
+ return *this;
+}
+
+NumberSet& NumberSet::operator|=(const NumberSet& set)
+{
+ int i;
+
+ for (i = 0; i < dwsize; i++)
+ bits[i] |= set.bits[i];
+
+ return *this;
+}
+
+NumberSet& NumberSet::operator-=(const NumberSet& set)
+{
+ int i;
+
+ for (i = 0; i < dwsize; i++)
+ bits[i] &= ~set.bits[i];
+
+ return *this;
+}
+
+bool NumberSet::operator<=(const NumberSet& set)
+{
+ int i;
+
+ for (i = 0; i < dwsize; i++)
+ if (bits[i] & ~set.bits[i]) return false;
+
+ return true;
+}
+
+
+
+FastNumberSet::FastNumberSet(void)
+{
+ num = 0;
+ size = 0;
+ asize = 0;
+ buffer = nullptr;
+}
+
+FastNumberSet::FastNumberSet(int size, bool set)
+{
+ this->size = this->asize = size;
+ buffer = new uint32[2 * size];
+ if (set)
+ {
+ for (num = 0; num < size; num++)
+ {
+ buffer[num] = num;
+ buffer[num + size] = num;
+ }
+ }
+ else
+ num = 0;
+}
+
+FastNumberSet::FastNumberSet(const FastNumberSet& set)
+{
+ int i;
+
+ this->size = this->asize = set.size;
+ this->num = set.num;
+ buffer = new uint32[2 * size];
+ for (i = 0; i < num; i++)
+ {
+ buffer[i] = set.buffer[i];
+ buffer[size + buffer[i]] = i;
+ }
+}
+
+void FastNumberSet::Reset(int size, bool set)
+{
+ if (size > this->asize)
+ {
+ delete[] buffer;
+ buffer = new uint32[2 * size];
+
+ this->asize = size;
+ }
+
+ this->size = size;
+
+ if (set)
+ {
+ for (num = 0; num < size; num++)
+ {
+ buffer[num] = num;
+ buffer[num + size] = num;
+ }
+ }
+ else
+ num = 0;
+}
+
+
+FastNumberSet::~FastNumberSet(void)
+{
+ delete[] buffer;
+}
+
+FastNumberSet& FastNumberSet::operator=(const FastNumberSet& set)
+{
+ if (set.size > this->asize)
+ {
+ delete[] buffer;
+ buffer = new uint32[2 * set.size];
+
+ this->asize = set.size;
+ }
+
+ this->size = set.size;
+
+ for (num = 0; num < set.num; num++)
+ {
+ buffer[num] = set.buffer[num];
+ buffer[buffer[num] + size] = num;
+ }
+
+ return *this;
+}
+
+void FastNumberSet::Clear(void)
+{
+ num = 0;
+}
+
+int FastNumberSet::Index(int elem)
+{
+ uint32 dw = buffer[size + elem];
+
+ if (dw < num && buffer[dw] == elem)
+ return dw;
+ else
+ return -1;
+}
diff --git a/oscar64/NumberSet.h b/oscar64/NumberSet.h
new file mode 100644
index 0000000..bea31e6
--- /dev/null
+++ b/oscar64/NumberSet.h
@@ -0,0 +1,127 @@
+#pragma once
+
+typedef unsigned __int32 uint32;
+
+class NumberSet
+{
+protected:
+ uint32 * bits;
+ int size, dwsize;
+public:
+ NumberSet(void);
+ NumberSet(int size, bool set = false);
+ NumberSet(const NumberSet& set);
+ ~NumberSet(void);
+
+ void Reset(int size, bool set = false);
+
+ NumberSet& operator+=(int elem);
+ NumberSet& operator-=(int elem);
+
+ bool operator[](int elem) const;
+
+ NumberSet& operator=(const NumberSet& set);
+
+ NumberSet& operator&=(const NumberSet& set);
+ NumberSet& operator|=(const NumberSet& set);
+ NumberSet& operator-=(const NumberSet& set);
+
+ bool operator<=(const NumberSet& set);
+
+ void Clear(void);
+
+ int Size(void) { return size; }
+};
+
+__forceinline NumberSet& NumberSet::operator+=(int elem)
+{
+ bits[elem >> 5] |= (1UL << (elem & 31));
+
+ return *this;
+}
+
+__forceinline NumberSet& NumberSet::operator-=(int elem)
+{
+ bits[elem >> 5] &= ~(1UL << (elem & 31));
+
+ return *this;
+}
+
+__forceinline bool NumberSet::operator[](int elem) const
+{
+ return (bits[elem >> 5] & (1UL << (elem & 31))) != 0;
+}
+
+
+class FastNumberSet
+{
+protected:
+ uint32 * buffer;
+ int size, num, asize;
+public:
+ FastNumberSet(void);
+ FastNumberSet(int size, bool set = false);
+ FastNumberSet(const FastNumberSet& set);
+ ~FastNumberSet(void);
+
+ void Reset(int size, bool set = false);
+
+ FastNumberSet& operator+=(int elem);
+ FastNumberSet& operator-=(int elem);
+
+ bool operator[](int elem);
+
+ FastNumberSet& operator=(const FastNumberSet& set);
+
+ bool Empty(void) { return !num; }
+ void Clear(void);
+
+ int Num(void) { return num; }
+ int Element(int i);
+
+ int Size(void) { return size; }
+ int Index(int elem);
+};
+
+__forceinline bool FastNumberSet::operator[](int elem)
+{
+ uint32 dw = buffer[size + elem];
+
+ return (dw < num&& buffer[dw] == elem);
+}
+
+__forceinline FastNumberSet& FastNumberSet::operator+=(int elem)
+{
+ uint32 dw = buffer[size + elem];
+
+ if (dw >= num || buffer[dw] != elem)
+ {
+ buffer[num] = elem;
+ buffer[size + elem] = num;
+ num++;
+ }
+
+ return *this;
+}
+
+__forceinline FastNumberSet& FastNumberSet::operator-=(int elem)
+{
+ uint32 dw = buffer[size + elem];
+
+ if (dw < num && buffer[dw] == elem)
+ {
+ num--;
+ buffer[dw] = buffer[num];
+ buffer[size + buffer[dw]] = dw;
+ }
+
+ return *this;
+}
+
+__forceinline int FastNumberSet::Element(int i)
+{
+ if (i < num)
+ return buffer[i];
+ else
+ return -1;
+}
diff --git a/oscar64/Parser.cpp b/oscar64/Parser.cpp
new file mode 100644
index 0000000..bd0ded3
--- /dev/null
+++ b/oscar64/Parser.cpp
@@ -0,0 +1,2209 @@
+#include "Parser.h"
+#include
+#include "Assembler.h"
+#include "MachineTypes.h"
+
+Parser::Parser(Errors* errors, Scanner* scanner, CompilationUnits* compilationUnits)
+ : mErrors(errors), mScanner(scanner), mCompilationUnits(compilationUnits)
+{
+ mGlobals = new DeclarationScope(compilationUnits->mScope);
+ mScope = mGlobals;
+}
+
+Parser::~Parser(void)
+{
+
+}
+
+Declaration* Parser::ParseBaseTypeDeclaration(uint32 flags)
+{
+ Declaration* dec = nullptr;
+
+ switch (mScanner->mToken)
+ {
+ case TK_UNSIGNED:
+ dec = new Declaration(mScanner->mLocation, DT_TYPE_INTEGER);
+ dec->mFlags = flags | DTF_DEFINED;
+ mScanner->NextToken();
+ if (mScanner->mToken == TK_INT || mScanner->mToken == TK_SHORT)
+ {
+ dec->mSize = 2;
+ mScanner->NextToken();
+ }
+ else if (mScanner->mToken == TK_LONG)
+ {
+ dec->mSize = 4;
+ mScanner->NextToken();
+ }
+ else if (mScanner->mToken == TK_CHAR)
+ {
+ dec->mSize = 1;
+ mScanner->NextToken();
+ }
+ break;
+
+ break;
+
+ case TK_CONST:
+ mScanner->NextToken();
+ return ParseBaseTypeDeclaration(flags | DTF_CONST);
+
+ case TK_VOLATILE:
+ mScanner->NextToken();
+ return ParseBaseTypeDeclaration(flags | DTF_VOLATILE);
+
+ case TK_LONG:
+ dec = new Declaration(mScanner->mLocation, DT_TYPE_INTEGER);
+ dec->mSize = 4;
+ dec->mFlags = flags | DTF_DEFINED | DTF_SIGNED;
+ mScanner->NextToken();
+ break;
+
+ case TK_SHORT:
+ case TK_INT:
+ dec = new Declaration(mScanner->mLocation, DT_TYPE_INTEGER);
+ dec->mSize = 2;
+ dec->mFlags = flags | DTF_DEFINED | DTF_SIGNED;
+ mScanner->NextToken();
+ break;
+
+ case TK_CHAR:
+ dec = new Declaration(mScanner->mLocation, DT_TYPE_INTEGER);
+ dec->mSize = 1;
+ dec->mFlags = flags | DTF_DEFINED | DTF_SIGNED;
+ mScanner->NextToken();
+ break;
+
+ case TK_BOOL:
+ dec = new Declaration(mScanner->mLocation, DT_TYPE_BOOL);
+ dec->mSize = 1;
+ dec->mFlags = flags | DTF_DEFINED | DTF_SIGNED;
+ mScanner->NextToken();
+ break;
+
+ case TK_FLOAT:
+ dec = new Declaration(mScanner->mLocation, DT_TYPE_FLOAT);
+ dec->mSize = 4;
+ dec->mFlags = flags | DTF_DEFINED | DTF_SIGNED;
+ mScanner->NextToken();
+ break;
+
+ case TK_VOID:
+ dec = new Declaration(mScanner->mLocation, DT_TYPE_VOID);
+ dec->mSize = 0;
+ dec->mFlags = flags | DTF_DEFINED;
+ mScanner->NextToken();
+ break;
+
+ case TK_IDENT:
+ dec = mScope->Lookup(mScanner->mTokenIdent);
+ if (dec && dec->mType <= DT_TYPE_FUNCTION)
+ mScanner->NextToken();
+ else if (!dec)
+ {
+ mErrors->Error(mScanner->mLocation, "Identifier not defined", mScanner->mTokenIdent->mString);
+ mScanner->NextToken();
+ }
+ else
+ {
+ mErrors->Error(mScanner->mLocation, "Identifier is no type", mScanner->mTokenIdent->mString);
+ mScanner->NextToken();
+ }
+ break;
+
+ case TK_ENUM:
+ {
+ dec = new Declaration(mScanner->mLocation, DT_TYPE_ENUM);
+ dec->mFlags = flags | DTF_SIGNED;
+ dec->mSize = 2;
+
+ mScanner->NextToken();
+ if (mScanner->mToken == TK_IDENT)
+ {
+ dec->mIdent = mScanner->mTokenIdent;
+
+ if (mScope->Insert(dec->mIdent, dec))
+ mErrors->Error(dec->mLocation, "Duplicate name");
+ mScanner->NextToken();
+ }
+
+ int nitem = 0;
+ if (mScanner->mToken == TK_OPEN_BRACE)
+ {
+ mScanner->NextToken();
+ if (mScanner->mToken == TK_IDENT)
+ {
+ for (;;)
+ {
+ Declaration* cdec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
+ cdec->mBase = dec;
+ cdec->mSize = 2;
+ if (mScanner->mToken == TK_IDENT)
+ {
+ cdec->mIdent = mScanner->mTokenIdent;
+ if (mScope->Insert(cdec->mIdent, cdec) != nullptr)
+ mErrors->Error(mScanner->mLocation, "Duplicate declaration", mScanner->mTokenIdent->mString);
+ mScanner->NextToken();
+ }
+ if (mScanner->mToken == TK_ASSIGN)
+ {
+ mScanner->NextToken();
+ Expression* exp = ParseRExpression();
+ if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_INTEGER)
+ nitem = exp->mDecValue->mInteger;
+ else
+ mErrors->Error(mScanner->mLocation, "Integer constant expected");
+ }
+ cdec->mInteger = nitem++;
+
+ if (mScanner->mToken == TK_COMMA)
+ mScanner->NextToken();
+ else
+ break;
+ }
+ }
+
+ if (mScanner->mToken == TK_CLOSE_BRACE)
+ mScanner->NextToken();
+ else
+ mErrors->Error(mScanner->mLocation, "'}' expected");
+ }
+ else
+ mErrors->Error(mScanner->mLocation, "'{' expected");
+
+ dec->mFlags |= DTF_DEFINED;
+ break;
+ }
+ case TK_STRUCT:
+ {
+ const Ident* structName = nullptr;
+
+ dec = new Declaration(mScanner->mLocation, DT_TYPE_STRUCT);
+
+ mScanner->NextToken();
+ if (mScanner->mToken == TK_IDENT)
+ {
+ structName = mScanner->mTokenIdent;
+ mScanner->NextToken();
+ Declaration * pdec = mScope->Insert(structName, dec);
+ if (pdec)
+ {
+ if (pdec->mType == DT_TYPE_STRUCT && (pdec->mFlags & DTF_DEFINED))
+ {
+ dec = pdec;
+ }
+ else
+ {
+ mErrors->Error(mScanner->mLocation, "Error duplicate struct declaration", structName->mString);
+ }
+ }
+ }
+
+ dec->mIdent = structName;
+ dec->mScope = new DeclarationScope(nullptr);
+
+ if (mScanner->mToken == TK_OPEN_BRACE)
+ {
+ mScanner->NextToken();
+ Declaration* mlast = nullptr;
+ for (;;)
+ {
+ Declaration* mdec = ParseDeclaration(false);
+ while (mdec)
+ {
+ if (!(mdec->mBase->mFlags & DTF_DEFINED))
+ mErrors->Error(mdec->mLocation, "Undefined type used in struct member declaration");
+ mdec->mType = DT_ELEMENT;
+ mdec->mOffset = dec->mSize;
+ dec->mSize += mdec->mBase->mSize;
+ dec->mScope->Insert(mdec->mIdent, mdec);
+ if (mlast)
+ mlast->mNext = mdec;
+ else
+ dec->mParams = mdec;
+ mlast = mdec;
+ mdec = mdec->mNext;
+ }
+
+ if (mScanner->mToken == TK_SEMICOLON)
+ mScanner->NextToken();
+ else
+ {
+ mErrors->Error(mScanner->mLocation, "';' expected");
+ break;
+ }
+
+ if (mScanner->mToken == TK_CLOSE_BRACE)
+ {
+ mScanner->NextToken();
+ break;
+ }
+ }
+
+ if (mlast)
+ mlast->mNext = nullptr;
+ else
+ dec->mParams = nullptr;
+
+ dec->mFlags |= DTF_DEFINED;
+ }
+ break;
+ }
+
+ default:
+ mErrors->Error(mScanner->mLocation, "Declaration starts with invalid token", TokenNames[mScanner->mToken]);
+ mScanner->NextToken();
+ }
+
+ if (!dec)
+ {
+ dec = new Declaration(mScanner->mLocation, DT_TYPE_VOID);
+ dec->mSize = 0;
+ dec->mFlags |= DTF_DEFINED;
+ }
+
+ return dec;
+
+}
+
+Declaration* Parser::ParsePostfixDeclaration(void)
+{
+ Declaration* dec;
+
+ if (mScanner->mToken == TK_MUL)
+ {
+ mScanner->NextToken();
+ Declaration* dec = ParsePostfixDeclaration();
+ Declaration* ndec = new Declaration(mScanner->mLocation, DT_TYPE_POINTER);
+ ndec->mBase = dec;
+ ndec->mSize = 2;
+ ndec->mFlags |= DTF_DEFINED;
+ return ndec;
+ }
+ else if (mScanner->mToken == TK_OPEN_PARENTHESIS)
+ {
+ mScanner->NextToken();
+ Declaration* vdec = ParsePostfixDeclaration();
+ if (mScanner->mToken == TK_CLOSE_PARENTHESIS)
+ mScanner->NextToken();
+ else
+ mErrors->Error(mScanner->mLocation, "')' expected");
+ dec = vdec;
+ }
+ else if (mScanner->mToken == TK_IDENT)
+ {
+ dec = new Declaration(mScanner->mLocation, DT_VARIABLE);
+ dec->mIdent = mScanner->mTokenIdent;
+ dec->mBase = nullptr;
+ mScanner->NextToken();
+ }
+ else
+ {
+ dec = new Declaration(mScanner->mLocation, DT_ANON);
+ dec->mBase = nullptr;
+ }
+
+ for (;;)
+ {
+ if (mScanner->mToken == TK_OPEN_BRACKET)
+ {
+ Declaration* ndec = new Declaration(mScanner->mLocation, DT_TYPE_ARRAY);
+ ndec->mSize = 0;
+ ndec->mFlags |= DTF_DEFINED;
+ mScanner->NextToken();
+ if (mScanner->mToken != TK_CLOSE_PARENTHESIS)
+ {
+ Expression* exp = ParseRExpression();
+ if (exp->mType == EX_CONSTANT && exp->mDecType->IsIntegerType() && exp->mDecValue->mType == DT_CONST_INTEGER)
+ ndec->mSize = exp->mDecValue->mInteger;
+ else
+ mErrors->Error(exp->mLocation, "Constant integer expression expected");
+ ndec->mFlags |= DTF_DEFINED;
+ }
+ if (mScanner->mToken == TK_CLOSE_BRACKET)
+ mScanner->NextToken();
+ else
+ mErrors->Error(mScanner->mLocation, "']' expected");
+ ndec->mBase = dec;
+ dec = ndec;
+ }
+ else if (mScanner->mToken == TK_OPEN_PARENTHESIS)
+ {
+ Declaration* ndec = new Declaration(mScanner->mLocation, DT_TYPE_FUNCTION);
+ ndec->mSize = 0;
+ Declaration* pdec = nullptr;
+ mScanner->NextToken();
+ if (mScanner->mToken != TK_CLOSE_PARENTHESIS)
+ {
+ int vi = 0;
+ for(;;)
+ {
+ if (mScanner->mToken == TK_ELLIPSIS)
+ {
+ ndec->mFlags |= DTF_VARIADIC;
+ mScanner->NextToken();
+ break;
+ }
+
+ Declaration* bdec = ParseBaseTypeDeclaration(0);
+ Declaration* adec = ParsePostfixDeclaration();
+
+ adec = ReverseDeclaration(adec, bdec);
+
+ if (adec->mBase->mType == DT_TYPE_VOID)
+ {
+ if (pdec)
+ mErrors->Error(pdec->mLocation, "Invalid void argument");
+ break;
+ }
+ else
+ {
+ if (!(adec->mBase->mFlags & DTF_DEFINED))
+ mErrors->Error(adec->mLocation, "Type of argument not defined");
+
+ adec->mType = DT_ARGUMENT;
+ adec->mVarIndex = vi;
+ adec->mOffset = 0;
+ adec->mSize = adec->mBase->mSize;
+ vi += adec->mBase->mSize;
+ if (pdec)
+ pdec->mNext = adec;
+ else
+ ndec->mParams = adec;
+ pdec = adec;
+
+ if (mScanner->mToken == TK_COMMA)
+ mScanner->NextToken();
+ else
+ break;
+ }
+ }
+
+ if (mScanner->mToken == TK_CLOSE_PARENTHESIS)
+ mScanner->NextToken();
+ else
+ mErrors->Error(mScanner->mLocation, "')' expected");
+ }
+ else
+ mScanner->NextToken();
+ ndec->mBase = dec;
+ dec = ndec;
+ }
+ else
+ return dec;
+ }
+}
+
+Declaration* Parser::ReverseDeclaration(Declaration* odec, Declaration* bdec)
+{
+ Declaration* cdec = odec->mBase;
+
+ if (bdec)
+ {
+ if (odec->mType == DT_TYPE_ARRAY)
+ odec->mSize *= bdec->mSize;
+ else if (odec->mType == DT_VARIABLE || odec->mType == DT_ARGUMENT || odec->mType == DT_ANON)
+ odec->mSize = bdec->mSize;
+ odec->mBase = bdec;
+ }
+
+ if (cdec)
+ return ReverseDeclaration(cdec, odec);
+ else
+ return odec;
+}
+
+Declaration * Parser::CopyConstantInitializer(int offset, Declaration* dtype, Expression* exp)
+{
+ Declaration* dec = exp->mDecValue;
+
+ if (exp->mType == EX_CONSTANT)
+ {
+ if (!dtype->CanAssign(exp->mDecType))
+ mErrors->Error(exp->mLocation, "Incompatible constant initializer");
+ else
+ {
+ if (dec->mType == DT_CONST_FLOAT)
+ {
+ if (dtype->IsIntegerType() || dtype->mType == DT_TYPE_POINTER)
+ {
+ Declaration* ndec = new Declaration(dec->mLocation, DT_CONST_INTEGER);
+ ndec->mInteger = int(dec->mNumber);
+ ndec->mBase = dtype;
+ dec = ndec;
+ }
+ else
+ {
+ Declaration* ndec = new Declaration(dec->mLocation, DT_CONST_FLOAT);
+ ndec->mNumber = dec->mNumber;
+ ndec->mBase = dtype;
+ dec = ndec;
+ }
+ }
+ else if (dec->mType == DT_CONST_INTEGER)
+ {
+ if (dtype->mType == DT_TYPE_FLOAT)
+ {
+ Declaration* ndec = new Declaration(dec->mLocation, DT_CONST_FLOAT);
+ ndec->mNumber = dec->mInteger;
+ ndec->mBase = dtype;
+ dec = ndec;
+ }
+ else
+ {
+ Declaration* ndec = new Declaration(dec->mLocation, DT_CONST_INTEGER);
+ ndec->mInteger = dec->mInteger;
+ ndec->mBase = dtype;
+ dec = ndec;
+ }
+ }
+ else if (dec->mType == DT_CONST_DATA)
+ {
+ if (dtype->mType == DT_TYPE_POINTER)
+ {
+ Declaration* ndec = new Declaration(dec->mLocation, DT_CONST_POINTER);
+ ndec->mValue = exp;
+ ndec->mBase = dtype;
+ dec = ndec;
+ }
+ else
+ {
+ Declaration* ndec = new Declaration(dec->mLocation, DT_CONST_DATA);
+ ndec->mValue = exp;
+ ndec->mBase = dtype;
+ dec = ndec;
+ }
+ }
+
+ dec->mOffset = offset;
+ }
+ }
+ else
+ mErrors->Error(exp->mLocation, "Constant initializer expected");
+
+ return dec;
+}
+
+Expression* Parser::ParseInitExpression(Declaration* dtype)
+{
+ Expression* exp = nullptr;
+ Declaration* dec;
+
+ if (dtype->mType == DT_TYPE_ARRAY || dtype->mType == DT_TYPE_STRUCT)
+ {
+ if (!(dtype->mFlags & DTF_DEFINED))
+ {
+ if (dtype->mIdent)
+ mErrors->Error(mScanner->mLocation, "Constant for undefined type", dtype->mIdent->mString);
+ else
+ mErrors->Error(mScanner->mLocation, "Constant for undefined annonymous type");
+ }
+ if (ConsumeTokenIf(TK_OPEN_BRACE))
+ {
+ dec = new Declaration(mScanner->mLocation, DT_CONST_STRUCT);
+ dec->mBase = dtype;
+ dec->mSize = dtype->mSize;
+
+ Declaration* last = nullptr;
+
+ if (dtype->mType == DT_TYPE_ARRAY)
+ {
+ int index = 0;
+ while (index < dtype->mSize)
+ {
+ Expression* texp = ParseInitExpression(dtype->mBase);
+ Declaration* cdec = CopyConstantInitializer(index * dtype->mBase->mSize, dtype->mBase, texp);
+
+ if (last)
+ last->mNext = cdec;
+ else
+ dec->mParams = cdec;
+ last = cdec;
+
+ index++;
+ if (!ConsumeTokenIf(TK_COMMA))
+ break;
+ if (mScanner->mToken == TK_CLOSE_BRACE)
+ break;
+ }
+ }
+ else
+ {
+ Declaration* mdec = dtype->mParams;
+ while (mdec)
+ {
+ Expression* texp = ParseInitExpression(mdec->mBase);
+
+ Declaration* cdec = CopyConstantInitializer(mdec->mOffset, mdec->mBase, texp);
+
+ if (last)
+ last->mNext = cdec;
+ else
+ dec->mParams = cdec;
+ last = cdec;
+
+ if (!ConsumeTokenIf(TK_COMMA))
+ break;
+ mdec = mdec->mNext;
+ }
+ }
+
+ ConsumeToken(TK_CLOSE_BRACE);
+
+ if (last)
+ last->mNext = nullptr;
+ else
+ dec->mParams = nullptr;
+ }
+ else if (mScanner->mToken == TK_STRING && dtype->mType == DT_TYPE_ARRAY && dtype->mBase->mType == DT_TYPE_INTEGER && dtype->mBase->mSize == 1)
+ {
+ dec = new Declaration(mScanner->mLocation, DT_CONST_DATA);
+ dec->mBase = dtype;
+ dec->mSize = dtype->mSize;
+ uint8* d = new uint8[dtype->mSize];
+ dec->mData = d;
+
+ if (strlen(mScanner->mTokenString) < dtype->mSize)
+ {
+ strcpy_s((char *)d, dec->mSize, mScanner->mTokenString);
+ }
+ else
+ mErrors->Error(mScanner->mLocation, "String constant is too large for char array");
+
+ mScanner->NextToken();
+ }
+ else
+ {
+ mErrors->Error(mScanner->mLocation, "Struct/Array constant expression expected");
+ dec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
+ }
+
+ exp = new Expression(mScanner->mLocation, EX_CONSTANT);
+ exp->mDecType = dtype;
+ exp->mDecValue = dec;
+ }
+ else
+ {
+ exp = ParseRExpression();
+ if (dtype->mType == DT_TYPE_POINTER && exp->mDecType && exp->mDecType->mType == DT_TYPE_ARRAY)
+ {
+ Declaration* ndec = new Declaration(exp->mDecValue->mLocation, DT_CONST_POINTER);
+ ndec->mValue = exp;
+ dec = ndec;
+
+ Expression * nexp = new Expression(mScanner->mLocation, EX_CONSTANT);
+ nexp->mDecType = new Declaration(dec->mLocation, DT_TYPE_POINTER);
+ nexp->mDecType->mBase = exp->mDecType->mBase;
+ nexp->mDecType->mSize = 2;
+ nexp->mDecType->mFlags |= DTF_DEFINED;
+ nexp->mDecValue = ndec;
+ exp = nexp;
+ }
+ }
+
+ return exp;
+}
+
+Declaration* Parser::ParseDeclaration(bool variable)
+{
+ bool definingType = false;
+
+ if (mScanner->mToken == TK_TYPEDEF)
+ {
+ definingType = true;
+ variable = false;
+ mScanner->NextToken();
+ }
+
+ Declaration* bdec = ParseBaseTypeDeclaration(0);
+
+ Declaration* rdec = nullptr, * ldec = nullptr;
+
+ for (;;)
+ {
+ Declaration* ndec = ParsePostfixDeclaration();
+
+ ndec = ReverseDeclaration(ndec, bdec);
+
+ if (definingType)
+ {
+ if (ndec->mIdent)
+ {
+ Declaration* pdec = mScope->Insert(ndec->mIdent, ndec->mBase);
+ if (pdec)
+ mErrors->Error(ndec->mLocation, "Duplicate type declaration", ndec->mIdent->mString);
+ }
+ }
+ else
+ {
+ if (variable)
+ {
+ if (ndec->mBase->mType == DT_TYPE_FUNCTION)
+ ndec->mType = DT_CONST_FUNCTION;
+
+ if (ndec->mIdent)
+ {
+ Declaration* pdec;
+
+ if (mGlobals == mScope)
+ {
+ pdec = mCompilationUnits->mScope->Insert(ndec->mIdent, ndec);
+ Declaration * ldec = mScope->Insert(ndec->mIdent, pdec ? pdec : ndec);
+ if (ldec && ldec != pdec)
+ mErrors->Error(ndec->mLocation, "Duplicate definition");
+ }
+ else
+ pdec = mScope->Insert(ndec->mIdent, ndec);
+
+ if (pdec)
+ {
+ if (pdec->mType == DT_CONST_FUNCTION && ndec->mBase->mType == DT_TYPE_FUNCTION)
+ {
+ if (!ndec->mBase->IsSame(pdec->mBase))
+ mErrors->Error(ndec->mLocation, "Function declaration differs");
+ ndec = pdec;
+ }
+ else
+ mErrors->Error(ndec->mLocation, "Duplicate variable declaration", ndec->mIdent->mString);
+ }
+ }
+
+ if (mGlobals == mScope)
+ {
+ ndec->mFlags |= DTF_GLOBAL;
+ ndec->mVarIndex = -1;
+ }
+ else
+ ndec->mVarIndex = mLocalIndex++;
+ }
+
+ ndec->mOffset = 0;
+
+ if (rdec)
+ ldec->mNext = ndec;
+ else
+ rdec = ndec;
+ ldec = ndec;
+ ndec->mNext = nullptr;
+
+ if (mScanner->mToken == TK_ASSIGN)
+ {
+ mScanner->NextToken();
+ ndec->mValue = ParseInitExpression(ndec->mBase);
+ }
+ }
+
+ if (mScanner->mToken == TK_COMMA)
+ mScanner->NextToken();
+ else if (mScanner->mToken == TK_OPEN_BRACE)
+ {
+ if (ndec->mBase->mType == DT_TYPE_FUNCTION)
+ {
+ if (ndec->mFlags & DTF_DEFINED)
+ mErrors->Error(ndec->mLocation, "Duplicate function definition");
+
+ ndec->mVarIndex = -1;
+ ndec->mValue = ParseFunction(ndec->mBase);
+ ndec->mFlags |= DTF_DEFINED;
+ }
+ return rdec;
+ }
+ else
+ return rdec;
+ }
+
+ return rdec;
+}
+
+Expression* Parser::ParseDeclarationExpression(void)
+{
+ Declaration* dec;
+ Expression* exp = nullptr, * rexp = nullptr;
+
+ dec = ParseDeclaration(true);
+ if (dec->mType == DT_ANON && dec->mNext == 0)
+ {
+ exp = new Expression(dec->mLocation, EX_TYPE);
+ exp->mDecValue = dec;
+ exp->mDecType = dec->mBase;
+ }
+ else
+ {
+ while (dec)
+ {
+ if (dec->mValue)
+ {
+ Expression* nexp = new Expression(dec->mValue->mLocation, EX_ASSIGNMENT);
+ nexp->mToken = TK_ASSIGN;
+ nexp->mLeft = new Expression(dec->mLocation, EX_VARIABLE);
+ nexp->mLeft->mDecValue = dec;
+ nexp->mLeft->mDecType = dec->mBase;
+
+ nexp->mRight = dec->mValue;
+
+ if (!exp)
+ exp = nexp;
+ else
+ {
+ if (!rexp)
+ {
+ rexp = new Expression(nexp->mLocation, EX_SEQUENCE);
+ rexp->mLeft = exp;
+ exp = rexp;
+ }
+ rexp->mRight = new Expression(nexp->mLocation, EX_SEQUENCE);
+ rexp = rexp->mRight;
+ rexp->mLeft = nexp;
+ }
+ }
+
+ dec = dec->mNext;
+ }
+ }
+
+ return exp;
+}
+
+Expression* Parser::ParseSimpleExpression(void)
+{
+ Declaration* dec;
+ Expression* exp = nullptr, * rexp = nullptr;
+
+ switch (mScanner->mToken)
+ {
+ case TK_INT:
+ case TK_SHORT:
+ case TK_LONG:
+ case TK_FLOAT:
+ case TK_CHAR:
+ case TK_BOOL:
+ case TK_VOID:
+ case TK_UNSIGNED:
+ case TK_CONST:
+ case TK_VOLATILE:
+ case TK_STRUCT:
+ case TK_TYPEDEF:
+ exp = ParseDeclarationExpression();
+ break;
+ case TK_INTEGER:
+ dec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
+ if (dec->mInteger < 32768)
+ dec->mBase = TheSignedIntTypeDeclaration;
+ else
+ dec->mBase = TheUnsignedIntTypeDeclaration;
+ dec->mInteger = mScanner->mTokenInteger;
+ exp = new Expression(mScanner->mLocation, EX_CONSTANT);
+ exp->mDecValue = dec;
+ exp->mDecType = dec->mBase;
+
+ mScanner->NextToken();
+ break;
+ case TK_NUMBER:
+ dec = new Declaration(mScanner->mLocation, DT_CONST_FLOAT);
+ dec->mBase = TheFloatTypeDeclaration;
+ dec->mNumber = mScanner->mTokenNumber;
+ exp = new Expression(mScanner->mLocation, EX_CONSTANT);
+ exp->mDecValue = dec;
+ exp->mDecType = dec->mBase;
+
+ mScanner->NextToken();
+ break;
+ case TK_STRING:
+ {
+ dec = new Declaration(mScanner->mLocation, DT_CONST_DATA);
+ dec->mSize = strlen(mScanner->mTokenString) + 1;
+ dec->mVarIndex = -1;
+ dec->mBase = new Declaration(mScanner->mLocation, DT_TYPE_ARRAY);
+ dec->mBase->mSize = dec->mSize;
+ dec->mBase->mBase = TheConstSignedCharTypeDeclaration;
+ dec->mBase->mFlags |= DTF_DEFINED;
+ uint8* d = new uint8[dec->mSize];
+ dec->mData = d;
+ memcpy(d, mScanner->mTokenString, dec->mSize);
+
+ exp = new Expression(mScanner->mLocation, EX_CONSTANT);
+ exp->mDecValue = dec;
+ exp->mDecType = dec->mBase;
+
+ mScanner->NextToken();
+
+ // automatic string concatenation
+ while (mScanner->mToken == TK_STRING)
+ {
+ int s = strlen(mScanner->mTokenString);
+ uint8* d = new uint8[dec->mSize + s];
+ memcpy(d, dec->mData, dec->mSize - 1);
+ memcpy(d + dec->mSize - 1, mScanner->mTokenString, s + 1);
+ dec->mSize += s;
+ delete[] dec->mData;
+ dec->mData = d;
+ mScanner->NextToken();
+ }
+ break;
+ }
+ case TK_TRUE:
+ dec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
+ dec->mBase = TheBoolTypeDeclaration;
+ dec->mInteger = 1;
+ exp = new Expression(mScanner->mLocation, EX_CONSTANT);
+ exp->mDecValue = dec;
+ exp->mDecType = dec->mBase;
+
+ mScanner->NextToken();
+ break;
+ case TK_FALSE:
+ dec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
+ dec->mBase = TheBoolTypeDeclaration;
+ dec->mInteger = 0;
+ exp = new Expression(mScanner->mLocation, EX_CONSTANT);
+ exp->mDecValue = dec;
+ exp->mDecType = dec->mBase;
+
+ mScanner->NextToken();
+ break;
+ case TK_NULL:
+ dec = new Declaration(mScanner->mLocation, DT_CONST_ADDRESS);
+ dec->mBase = TheVoidPointerTypeDeclaration;
+ dec->mInteger = 0;
+ exp = new Expression(mScanner->mLocation, EX_CONSTANT);
+ exp->mDecValue = dec;
+ exp->mDecType = dec->mBase;
+
+ mScanner->NextToken();
+ break;
+ case TK_IDENT:
+ dec = mScope->Lookup(mScanner->mTokenIdent);
+ if (dec)
+ {
+ if (dec->mType == DT_CONST_INTEGER || dec->mType == DT_CONST_FLOAT || dec->mType == DT_CONST_FUNCTION)
+ {
+ exp = new Expression(mScanner->mLocation, EX_CONSTANT);
+ exp->mDecValue = dec;
+ exp->mDecType = dec->mBase;
+ exp->mConst = true;
+ mScanner->NextToken();
+ }
+ else if (dec->mType == DT_VARIABLE || dec->mType == DT_ARGUMENT)
+ {
+ exp = new Expression(mScanner->mLocation, EX_VARIABLE);
+ exp->mDecValue = dec;
+ exp->mDecType = dec->mBase;
+ mScanner->NextToken();
+ }
+ else if (dec->mType <= DT_TYPE_FUNCTION)
+ {
+ exp = ParseDeclarationExpression();
+ }
+ else
+ {
+ mErrors->Error(mScanner->mLocation, "Invalid identifier", mScanner->mTokenIdent->mString);
+ mScanner->NextToken();
+ }
+ }
+ else
+ {
+ mErrors->Error(mScanner->mLocation, "Unknown identifier", mScanner->mTokenIdent->mString);
+ mScanner->NextToken();
+ }
+
+ break;
+ case TK_SIZEOF:
+ mScanner->NextToken();
+ rexp = ParseParenthesisExpression();
+ dec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
+ dec->mBase = TheSignedIntTypeDeclaration;
+ dec->mInteger = rexp->mDecType->mSize;
+ exp = new Expression(mScanner->mLocation, EX_CONSTANT);
+ exp->mDecValue = dec;
+ exp->mDecType = dec->mBase;
+ break;
+
+ case TK_OPEN_PARENTHESIS:
+ mScanner->NextToken();
+ exp = ParseExpression();
+ if (mScanner->mToken == TK_CLOSE_PARENTHESIS)
+ mScanner->NextToken();
+ else
+ mErrors->Error(mScanner->mLocation, "')' expected");
+
+ if (exp->mType == EX_TYPE)
+ {
+ Expression* nexp = new Expression(mScanner->mLocation, EX_TYPECAST);
+ nexp->mDecType = exp->mDecType;
+ nexp->mLeft = exp;
+ nexp->mRight = ParsePrefixExpression();
+ exp = nexp->ConstantFold();
+ }
+ break;
+ default:
+ mErrors->Error(mScanner->mLocation, "Term starts with invalid token", TokenNames[mScanner->mToken]);
+ mScanner->NextToken();
+ }
+
+ if (!exp)
+ {
+ exp = new Expression(mScanner->mLocation, EX_VOID);
+ exp->mDecType = TheVoidTypeDeclaration;
+ }
+
+ return exp;
+}
+
+
+Expression* Parser::ParsePostfixExpression(void)
+{
+ Expression* exp = ParseSimpleExpression();
+
+ for (;;)
+ {
+ if (mScanner->mToken == TK_OPEN_BRACKET)
+ {
+ if (exp->mDecType->mType != DT_TYPE_ARRAY && exp->mDecType->mType != DT_TYPE_POINTER)
+ mErrors->Error(mScanner->mLocation, "Array expected for indexing");
+ mScanner->NextToken();
+ Expression* nexp = new Expression(mScanner->mLocation, EX_INDEX);
+ nexp->mLeft = exp;
+ nexp->mRight = ParseExpression();
+ if (mScanner->mToken == TK_CLOSE_BRACKET)
+ mScanner->NextToken();
+ else
+ mErrors->Error(mScanner->mLocation, "']' expected");
+ nexp->mDecType = exp->mDecType->mBase;
+ exp = nexp;
+ }
+ else if (mScanner->mToken == TK_OPEN_PARENTHESIS)
+ {
+ if (exp->mDecType->mType == DT_TYPE_POINTER && exp->mDecType->mBase->mType == DT_TYPE_FUNCTION)
+ {
+ }
+ else if (exp->mDecType->mType == DT_TYPE_FUNCTION)
+ {
+ }
+ else
+ mErrors->Error(mScanner->mLocation, "Function expected for call");
+
+ mScanner->NextToken();
+ Expression* nexp = new Expression(mScanner->mLocation, EX_CALL);
+ nexp->mLeft = exp;
+ nexp->mDecType = exp->mDecType->mBase;
+ if (mScanner->mToken != TK_CLOSE_PARENTHESIS)
+ {
+ nexp->mRight = ParseListExpression();
+ ConsumeToken(TK_CLOSE_PARENTHESIS);
+ }
+ else
+ {
+ nexp->mRight = nullptr;
+ mScanner->NextToken();
+ }
+ exp = nexp;
+ }
+ else if (mScanner->mToken == TK_INC || mScanner->mToken == TK_DEC)
+ {
+ Expression* nexp = new Expression(mScanner->mLocation, EX_POSTINCDEC);
+ nexp->mToken = mScanner->mToken;
+ nexp->mLeft = exp;
+ nexp->mDecType = exp->mDecType;
+ exp = nexp;
+ mScanner->NextToken();
+ }
+ else if (mScanner->mToken == TK_ARROW)
+ {
+ mScanner->NextToken();
+ if (exp->mDecType->mType == DT_TYPE_POINTER)
+ {
+ Expression * dexp = new Expression(mScanner->mLocation, EX_PREFIX);
+ dexp->mToken = TK_MUL;
+ dexp->mDecType = exp->mDecType->mBase;
+ dexp->mLeft = exp;
+
+ if (dexp->mDecType->mType == DT_TYPE_STRUCT)
+ {
+ Expression* nexp = new Expression(mScanner->mLocation, EX_QUALIFY);
+ nexp->mLeft = dexp;
+ if (mScanner->mToken == TK_IDENT)
+ {
+ Declaration* mdec = dexp->mDecType->mScope->Lookup(mScanner->mTokenIdent);
+ if (mdec)
+ {
+ nexp->mDecValue = mdec;
+ nexp->mDecType = mdec->mBase;
+ exp = nexp;
+ }
+ else
+ mErrors->Error(mScanner->mLocation, "Struct member identifier not found", mScanner->mTokenIdent->mString);
+ mScanner->NextToken();
+ }
+ else
+ mErrors->Error(mScanner->mLocation, "Struct member identifier expected");
+ }
+ else
+ mErrors->Error(mScanner->mLocation, "Struct expected");
+ }
+ else
+ mErrors->Error(mScanner->mLocation, "Pointer expected");
+ }
+ else if (mScanner->mToken == TK_DOT)
+ {
+ mScanner->NextToken();
+ if (exp->mDecType->mType == DT_TYPE_STRUCT)
+ {
+ Expression* nexp = new Expression(mScanner->mLocation, EX_QUALIFY);
+ nexp->mLeft = exp;
+ if (mScanner->mToken == TK_IDENT)
+ {
+ Declaration* mdec = exp->mDecType->mScope->Lookup(mScanner->mTokenIdent);
+ if (mdec)
+ {
+ nexp->mDecValue = mdec;
+ nexp->mDecType = mdec->mBase;
+ exp = nexp;
+ }
+ else
+ mErrors->Error(mScanner->mLocation, "Struct member identifier not found", mScanner->mTokenIdent->mString);
+ mScanner->NextToken();
+ }
+ else
+ mErrors->Error(mScanner->mLocation, "Struct member identifier expected");
+ }
+ else
+ mErrors->Error(mScanner->mLocation, "Struct expected");
+ }
+ else
+ return exp;
+ }
+}
+
+
+Expression* Parser::ParsePrefixExpression(void)
+{
+ if (mScanner->mToken == TK_SUB || mScanner->mToken == TK_BINARY_NOT || mScanner->mToken == TK_LOGICAL_NOT || mScanner->mToken == TK_MUL || mScanner->mToken == TK_INC || mScanner->mToken == TK_DEC || mScanner->mToken == TK_BINARY_AND)
+ {
+ Expression* nexp;
+ if (mScanner->mToken == TK_LOGICAL_NOT)
+ {
+ mScanner->NextToken();
+ nexp = ParsePrefixExpression();
+ nexp = nexp->LogicInvertExpression();
+ }
+ else if (mScanner->mToken == TK_INC || mScanner->mToken == TK_DEC)
+ {
+ nexp = new Expression(mScanner->mLocation, EX_PREINCDEC);
+ nexp->mToken = mScanner->mToken;
+ mScanner->NextToken();
+ nexp->mLeft = ParsePrefixExpression();;
+ nexp->mDecType = nexp->mLeft->mDecType;
+ }
+ else
+ {
+ nexp = new Expression(mScanner->mLocation, EX_PREFIX);
+ nexp->mToken = mScanner->mToken;
+ mScanner->NextToken();
+ nexp->mLeft = ParsePrefixExpression();
+ if (nexp->mToken == TK_MUL)
+ {
+ if (nexp->mLeft->mDecType->mType == DT_TYPE_POINTER || nexp->mLeft->mDecType->mType == DT_TYPE_ARRAY)
+ nexp->mDecType = nexp->mLeft->mDecType;
+ else
+ mErrors->Error(nexp->mLocation, "Pointer or array type expected");
+ }
+ else if (nexp->mToken == TK_BINARY_AND)
+ {
+ Declaration* pdec = new Declaration(nexp->mLocation, DT_TYPE_POINTER);
+ pdec->mBase = nexp->mLeft->mDecType;
+ pdec->mSize = 2;
+ nexp->mDecType = pdec;
+ }
+ else
+ nexp->mDecType = nexp->mLeft->mDecType;
+ }
+ return nexp->ConstantFold();
+ }
+ else
+ return ParsePostfixExpression();
+}
+
+Expression* Parser::ParseMulExpression(void)
+{
+ Expression* exp = ParsePrefixExpression();
+
+ while (mScanner->mToken == TK_MUL || mScanner->mToken == TK_DIV || mScanner->mToken == TK_MOD)
+ {
+ Expression* nexp = new Expression(mScanner->mLocation, EX_BINARY);
+ nexp->mToken = mScanner->mToken;
+ nexp->mLeft = exp;
+ mScanner->NextToken();
+ nexp->mRight = ParsePrefixExpression();
+ exp = nexp->ConstantFold();
+ }
+
+ return exp;
+}
+
+Expression* Parser::ParseAddExpression(void)
+{
+ Expression* exp = ParseMulExpression();
+
+ while (mScanner->mToken == TK_ADD || mScanner->mToken == TK_SUB)
+ {
+ Expression * nexp = new Expression(mScanner->mLocation, EX_BINARY);
+ nexp->mToken = mScanner->mToken;
+ nexp->mLeft = exp;
+ mScanner->NextToken();
+ nexp->mRight = ParseMulExpression();
+ exp = nexp->ConstantFold();
+ }
+
+ return exp;
+}
+
+Expression* Parser::ParseShiftExpression(void)
+{
+ Expression* exp = ParseAddExpression();
+
+ while (mScanner->mToken == TK_LEFT_SHIFT || mScanner->mToken == TK_RIGHT_SHIFT)
+ {
+ Expression* nexp = new Expression(mScanner->mLocation, EX_BINARY);
+ nexp->mToken = mScanner->mToken;
+ nexp->mLeft = exp;
+ mScanner->NextToken();
+ nexp->mRight = ParseAddExpression();
+ exp = nexp->ConstantFold();
+ }
+
+ return exp;
+}
+
+Expression* Parser::ParseRelationalExpression(void)
+{
+ Expression* exp = ParseShiftExpression();
+
+ while (mScanner->mToken >= TK_EQUAL && mScanner->mToken <= TK_LESS_EQUAL)
+ {
+ Expression* nexp = new Expression(mScanner->mLocation, EX_RELATIONAL);
+ nexp->mToken = mScanner->mToken;
+ nexp->mLeft = exp;
+ mScanner->NextToken();
+ nexp->mRight = ParseShiftExpression();
+ exp = nexp->ConstantFold();
+ }
+
+ return exp;
+}
+
+Expression* Parser::ParseBinaryAndExpression(void)
+{
+ Expression* exp = ParseRelationalExpression();
+
+ while (mScanner->mToken == TK_BINARY_AND)
+ {
+ Expression* nexp = new Expression(mScanner->mLocation, EX_BINARY);
+ nexp->mToken = mScanner->mToken;
+ nexp->mLeft = exp;
+ mScanner->NextToken();
+ nexp->mRight = ParseRelationalExpression();
+ exp = nexp->ConstantFold();
+ }
+
+ return exp;
+}
+
+Expression* Parser::ParseBinaryXorExpression(void)
+{
+ Expression* exp = ParseBinaryAndExpression();
+
+ while (mScanner->mToken == TK_BINARY_XOR)
+ {
+ Expression* nexp = new Expression(mScanner->mLocation, EX_BINARY);
+ nexp->mToken = mScanner->mToken;
+ nexp->mLeft = exp;
+ mScanner->NextToken();
+ nexp->mRight = ParseBinaryAndExpression();
+ exp = nexp->ConstantFold();
+ }
+
+ return exp;
+}
+
+Expression* Parser::ParseBinaryOrExpression(void)
+{
+ Expression* exp = ParseBinaryXorExpression();
+
+ while (mScanner->mToken == TK_BINARY_OR)
+ {
+ Expression* nexp = new Expression(mScanner->mLocation, EX_BINARY);
+ nexp->mToken = mScanner->mToken;
+ nexp->mLeft = exp;
+ mScanner->NextToken();
+ nexp->mRight = ParseBinaryXorExpression();
+ exp = nexp->ConstantFold();
+ }
+
+ return exp;
+}
+
+Expression* Parser::ParseLogicAndExpression(void)
+{
+ Expression* exp = ParseBinaryOrExpression();
+
+ while (mScanner->mToken == TK_LOGICAL_AND)
+ {
+ Expression* nexp = new Expression(mScanner->mLocation, EX_LOGICAL_AND);
+ nexp->mToken = mScanner->mToken;
+ nexp->mLeft = exp;
+ mScanner->NextToken();
+ nexp->mRight = ParseBinaryOrExpression();
+ exp = nexp->ConstantFold();
+ }
+
+ return exp;
+}
+
+Expression* Parser::ParseLogicOrExpression(void)
+{
+ Expression* exp = ParseLogicAndExpression();
+
+ while (mScanner->mToken == TK_LOGICAL_OR)
+ {
+ Expression* nexp = new Expression(mScanner->mLocation, EX_LOGICAL_OR);
+ nexp->mToken = mScanner->mToken;
+ nexp->mLeft = exp;
+ mScanner->NextToken();
+ nexp->mRight = ParseLogicAndExpression();
+ exp = nexp->ConstantFold();
+ }
+
+ return exp;
+}
+
+Expression* Parser::ParseConditionalExpression(void)
+{
+ Expression* exp = ParseLogicAndExpression();
+
+ if (mScanner->mToken == TK_QUESTIONMARK)
+ {
+ Expression* nexp = new Expression(mScanner->mLocation, EX_CONDITIONAL);
+ nexp->mLeft = exp;
+ mScanner->NextToken();
+ Expression* texp = new Expression(mScanner->mLocation, EX_SEQUENCE);
+ nexp->mRight = texp;
+
+ texp->mLeft = ParseLogicOrExpression();
+ ConsumeToken(TK_COLON);
+ texp->mRight = ParseConditionalExpression();
+
+ exp = nexp;
+ }
+
+ return exp;
+}
+
+Expression* Parser::ParseRExpression(void)
+{
+ return ParseConditionalExpression();
+}
+
+Expression* Parser::ParseParenthesisExpression(void)
+{
+ if (mScanner->mToken == TK_OPEN_PARENTHESIS)
+ mScanner->NextToken();
+ else
+ mErrors->Error(mScanner->mLocation, "'(' expected");
+
+ Expression* exp = ParseExpression();
+
+ if (mScanner->mToken == TK_CLOSE_PARENTHESIS)
+ mScanner->NextToken();
+ else
+ mErrors->Error(mScanner->mLocation, "')' expected");
+
+ return exp;
+}
+
+Expression* Parser::ParseAssignmentExpression(void)
+{
+ Expression* exp = ParseLogicOrExpression();
+
+ while (mScanner->mToken >= TK_ASSIGN && mScanner->mToken <= TK_ASSIGN_OR)
+ {
+ Expression* nexp = new Expression(mScanner->mLocation, EX_ASSIGNMENT);
+ nexp->mToken = mScanner->mToken;
+ nexp->mLeft = exp;
+ mScanner->NextToken();
+ nexp->mRight = ParseConditionalExpression();
+ exp = nexp;
+ }
+
+ return exp;
+}
+
+Expression* Parser::ParseExpression(void)
+{
+ return ParseAssignmentExpression();
+}
+
+Expression* Parser::ParseListExpression(void)
+{
+ Expression* exp = ParseExpression();
+ if (mScanner->mToken == TK_COMMA)
+ {
+ Expression* nexp = new Expression(mScanner->mLocation, EX_LIST);
+ nexp->mToken = mScanner->mToken;
+ nexp->mLeft = exp;
+ mScanner->NextToken();
+ nexp->mRight = ParseListExpression();
+ exp = nexp;
+ }
+ return exp;
+
+}
+
+Expression* Parser::ParseFunction(Declaration * dec)
+{
+ DeclarationScope* scope = new DeclarationScope(mScope);
+ mScope = scope;
+
+ Declaration* pdec = dec->mParams;
+ while (pdec)
+ {
+ if (pdec->mIdent)
+ scope->Insert(pdec->mIdent, pdec);
+ pdec = pdec->mNext;
+ }
+ mLocalIndex = 0;
+
+ Expression * exp = ParseStatement();
+
+ mScope = mScope->mParent;
+
+ return exp;
+}
+
+Expression* Parser::ParseStatement(void)
+{
+ Expression* exp = nullptr;
+
+ if (mScanner->mToken == TK_OPEN_BRACE)
+ {
+ DeclarationScope* scope = new DeclarationScope(mScope);
+ mScope = scope;
+
+ mScanner->NextToken();
+ if (mScanner->mToken != TK_CLOSE_BRACE)
+ {
+ Expression* pexp = nullptr;
+ do
+ {
+ Expression* nexp = ParseStatement();
+ if (exp)
+ {
+ if (!pexp)
+ {
+ pexp = new Expression(mScanner->mLocation, EX_SEQUENCE);
+ pexp->mLeft = exp;
+ exp = pexp;
+ }
+
+ pexp->mRight = new Expression(mScanner->mLocation, EX_SEQUENCE);
+ pexp = pexp->mRight;
+ pexp->mLeft = nexp;
+ }
+ else
+ exp = nexp;
+
+ } while (mScanner->mToken != TK_CLOSE_BRACE && mScanner->mToken != TK_EOF);
+ if (mScanner->mToken != TK_CLOSE_BRACE)
+ mErrors->Error(mScanner->mLocation, "'}' expected");
+ mScanner->NextToken();
+ }
+ else
+ {
+ exp = new Expression(mScanner->mLocation, EX_VOID);
+ mScanner->NextToken();
+ }
+
+ mScope = mScope->mParent;
+ }
+ else
+ {
+ switch (mScanner->mToken)
+ {
+ case TK_IF:
+ mScanner->NextToken();
+ exp = new Expression(mScanner->mLocation, EX_IF);
+ exp->mLeft = ParseParenthesisExpression();
+ exp->mRight = new Expression(mScanner->mLocation, EX_ELSE);
+ exp->mRight->mLeft = ParseStatement();
+ if (mScanner->mToken == TK_ELSE)
+ {
+ mScanner->NextToken();
+ exp->mRight->mRight = ParseStatement();
+ }
+ else
+ exp->mRight->mRight = nullptr;
+ break;
+ case TK_WHILE:
+ {
+ mScanner->NextToken();
+
+ DeclarationScope* scope = new DeclarationScope(mScope);
+ mScope = scope;
+
+ exp = new Expression(mScanner->mLocation, EX_WHILE);
+ exp->mLeft = ParseParenthesisExpression();
+ exp->mRight = ParseStatement();
+
+ mScope = mScope->mParent;
+ }
+ break;
+ case TK_DO:
+ mScanner->NextToken();
+ exp = new Expression(mScanner->mLocation, EX_DO);
+ exp->mRight = ParseStatement();
+ if (mScanner->mToken == TK_WHILE)
+ {
+ mScanner->NextToken();
+ exp->mLeft = ParseParenthesisExpression();
+ }
+ else
+ mErrors->Error(mScanner->mLocation, "'while' expected");
+ break;
+ case TK_FOR:
+ mScanner->NextToken();
+ if (mScanner->mToken == TK_OPEN_PARENTHESIS)
+ {
+ DeclarationScope* scope = new DeclarationScope(mScope);
+ mScope = scope;
+
+ mScanner->NextToken();
+ exp = new Expression(mScanner->mLocation, EX_FOR);
+ exp->mLeft = new Expression(mScanner->mLocation, EX_SEQUENCE);
+ exp->mLeft->mLeft = new Expression(mScanner->mLocation, EX_SEQUENCE);
+ exp->mLeft->mRight = ParseExpression();
+ if (mScanner->mToken == TK_SEMICOLON)
+ mScanner->NextToken();
+ else
+ mErrors->Error(mScanner->mLocation, "';' expected");
+ exp->mLeft->mLeft->mLeft = ParseExpression();
+ if (mScanner->mToken == TK_SEMICOLON)
+ mScanner->NextToken();
+ else
+ mErrors->Error(mScanner->mLocation, "';' expected");
+ if (mScanner->mToken != TK_CLOSE_PARENTHESIS)
+ exp->mLeft->mLeft->mRight = ParseExpression();
+ if (mScanner->mToken == TK_CLOSE_PARENTHESIS)
+ mScanner->NextToken();
+ else
+ mErrors->Error(mScanner->mLocation, "')' expected");
+ exp->mRight = ParseStatement();
+
+ mScope = mScope->mParent;
+ }
+ else
+ mErrors->Error(mScanner->mLocation, "'(' expected");
+ break;
+ case TK_SWITCH:
+ mScanner->NextToken();
+ exp = ParseSwitchStatement();
+ break;
+ case TK_RETURN:
+ mScanner->NextToken();
+ exp = new Expression(mScanner->mLocation, EX_RETURN);
+ if (mScanner->mToken != TK_SEMICOLON)
+ exp->mLeft = ParseRExpression();
+ break;
+ case TK_BREAK:
+ mScanner->NextToken();
+ exp = new Expression(mScanner->mLocation, EX_BREAK);
+ break;
+ case TK_CONTINUE:
+ mScanner->NextToken();
+ exp = new Expression(mScanner->mLocation, EX_CONTINUE);
+ break;
+ case TK_SEMICOLON:
+ break;
+ case TK_ASM:
+ mScanner->NextToken();
+ if (mScanner->mToken == TK_OPEN_BRACE)
+ {
+ mScanner->NextToken();
+ exp = ParseAssembler();
+ if (mScanner->mToken == TK_CLOSE_BRACE)
+ mScanner->NextToken();
+ else
+ mErrors->Error(mScanner->mLocation, "'}' expected");
+ }
+ break;
+ default:
+ exp = ParseExpression();
+ }
+ if (mScanner->mToken == TK_SEMICOLON)
+ mScanner->NextToken();
+ }
+
+ return exp;
+}
+
+Expression* Parser::ParseSwitchStatement(void)
+{
+ Expression* sexp = new Expression(mScanner->mLocation, EX_SWITCH);
+
+ if (mScanner->mToken == TK_OPEN_PARENTHESIS)
+ {
+ mScanner->NextToken();
+ sexp->mLeft = ParseRExpression();
+ if (mScanner->mToken == TK_CLOSE_PARENTHESIS)
+ mScanner->NextToken();
+ else
+ mErrors->Error(mScanner->mLocation, "')' expected");
+ }
+ else
+ mErrors->Error(mScanner->mLocation, "'(' expected");
+
+ if (mScanner->mToken == TK_OPEN_BRACE)
+ {
+ mScanner->NextToken();
+
+ if (mScanner->mToken != TK_CLOSE_BRACE)
+ {
+ Expression* pcsexp = nullptr;
+
+ Expression* cexp = nullptr;
+
+ Expression* pexp = nullptr;
+ do
+ {
+ if (mScanner->mToken == TK_CASE)
+ {
+ mScanner->NextToken();
+ cexp = new Expression(mScanner->mLocation, EX_CASE);
+ pexp = cexp;
+ cexp->mLeft = ParseRExpression();
+
+ if (mScanner->mToken == TK_COLON)
+ mScanner->NextToken();
+ else
+ mErrors->Error(mScanner->mLocation, "':' expected");
+
+ Expression* csexp = new Expression(mScanner->mLocation, EX_SEQUENCE);
+ csexp->mLeft = cexp;
+ if (pcsexp)
+ pcsexp->mRight = csexp;
+ else
+ sexp->mRight = csexp;
+ pcsexp = csexp;
+
+ }
+ else if (mScanner->mToken == TK_DEFAULT)
+ {
+ mScanner->NextToken();
+ cexp = new Expression(mScanner->mLocation, EX_DEFAULT);
+ pexp = cexp;
+
+ if (mScanner->mToken == TK_COLON)
+ mScanner->NextToken();
+ else
+ mErrors->Error(mScanner->mLocation, "':' expected");
+
+ Expression * csexp = new Expression(mScanner->mLocation, EX_SEQUENCE);
+ csexp->mLeft = cexp;
+ if (pcsexp)
+ pcsexp->mRight = csexp;
+ else
+ sexp->mRight = csexp;
+ pcsexp = csexp;
+ }
+ else
+ {
+ Expression* nexp = ParseStatement();
+ if (cexp)
+ {
+ Expression* sexp = new Expression(mScanner->mLocation, EX_SEQUENCE);
+ sexp->mLeft = nexp;
+ pexp->mRight = sexp;
+ pexp = sexp;
+ }
+ }
+
+ } while (mScanner->mToken != TK_CLOSE_BRACE && mScanner->mToken != TK_EOF);
+ }
+
+ if (mScanner->mToken == TK_CLOSE_BRACE)
+ mScanner->NextToken();
+ else
+ mErrors->Error(mScanner->mLocation, "'}' expected");
+ }
+ else
+ mErrors->Error(mScanner->mLocation, "'{' expected");
+
+ return sexp;
+}
+
+
+
+Expression* Parser::ParseAssemblerBaseOperand(void)
+{
+ Expression* exp = nullptr;
+ Declaration* dec;
+
+ switch (mScanner->mToken)
+ {
+ case TK_SUB:
+ mScanner->NextToken();
+ exp = ParseAssemblerBaseOperand();
+ if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_INTEGER)
+ {
+ dec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
+ dec->mInteger = - exp->mDecValue->mInteger;
+ if (dec->mInteger < 32768)
+ dec->mBase = TheSignedIntTypeDeclaration;
+ else
+ dec->mBase = TheUnsignedIntTypeDeclaration;
+ exp = new Expression(mScanner->mLocation, EX_CONSTANT);
+ exp->mDecValue = dec;
+ exp->mDecType = dec->mBase;
+ }
+ else
+ mErrors->Error(exp->mLocation, "Cannot negate expression");
+ break;
+
+ case TK_INTEGER:
+ dec = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
+ dec->mInteger = mScanner->mTokenInteger;
+ if (dec->mInteger < 32768)
+ dec->mBase = TheSignedIntTypeDeclaration;
+ else
+ dec->mBase = TheUnsignedIntTypeDeclaration;
+ exp = new Expression(mScanner->mLocation, EX_CONSTANT);
+ exp->mDecValue = dec;
+ exp->mDecType = dec->mBase;
+
+ mScanner->NextToken();
+ break;
+
+ case TK_IDENT:
+ dec = mScope->Lookup(mScanner->mTokenIdent);
+ if (!dec)
+ {
+ exp = new Expression(mScanner->mLocation, EX_CONSTANT);
+ dec = new Declaration(mScanner->mLocation, DT_LABEL);
+ dec->mIdent = mScanner->mTokenIdent;
+ exp->mDecType = TheUnsignedIntTypeDeclaration;
+ mScope->Insert(dec->mIdent, dec);
+ }
+ else
+ {
+ exp = new Expression(mScanner->mLocation, EX_CONSTANT);
+ if (dec->mType == DT_ARGUMENT)
+ {
+ Declaration* ndec = new Declaration(exp->mLocation, DT_CONST_INTEGER);
+ ndec->mBase = TheUnsignedIntTypeDeclaration;
+ ndec->mInteger = 2 + dec->mVarIndex;
+ dec = ndec;
+ exp->mDecType = TheUnsignedIntTypeDeclaration;
+ }
+ else if (dec->mType == DT_CONST_ASSEMBLER)
+ {
+ exp->mDecType = dec->mBase;
+ }
+ else
+ exp->mDecType = TheUnsignedIntTypeDeclaration;
+ }
+
+ exp->mDecValue = dec;
+
+ mScanner->NextToken();
+
+ while (ConsumeTokenIf(TK_DOT))
+ {
+ if (mScanner->mToken == TK_IDENT)
+ {
+ if (exp->mDecValue->mType == DT_CONST_ASSEMBLER)
+ {
+ Declaration* ldec = exp->mDecValue->mBase->mScope->Lookup(mScanner->mTokenIdent);
+ if (ldec)
+ {
+ exp->mDecValue = ldec;
+ exp->mDecType = TheUnsignedIntTypeDeclaration;
+ }
+ else
+ mErrors->Error(mScanner->mLocation, "Assembler label not found", mScanner->mTokenIdent->mString);
+ }
+ mScanner->NextToken();
+ }
+ else
+ mErrors->Error(mScanner->mLocation, "Identifier for qualification expected");
+ }
+ break;
+ default:
+ mErrors->Error(mScanner->mLocation, "Invalid assembler operand");
+ }
+
+ if (!exp)
+ {
+ exp = new Expression(mScanner->mLocation, EX_VOID);
+ exp->mDecType = TheVoidTypeDeclaration;
+ }
+
+ return exp;
+}
+
+Expression* Parser::ParseAssemblerAddOperand(void)
+{
+ Expression* exp = ParseAssemblerBaseOperand();
+ while (mScanner->mToken == TK_ADD || mScanner->mToken == TK_SUB)
+ {
+ Expression* nexp = new Expression(mScanner->mLocation, EX_BINARY);
+ nexp->mToken = mScanner->mToken;
+ nexp->mLeft = exp;
+ mScanner->NextToken();
+ nexp->mRight = ParseAssemblerBaseOperand();
+ if (nexp->mLeft->mDecValue->mType == DT_VARIABLE)
+ {
+ if (nexp->mRight->mDecValue->mType == DT_CONST_INTEGER)
+ {
+ Declaration* ndec = new Declaration(mScanner->mLocation, DT_VARIABLE_REF);
+ ndec->mBase = nexp->mLeft->mDecValue;
+ ndec->mOffset = nexp->mRight->mDecValue->mInteger;
+ exp = new Expression(mScanner->mLocation, EX_CONSTANT);
+ exp->mDecValue = ndec;
+ }
+ else
+ mErrors->Error(mScanner->mLocation, "Integer offset expected");
+ }
+ else if (nexp->mLeft->mDecValue->mType == DT_LABEL)
+ {
+ if (nexp->mRight->mDecValue->mType == DT_CONST_INTEGER)
+ {
+ Declaration* ndec = new Declaration(mScanner->mLocation, DT_LABEL_REF);
+ ndec->mBase = nexp->mLeft->mDecValue;
+ ndec->mOffset = nexp->mRight->mDecValue->mInteger;
+ exp = new Expression(mScanner->mLocation, EX_CONSTANT);
+ exp->mDecValue = ndec;
+ }
+ else
+ mErrors->Error(mScanner->mLocation, "Integer offset expected");
+ }
+ else
+ exp = nexp->ConstantFold();
+ }
+ return exp;
+}
+
+Expression* Parser::ParseAssemblerOperand(void)
+{
+ return ParseAssemblerAddOperand();
+}
+
+Expression* Parser::ParseAssembler(void)
+{
+ DeclarationScope* scope = new DeclarationScope(mScope);
+ mScope = scope;
+
+ mScanner->SetAssemblerMode(true);
+
+ Declaration* decfp = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
+ decfp->mIdent = Ident::Unique("fp");
+ decfp->mBase = TheUnsignedIntTypeDeclaration;
+ decfp->mSize = 2;
+ decfp->mInteger = BC_REG_LOCALS;
+ mScope->Insert(decfp->mIdent, decfp);
+
+ Declaration* decaccu = new Declaration(mScanner->mLocation, DT_CONST_INTEGER);
+ decaccu->mIdent = Ident::Unique("accu");
+ decaccu->mBase = TheUnsignedIntTypeDeclaration;
+ decaccu->mSize = 2;
+ decaccu->mInteger = BC_REG_ACCU;
+ mScope->Insert(decaccu->mIdent, decaccu);
+
+ Declaration* dassm = new Declaration(mScanner->mLocation, DT_TYPE_ASSEMBLER);
+ dassm->mScope = scope;
+
+ Declaration* vdasm = new Declaration(mScanner->mLocation, DT_CONST_ASSEMBLER);
+ vdasm->mVarIndex = -1;
+
+ vdasm->mBase = dassm;
+
+ Expression* ifirst = new Expression(mScanner->mLocation, EX_ASSEMBLER);
+ Expression* ilast = ifirst;
+
+ ifirst->mDecType = dassm;
+ ifirst->mDecValue = vdasm;
+ vdasm->mValue = ifirst;
+
+ int offset = 0;
+
+ while (mScanner->mToken != TK_CLOSE_BRACE && mScanner->mToken != TK_EOF)
+ {
+ if (mScanner->mToken == TK_IDENT)
+ {
+ AsmInsType ins = FindAsmInstruction(mScanner->mTokenIdent->mString);
+ if (ins == ASMIT_INV)
+ {
+ const Ident* label = mScanner->mTokenIdent;
+ mScanner->NextToken();
+ if (mScanner->mToken != TK_COLON)
+ mErrors->Error(mScanner->mLocation, "':' expected");
+ else
+ mScanner->NextToken();
+
+ Declaration* dec = mScope->Lookup(label);
+ if (dec)
+ {
+ if (dec->mType != DT_LABEL || dec->mBase)
+ mErrors->Error(mScanner->mLocation, "Duplicate label definition");
+ }
+ else
+ dec = new Declaration(mScanner->mLocation, DT_LABEL);
+
+ dec->mIdent = label;
+ dec->mValue = ilast;
+ dec->mInteger = offset;
+ dec->mBase = vdasm;
+ mScope->Insert(dec->mIdent, dec);
+ }
+ else
+ {
+ ilast->mAsmInsType = ins;
+ mScanner->NextToken();
+ if (mScanner->mToken == TK_EOL)
+ ilast->mAsmInsMode = ASMIM_IMPLIED;
+ else if (mScanner->mToken == TK_HASH)
+ {
+ ilast->mAsmInsMode = ASMIM_IMMEDIATE;
+ mScanner->NextToken();
+ ilast->mLeft = ParseAssemblerOperand();
+ }
+ else if (mScanner->mToken == TK_OPEN_PARENTHESIS)
+ {
+ mScanner->NextToken();
+ ilast->mLeft = ParseAssemblerOperand();
+ if (mScanner->mToken == TK_COMMA)
+ {
+ mScanner->NextToken();
+ if (mScanner->mToken == TK_IDENT && (!strcmp(mScanner->mTokenIdent->mString, "x") || !strcmp(mScanner->mTokenIdent->mString, "X")))
+ {
+ ilast->mAsmInsMode = ASMIM_INDIRECT_X;
+ mScanner->NextToken();
+ if (mScanner->mToken == TK_CLOSE_PARENTHESIS)
+ mScanner->NextToken();
+ else
+ mErrors->Error(mScanner->mLocation, "')' expected");
+ }
+ else
+ mErrors->Error(mScanner->mLocation, "',x' expected");
+ }
+ else if (mScanner->mToken == TK_CLOSE_PARENTHESIS)
+ {
+ mScanner->NextToken();
+ if (mScanner->mToken == TK_COMMA)
+ {
+ mScanner->NextToken();
+ if (mScanner->mToken == TK_IDENT && (!strcmp(mScanner->mTokenIdent->mString, "y") || !strcmp(mScanner->mTokenIdent->mString, "Y")))
+ {
+ ilast->mAsmInsMode = ASMIM_INDIRECT_Y;
+ mScanner->NextToken();
+ }
+ else
+ mErrors->Error(mScanner->mLocation, "',y' expected");
+ }
+ else
+ {
+ ilast->mAsmInsMode = ASMIM_INDIRECT;
+ }
+ }
+ else
+ mErrors->Error(mScanner->mLocation, "',' or ')' expected");
+ }
+ else
+ {
+ ilast->mLeft = ParseAssemblerOperand();
+ if (mScanner->mToken == TK_COMMA)
+ {
+ mScanner->NextToken();
+ if (mScanner->mToken == TK_IDENT && (!strcmp(mScanner->mTokenIdent->mString, "x") || !strcmp(mScanner->mTokenIdent->mString, "X")))
+ {
+ ilast->mAsmInsMode = ASMIM_ABSOLUTE_X;
+ mScanner->NextToken();
+ }
+ else if (mScanner->mToken == TK_IDENT && (!strcmp(mScanner->mTokenIdent->mString, "y") || !strcmp(mScanner->mTokenIdent->mString, "Y")))
+ {
+ ilast->mAsmInsMode = ASMIM_ABSOLUTE_Y;
+ mScanner->NextToken();
+ }
+ else
+ mErrors->Error(mScanner->mLocation, "',x' or ',y' expected");
+ }
+ else
+ {
+ if (HasAsmInstructionMode(ilast->mAsmInsType, ASMIM_RELATIVE))
+ ilast->mAsmInsMode = ASMIM_RELATIVE;
+ else
+ ilast->mAsmInsMode = ASMIM_ABSOLUTE;
+ }
+ }
+
+ if (ilast->mLeft && ilast->mLeft->mDecValue && ilast->mLeft->mDecValue->mType == DT_CONST_INTEGER && ilast->mLeft->mDecValue->mInteger < 256)
+ {
+ if (ilast->mAsmInsMode == ASMIM_ABSOLUTE && HasAsmInstructionMode(ilast->mAsmInsType, ASMIM_ZERO_PAGE))
+ ilast->mAsmInsMode = ASMIM_ZERO_PAGE;
+ else if (ilast->mAsmInsMode == ASMIM_ABSOLUTE_X && HasAsmInstructionMode(ilast->mAsmInsType, ASMIM_ZERO_PAGE_X))
+ ilast->mAsmInsMode = ASMIM_ZERO_PAGE_X;
+ else if (ilast->mAsmInsMode == ASMIM_ABSOLUTE_Y && HasAsmInstructionMode(ilast->mAsmInsType, ASMIM_ZERO_PAGE_Y))
+ ilast->mAsmInsMode = ASMIM_ZERO_PAGE_Y;
+ }
+
+ if (mScanner->mToken != TK_EOL)
+ {
+ mErrors->Error(mScanner->mLocation, "End of line expected");
+ }
+
+ while (mScanner->mToken != TK_EOL && mScanner->mToken != TK_EOF)
+ mScanner->NextToken();
+
+ offset += AsmInsSize(ilast->mAsmInsType, ilast->mAsmInsMode);
+
+ ilast->mRight = new Expression(mScanner->mLocation, EX_ASSEMBLER);
+ ilast = ilast->mRight;
+ }
+ }
+ else if (mScanner->mToken == TK_EOL)
+ {
+ mScanner->NextToken();
+ }
+ else
+ {
+ mErrors->Error(mScanner->mLocation, "Invalid assembler token");
+
+ while (mScanner->mToken != TK_EOL && mScanner->mToken != TK_EOF)
+ mScanner->NextToken();
+ }
+ }
+
+ ilast->mAsmInsType = ASMIT_RTS;
+ ilast->mAsmInsMode = ASMIM_IMPLIED;
+
+#if 0
+ offset = 0;
+ ilast = ifirst;
+ while (ilast)
+ {
+ if (ilast->mLeft && ilast->mLeft->mType == EX_UNDEFINED)
+ {
+ Declaration* dec = mScope->Lookup(ilast->mLeft->mDecValue->mIdent);
+ if (dec)
+ {
+ ilast->mLeft->mType = EX_CONSTANT;
+ ilast->mLeft->mDecValue = dec;
+ }
+ else
+ mErrors->Error(ilast->mLeft->mLocation, "Undefined label", ilast->mLeft->mDecValue->mIdent->mString);
+ }
+ offset += AsmInsSize(ilast->mAsmInsType, ilast->mAsmInsMode);
+
+ ilast = ilast->mRight;
+ }
+#endif
+
+ mScope = mScope->mParent;
+ dassm->mSize = offset;
+ dassm->mScope->mParent = nullptr;
+
+ mScanner->SetAssemblerMode(false);
+
+ return ifirst;
+}
+
+bool Parser::ConsumeToken(Token token)
+{
+ if (mScanner->mToken == token)
+ {
+ mScanner->NextToken();
+ return true;
+ }
+ else
+ {
+ char buffer[100];
+ sprintf_s(buffer, "%s expected", TokenNames[token]);
+ mErrors->Error(mScanner->mLocation, buffer);
+ return false;
+ }
+}
+
+bool Parser::ConsumeTokenIf(Token token)
+{
+ if (mScanner->mToken == token)
+ {
+ mScanner->NextToken();
+ return true;
+ }
+ else
+ return false;
+
+}
+
+void Parser::ParsePragma(void)
+{
+ if (mScanner->mToken == TK_IDENT)
+ {
+ if (!strcmp(mScanner->mTokenIdent->mString, "message"))
+ {
+ mScanner->NextToken();
+ ConsumeToken(TK_OPEN_PARENTHESIS);
+ if (mScanner->mToken == TK_STRING)
+ {
+ printf("%s\n", mScanner->mTokenString);
+ mScanner->NextToken();
+ }
+ ConsumeToken(TK_CLOSE_PARENTHESIS);
+ }
+ else if (!strcmp(mScanner->mTokenIdent->mString, "compile"))
+ {
+ mScanner->NextToken();
+ ConsumeToken(TK_OPEN_PARENTHESIS);
+ if (mScanner->mToken == TK_STRING)
+ {
+ mCompilationUnits->AddUnit(mScanner->mLocation, mScanner->mTokenString, mScanner->mLocation.mFileName);
+ mScanner->NextToken();
+ }
+ ConsumeToken(TK_CLOSE_PARENTHESIS);
+ }
+ else if (!strcmp(mScanner->mTokenIdent->mString, "intrinsic"))
+ {
+ mScanner->NextToken();
+ ConsumeToken(TK_OPEN_PARENTHESIS);
+ if (mScanner->mToken == TK_IDENT)
+ {
+ Declaration* dec = mGlobals->Lookup(mScanner->mTokenIdent);
+ if (dec && dec->mType == DT_CONST_FUNCTION)
+ dec->mFlags |= DTF_INTRINSIC;
+ else
+ mErrors->Error(mScanner->mLocation, "Intrinsic function not found");
+ mScanner->NextToken();
+ }
+ ConsumeToken(TK_CLOSE_PARENTHESIS);
+ }
+ else if (!strcmp(mScanner->mTokenIdent->mString, "startup"))
+ {
+ if (mCompilationUnits->mStartup)
+ mErrors->Error(mScanner->mLocation, "Duplicate startup pragma");
+
+ mScanner->NextToken();
+ ConsumeToken(TK_OPEN_PARENTHESIS);
+ if (mScanner->mToken == TK_IDENT)
+ {
+ Declaration* dec = mGlobals->Lookup(mScanner->mTokenIdent);
+ if (dec && dec->mType == DT_CONST_ASSEMBLER)
+ mCompilationUnits->mStartup = dec;
+ else
+ mErrors->Error(mScanner->mLocation, "Startup function not found");
+ mScanner->NextToken();
+ }
+ ConsumeToken(TK_CLOSE_PARENTHESIS);
+ }
+ else if (!strcmp(mScanner->mTokenIdent->mString, "bytecode"))
+ {
+ mScanner->NextToken();
+ ConsumeToken(TK_OPEN_PARENTHESIS);
+ Expression* exp = ParseAssemblerOperand();
+
+ ConsumeToken(TK_COMMA);
+ if (mScanner->mToken == TK_IDENT)
+ {
+ Declaration* dec = mGlobals->Lookup(mScanner->mTokenIdent);
+ if (dec && dec->mType == DT_CONST_ASSEMBLER)
+ {
+ mScanner->NextToken();
+ if (ConsumeTokenIf(TK_DOT))
+ {
+ if (mScanner->mToken == TK_IDENT)
+ {
+ Declaration* ndec = dec->mBase->mScope->Lookup(mScanner->mTokenIdent);
+ if (ndec)
+ dec = ndec;
+ else
+ mErrors->Error(mScanner->mLocation, "Label not found in assembler code");
+ mScanner->NextToken();
+ }
+ else
+ mErrors->Error(mScanner->mLocation, "Identifier expected");
+ }
+
+ if (exp->mType == EX_CONSTANT && exp->mDecValue->mType == DT_CONST_INTEGER && exp->mDecValue->mInteger >= 0 && exp->mDecValue->mInteger < 128)
+ {
+ if (mCompilationUnits->mByteCodes[exp->mDecValue->mInteger])
+ mErrors->Error(mScanner->mLocation, "Duplicate bytecode function");
+
+ mCompilationUnits->mByteCodes[exp->mDecValue->mInteger] = dec;
+ }
+ else
+ mErrors->Error(exp->mLocation, "Numeric value for byte code expected");
+ }
+ else
+ {
+ mErrors->Error(mScanner->mLocation, "Bytecode function not found");
+ mScanner->NextToken();
+ }
+
+ }
+ ConsumeToken(TK_CLOSE_PARENTHESIS);
+ }
+ else
+ {
+ mScanner->NextToken();
+ if (ConsumeTokenIf(TK_OPEN_PARENTHESIS))
+ {
+ while (mScanner->mToken != TK_CLOSE_PARENTHESIS && mScanner->mToken != TK_EOF)
+ mScanner->NextToken();
+ ConsumeToken(TK_CLOSE_PARENTHESIS);
+ }
+ mErrors->Error(mScanner->mLocation, "Unknown pragma, ignored", mScanner->mTokenIdent->mString);
+ }
+ }
+ else
+ mErrors->Error(mScanner->mLocation, "Invalid pragma directive");
+}
+
+void Parser::Parse(void)
+{
+ mLocalIndex = 0;
+
+ while (mScanner->mToken != TK_EOF)
+ {
+ if (mScanner->mToken == TK_PREP_PRAGMA)
+ {
+ mScanner->NextToken();
+ ParsePragma();
+ }
+ else if (mScanner->mToken == TK_ASM)
+ {
+ mScanner->NextToken();
+ if (mScanner->mToken == TK_IDENT)
+ {
+ const Ident* ident = mScanner->mTokenIdent;
+ mScanner->NextToken();
+
+ if (mScanner->mToken == TK_OPEN_BRACE)
+ {
+ mScanner->NextToken();
+
+ Expression* exp = ParseAssembler();
+
+ exp->mDecValue->mIdent = ident;
+ mScope->Insert(ident, exp->mDecValue);
+
+ if (mScanner->mToken == TK_CLOSE_BRACE)
+ mScanner->NextToken();
+ else
+ mErrors->Error(mScanner->mLocation, "'}' expected");
+ }
+ }
+ else
+ mErrors->Error(mScanner->mLocation, "Identifier expected");
+ }
+ else if (mScanner->mToken == TK_SEMICOLON)
+ mScanner->NextToken();
+ else
+ ParseDeclaration(true);
+ }
+}
diff --git a/oscar64/Parser.h b/oscar64/Parser.h
new file mode 100644
index 0000000..5e45edb
--- /dev/null
+++ b/oscar64/Parser.h
@@ -0,0 +1,66 @@
+#pragma once
+
+#include "Scanner.h"
+#include "Declaration.h"
+#include "CompilationUnits.h"
+
+class Parser
+{
+public:
+ Parser(Errors * errors, Scanner* scanner, CompilationUnits * compilationUnits);
+ ~Parser(void);
+
+ DeclarationScope * mGlobals, * mScope;
+ int mLocalIndex;
+ CompilationUnits * mCompilationUnits;
+
+ void Parse(void);
+protected:
+ bool ConsumeToken(Token token);
+ bool ConsumeTokenIf(Token token);
+
+ void ParsePragma(void);
+
+ Declaration* ParseBaseTypeDeclaration(uint32 flags);
+ Declaration* ParseDeclaration(bool variable);
+
+ Declaration* CopyConstantInitializer(int offset, Declaration* dtype, Expression* exp);
+ Expression* ParseInitExpression(Declaration* dtype);
+ Expression* ParseDeclarationExpression(void);
+
+ Declaration* ParsePostfixDeclaration(void);
+ Declaration* ReverseDeclaration(Declaration* odec, Declaration* bdec);
+
+ Expression* ParseFunction(Declaration* dec);
+ Expression* ParseAssembler(void);
+
+ Expression* ParseAssemblerBaseOperand(void);
+ Expression* ParseAssemblerAddOperand(void);
+ Expression* ParseAssemblerOperand(void);
+
+ Expression* ParseStatement(void);
+ Expression* ParseSwitchStatement(void);
+
+ Expression* ParseSimpleExpression(void);
+ Expression* ParsePrefixExpression(void);
+ Expression* ParsePostfixExpression(void);
+ Expression* ParseMulExpression(void);
+ Expression* ParseAddExpression(void);
+ Expression* ParseShiftExpression(void);
+ Expression* ParseRelationalExpression(void);
+ Expression* ParseBinaryAndExpression(void);
+ Expression* ParseBinaryXorExpression(void);
+ Expression* ParseBinaryOrExpression(void);
+ Expression* ParseLogicAndExpression(void);
+ Expression* ParseLogicOrExpression(void);
+ Expression* ParseConditionalExpression(void);
+ Expression* ParseAssignmentExpression(void);
+ Expression* ParseExpression(void);
+ Expression* ParseRExpression(void);
+ Expression* ParseListExpression(void);
+
+ Expression* ParseParenthesisExpression(void);
+
+ Errors* mErrors;
+ Scanner* mScanner;
+};
diff --git a/oscar64/Preprocessor.cpp b/oscar64/Preprocessor.cpp
new file mode 100644
index 0000000..2e49773
--- /dev/null
+++ b/oscar64/Preprocessor.cpp
@@ -0,0 +1,170 @@
+#include "Preprocessor.h"
+#include
+
+SourcePath::SourcePath(const char* path)
+{
+ strcpy_s(mPathName, path);
+}
+
+SourcePath::~SourcePath(void)
+{
+
+}
+
+bool SourceFile::ReadLine(char* line)
+{
+ if (mFile)
+ {
+ if (fgets(line, 1024, mFile))
+ return true;
+
+ fclose(mFile);
+ mFile = nullptr;
+ }
+
+ return false;
+}
+
+SourceFile::SourceFile(void)
+ : mFile(nullptr), mFileName{ 0 }
+{
+
+}
+
+SourceFile::~SourceFile(void)
+{
+ if (mFile)
+ {
+ fclose(mFile);
+ mFile = nullptr;
+ }
+}
+
+bool SourceFile::Open(const char* name, const char* path)
+{
+ strcpy_s(mFileName, path);
+ int n = strlen(mFileName);
+
+ if (n > 0 && mFileName[n - 1] != '/')
+ {
+ mFileName[n++] = '/';
+ mFileName[n] = 0;
+ }
+
+ strcat_s(mFileName + n, sizeof(mFileName) - n, name);
+
+ if (!fopen_s(&mFile, mFileName, "r"))
+ return true;
+
+ return false;
+}
+
+void SourceFile::Close(void)
+{
+ if (mFile)
+ {
+ fclose(mFile);
+ mFile = nullptr;
+ }
+}
+
+bool Preprocessor::NextLine(void)
+{
+ int s = 0;
+ while (mSource->ReadLine(mLine + s))
+ {
+ mLocation.mLine++;
+
+ s = strlen(mLine);
+ while (s > 0 && mLine[s - 1] == '\n')
+ s--;
+ if (s == 0 || mLine[s - 1] != '\\')
+ return true;
+ s--;
+ }
+
+ return false;
+}
+
+bool Preprocessor::OpenSource(const char* name, bool local)
+{
+ if (mSource)
+ mSource->mLocation = mLocation;
+
+ SourceFile * source = new SourceFile();
+
+ bool ok = false;
+
+ if (source->Open(name, ""))
+ ok = true;
+
+ if (!ok && local && mSource)
+ {
+ char lpath[200];
+ strcpy_s(lpath, mSource->mFileName);
+ int i = strlen(lpath);
+ while (i > 0 && lpath[i - 1] != '/')
+ i--;
+ lpath[i] = 0;
+
+ if (source->Open(name, lpath))
+ ok = true;
+ }
+
+ SourcePath* p = mPaths;
+ while (!ok && p)
+ {
+ if (source->Open(name, p->mPathName))
+ ok = true;
+ else
+ p = p->mNext;
+ }
+
+ if (ok)
+ {
+ printf("Reading %s\n", source->mFileName);
+ source->mUp = mSource;
+ mSource = source;
+ mLocation.mFileName = mSource->mFileName;
+ mLocation.mLine = 0;
+ mLine[0] = 0;
+
+ return true;
+ }
+ else
+ return false;
+}
+
+bool Preprocessor::CloseSource(void)
+{
+ if (mSource)
+ {
+ mSource = mSource->mUp;
+ if (mSource)
+ {
+ mLocation = mSource->mLocation;
+ mLine[0] = 0;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+Preprocessor::Preprocessor(Errors* errors)
+ : mSource(nullptr), mSourceList(nullptr), mPaths(nullptr), mErrors(errors)
+{
+
+}
+
+Preprocessor::~Preprocessor(void)
+{
+}
+
+void Preprocessor::AddPath(const char* path)
+{
+ SourcePath* sp = new SourcePath(path);
+ sp->mNext = mPaths;
+ mPaths = sp;
+}
+
diff --git a/oscar64/Preprocessor.h b/oscar64/Preprocessor.h
new file mode 100644
index 0000000..28d25e8
--- /dev/null
+++ b/oscar64/Preprocessor.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#include "Errors.h"
+#include
+
+class SourceFile
+{
+public:
+ char mFileName[200];
+
+ SourceFile * mUp, * mNext;
+ Location mLocation;
+
+ bool ReadLine(char* line);
+
+ SourceFile(void);
+ ~SourceFile(void);
+
+ bool Open(const char* name, const char * path);
+ void Close(void);
+protected:
+ FILE* mFile;
+};
+
+class SourcePath
+{
+public:
+ char mPathName[200];
+
+ SourcePath* mNext;
+
+ SourcePath(const char* path);
+ ~SourcePath(void);
+};
+
+class Preprocessor
+{
+public:
+ char mLine[32768];
+
+ Location mLocation;
+ Errors* mErrors;
+
+ SourceFile* mSource, * mSourceList;
+ SourcePath* mPaths;
+
+ void AddPath(const char* path);
+ bool NextLine(void);
+
+ bool OpenSource(const char* name, bool local);
+ bool CloseSource(void);
+
+ Preprocessor(Errors * errors);
+ ~Preprocessor(void);
+};
diff --git a/oscar64/Scanner.cpp b/oscar64/Scanner.cpp
new file mode 100644
index 0000000..463297d
--- /dev/null
+++ b/oscar64/Scanner.cpp
@@ -0,0 +1,1260 @@
+#include "Scanner.h"
+#include
+#include
+#include
+#include
+
+
+const char* TokenNames[] = {
+ "tk_none",
+ "tk_eof",
+ "tk_error",
+ "tk_eols",
+
+ "'if'",
+ "'else'",
+ "'while'",
+ "'do'",
+ "'for'",
+ "'void'",
+ "'int'",
+ "'char'",
+ "'float'",
+ "'unsigned'",
+ "'switch'",
+ "'case'",
+ "'default'",
+ "'break'",
+ "'return'",
+ "'short'",
+ "'long'",
+ "'continue'",
+ "'integer'",
+ "'bool'",
+ "'const'",
+ "'volatile'",
+ "'typedef'",
+ "'struct'",
+ "'union'",
+ "'enum'",
+ "'sizeof'",
+
+ "__asm",
+
+ "number",
+ "string literal",
+ "identifier",
+ "'true'",
+ "'false'",
+ "'nullptr'",
+
+ "'+'",
+ "'-'",
+ "'*'",
+ "'/'",
+ "'%'",
+
+ "'<<'",
+ "'>>'",
+
+ "'++'",
+ "'--'",
+
+ "'!'",
+ "'&&'",
+ "'||'",
+
+ "'~'",
+ "'&'",
+ "'|'",
+ "'^'",
+
+ "'=='",
+ "'!='",
+ "'>'",
+ "'>='",
+ "'<'",
+ "'<='",
+
+ "'='",
+ "'+='",
+ "'-='",
+ "'*='",
+ "'/='",
+ "'%='",
+ "'<<='",
+ "'>>='",
+ "'&='",
+ "'^='",
+ "'|='",
+
+ "'->'",
+ "'#'",
+ "'$'",
+
+ "'('",
+ "')'",
+
+ "'{'",
+ "'}'",
+
+ "'['",
+ "']'",
+
+ "'.'",
+ "'..'",
+ "'...'",
+ "','",
+ "';'",
+ "':'",
+ "'?'",
+
+ "'#define'",
+ "'#include'",
+ "'#if'",
+ "'#elif'",
+ "'#else'",
+ "'#endif'",
+ "'#ifdef'",
+ "'#ifndef'",
+ "'#pragma'"
+};
+
+
+Macro::Macro(const Ident* ident)
+ : mIdent(ident), mString(nullptr), mNumArguments(0)
+{
+
+}
+
+Macro::~Macro(void)
+{
+
+}
+
+void Macro::SetString(const char* str)
+{
+ int s = strlen(str);
+ SetString(str, s);
+}
+
+void Macro::SetString(const char* str, int length)
+{
+ char* nstr = new char[length + 2];
+
+ while (*str != 0 && *str <= ' ')
+ {
+ length--;
+ str++;
+ }
+ while (length > 0 && str[length - 1] <= ' ')
+ length--;
+
+ if (length > 0)
+ memcpy(nstr, str, length);
+
+ nstr[length] = ' ';
+ nstr[length + 1] = 0;
+ mString = nstr;
+}
+
+
+void Macro::AddArgument(const Ident * ident)
+{
+ mArguments[mNumArguments++] = ident;
+}
+
+MacroDict::MacroDict(void)
+{
+ mHashSize = 0;
+ mHashFill = 0;
+ mHash = nullptr;
+}
+
+MacroDict::~MacroDict(void)
+{
+ delete[] mHash;
+}
+
+void MacroDict::Insert(Macro * macro)
+{
+ if (!mHash)
+ {
+ mHashSize = 16;
+ mHashFill = 0;
+ mHash = new MacroPtr[mHashSize];
+ for (int i = 0; i < mHashSize; i++)
+ mHash[i] = nullptr;
+ }
+
+ int hm = mHashSize - 1;
+ int hi = macro->mIdent->mHash & hm;
+
+ while (mHash[hi])
+ {
+ if (macro->mIdent == mHash[hi]->mIdent)
+ {
+ mHash[hi] = macro;
+ return;
+ }
+
+ hi = (hi + 1) & hm;
+ }
+
+ mHash[hi] = macro;
+ mHashFill++;
+
+ if (2 * mHashFill >= mHashSize)
+ {
+ int size = mHashSize;
+ Macro ** entries = mHash;
+ mHashSize *= 2;
+ mHashFill = 0;
+ mHash = new MacroPtr[mHashSize];
+ for (int i = 0; i < mHashSize; i++)
+ mHash[i] = nullptr;
+
+ for (int i = 0; i < size; i++)
+ {
+ if (entries[i])
+ Insert(entries[i]);
+ }
+ delete[] entries;
+ }
+}
+
+Macro* MacroDict::Lookup(const Ident* ident)
+{
+ if (mHashSize > 0)
+ {
+ int hm = mHashSize - 1;
+ int hi = ident->mHash & hm;
+
+ while (mHash[hi])
+ {
+ if (ident == mHash[hi]->mIdent)
+ return mHash[hi];
+ hi = (hi + 1) & hm;
+ }
+ }
+
+ return nullptr;
+}
+
+
+
+Scanner::Scanner(Errors* errors, Preprocessor* preprocessor)
+ : mErrors(errors), mPreprocessor(preprocessor)
+{
+ mOffset = 0;
+ mLine = mPreprocessor->mLine;
+ mPrepCondition = 0;
+ mPrepPending = 0;
+ mAssemblerMode = false;
+ mMacroExpansion = nullptr;
+
+ mDefines = new MacroDict();
+ mDefineArguments = nullptr;
+
+ NextChar();
+ NextToken();
+
+ assert(sizeof(TokenNames) == NUM_TOKENS * sizeof(char*));
+}
+
+Scanner::~Scanner(void)
+{
+ delete mDefines;
+}
+
+
+const char* Scanner::TokenName(Token token) const
+{
+ return TokenNames[token];
+}
+
+
+void Scanner::SetAssemblerMode(bool mode)
+{
+ mAssemblerMode = mode;
+}
+
+static bool IsIdentChar(char c)
+{
+ if (c >= 'a' && c <= 'z')
+ return true;
+ else if (c >= 'A' && c <= 'Z')
+ return true;
+ else if (c >= '0' && c <= '9')
+ return true;
+ else if (c == '_')
+ return true;
+ else
+ return false;
+}
+
+static inline bool IsWhitespace(char ch)
+{
+ return ch <= 32;
+}
+
+static inline bool IsLineBreak(char ch)
+{
+ return ch == '\n' || ch == '\r';
+}
+
+static inline bool IsAlpha(char ch)
+{
+ return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_';
+}
+
+static inline bool IsAlphaNumeric(char ch)
+{
+ return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_' || (ch >= '0' && ch <= '9');
+}
+
+
+static inline bool IsNumeric(char ch)
+{
+ return ch >= '0' && ch <= '9';
+}
+
+
+static inline bool IsHex(char ch)
+{
+ return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F');
+}
+
+static inline int HexValue(char ch)
+{
+ if (ch >= '0' && ch <= '9')
+ return ch - '0';
+ else if (ch >= 'a' && ch <= 'f')
+ return ch - 'a' + 10;
+ else if (ch >= 'A' && ch <= 'F')
+ return ch - 'A' + 10;
+ else
+ return 0;
+}
+
+void Scanner::NextToken(void)
+{
+ for (;;)
+ {
+ NextRawToken();
+ if (mToken == TK_PREP_ENDIF)
+ {
+ if (mPrepCondition > 0)
+ mPrepCondition--;
+ else if (mPrepPending > 0)
+ mPrepPending--;
+ else
+ mErrors->Error(mLocation, "Unexpected #endif");
+ }
+ else if (mToken == TK_EOF)
+ {
+ if (!mPreprocessor->CloseSource())
+ return;
+ mToken = TK_NONE;
+ mOffset = 0;
+ }
+ else if (mPrepCondition > 0)
+ {
+ if (mToken == TK_PREP_IFDEF || mToken == TK_PREP_IFNDEF)
+ mPrepCondition++;
+ }
+ else if (mToken == TK_PREP_INCLUDE)
+ {
+ NextRawToken();
+ if (mToken == TK_STRING)
+ {
+ if (!mPreprocessor->OpenSource(mTokenString, true))
+ mErrors->Error(mLocation, "Could not open source file", mTokenString);
+ }
+ else if (mToken == TK_LESS_THAN)
+ {
+ mOffset--;
+ StringToken('>');
+ if (!mPreprocessor->OpenSource(mTokenString, false))
+ mErrors->Error(mLocation, "Could not open source file", mTokenString);
+ }
+ }
+ else if (mToken == TK_PREP_DEFINE)
+ {
+ NextRawToken();
+ if (mToken == TK_IDENT)
+ {
+ Macro* macro = new Macro(mTokenIdent);
+
+ if (mTokenChar == '(')
+ {
+ NextRawToken();
+
+ // Macro with argument
+ do
+ {
+ NextRawToken();
+ if (mToken == TK_IDENT)
+ {
+ macro->AddArgument(mTokenIdent);
+ NextRawToken();
+ }
+ else
+ mErrors->Error(mLocation, "Invalid define argument");
+
+ } while (mToken == TK_COMMA);
+
+ if (mToken == TK_CLOSE_PARENTHESIS)
+ {
+ // No need to goto next token, mOffset is already behind it
+ }
+ else
+ mErrors->Error(mLocation, "')' expected in defined parameter list");
+ }
+
+ macro->SetString(mLine + mOffset);
+ int slen = strlen(mLine + mOffset);
+ mDefines->Insert(macro);
+ mOffset += slen;
+ }
+ }
+ else if (mToken == TK_PREP_IFDEF)
+ {
+ NextRawToken();
+ if (mToken == TK_IDENT)
+ {
+ Macro * def = mDefines->Lookup(mTokenIdent);
+ if (def)
+ mPrepPending++;
+ else
+ mPrepCondition++;
+ }
+ }
+ else if (mToken == TK_PREP_IFNDEF)
+ {
+ NextRawToken();
+ if (mToken == TK_IDENT)
+ {
+ Macro * def = mDefines->Lookup(mTokenIdent);
+ if (!def)
+ mPrepPending++;
+ else
+ mPrepCondition++;
+ }
+ }
+ else if (mToken == TK_IDENT)
+ {
+ Macro* def = nullptr;
+ if (mDefineArguments)
+ def = mDefineArguments->Lookup(mTokenIdent);
+ if (!def)
+ def = mDefines->Lookup(mTokenIdent);
+
+ if (def)
+ {
+ MacroExpansion* ex = new MacroExpansion();
+ ex->mDefinedArguments = mDefineArguments;
+ if (def->mNumArguments)
+ {
+ mDefineArguments = new MacroDict();
+ NextRawToken();
+ if (mToken == TK_OPEN_PARENTHESIS)
+ {
+ mOffset--;
+ for (int i = 0; i < def->mNumArguments; i++)
+ {
+ int offset = mOffset;
+ int level = 0;
+ bool quote = false;
+ while (mLine[offset] && (quote || level > 0 || (mLine[offset] != ',' && mLine[offset] != ')')))
+ {
+ if (mLine[offset] == '"')
+ {
+ quote = !quote;
+ }
+ else if (mLine[offset] == '(')
+ {
+ level++;
+ }
+ else if (mLine[offset] == ')')
+ {
+ level--;
+ }
+ offset++;
+ }
+ Macro* arg = new Macro(def->mArguments[i]);
+ arg->SetString(mLine + mOffset, offset - mOffset);
+ mDefineArguments->Insert(arg);
+ mOffset = offset;
+ if (i + 1 != def->mNumArguments)
+ {
+ if (mLine[mOffset] == ',')
+ mOffset++;
+ else
+ mErrors->Error(mLocation, "Invalid define expansion argument");
+ }
+ else
+ {
+ if (mLine[mOffset] == ')')
+ mOffset++;
+ else
+ mErrors->Error(mLocation, "Invalid define expansion closing argument");
+ }
+ }
+ }
+ else
+ mErrors->Error(mLocation, "Missing arguments for macro expansion");
+ NextChar();
+ }
+ else
+ mDefineArguments = nullptr;
+
+ ex->mLine = mLine;
+ ex->mOffset = mOffset;
+ ex->mLink = mMacroExpansion;
+ ex->mChar = mTokenChar;
+
+ mMacroExpansion = ex;
+ mLine = def->mString;
+ mOffset = 0;
+ NextChar();
+ }
+ else
+ return;
+ }
+ else
+ return;
+ }
+}
+
+void Scanner::NextRawToken(void)
+{
+ if (mToken != TK_EOF)
+ {
+ Token pt = mToken;
+
+ mToken = TK_ERROR;
+
+ while (IsWhitespace(mTokenChar))
+ {
+ if (mAssemblerMode && mTokenChar == '\n')
+ {
+ mToken = TK_EOL;
+ NextChar();
+ return;
+ }
+ if (!NextChar())
+ {
+ mToken = TK_EOF;
+ return;
+ }
+ }
+
+ mLocation = mPreprocessor->mLocation;
+ mLocation.mColumn = mOffset;
+
+ switch (mTokenChar)
+ {
+ case '+':
+ mToken = TK_ADD;
+ NextChar();
+ if (mTokenChar == '+')
+ {
+ NextChar();
+ mToken = TK_INC;
+ }
+ else if (mTokenChar == '=')
+ {
+ NextChar();
+ mToken = TK_ASSIGN_ADD;
+ }
+ break;
+ case '-':
+ mToken = TK_SUB;
+ NextChar();
+ if (mTokenChar == '-')
+ {
+ NextChar();
+ mToken = TK_DEC;
+ }
+ else if (mTokenChar == '=')
+ {
+ NextChar();
+ mToken = TK_ASSIGN_SUB;
+ }
+ else if (mTokenChar == '>')
+ {
+ NextChar();
+ mToken = TK_ARROW;
+ }
+ break;
+ case '*':
+ mToken = TK_MUL;
+ NextChar();
+ if (mTokenChar == '=')
+ {
+ NextChar();
+ mToken = TK_ASSIGN_MUL;
+ }
+ break;
+ case '/':
+ mToken = TK_DIV;
+ NextChar();
+ if (mTokenChar == '*')
+ {
+ bool first = true;
+ while (first || mTokenChar != '/')
+ {
+ if (mTokenChar == '*')
+ first = false;
+ else
+ first = true;
+ if (!NextChar())
+ {
+ mToken = TK_ERROR;
+ Error("Multiline comment not closed");
+ return;
+ }
+ }
+ NextChar();
+ NextToken();
+ }
+ else if (mTokenChar == '/')
+ {
+ NextChar();
+ while (!IsLineBreak(mTokenChar) && NextChar())
+ ;
+ NextToken();
+ }
+ else if (mTokenChar == '=')
+ {
+ NextChar();
+ mToken = TK_ASSIGN_DIV;
+ }
+ break;
+ case '%':
+ mToken = TK_MOD;
+ NextChar();
+ if (mTokenChar == '=')
+ {
+ NextChar();
+ mToken = TK_ASSIGN_MOD;
+ }
+ break;
+ case '~':
+ mToken = TK_BINARY_NOT;
+ NextChar();
+ break;
+ case '^':
+ mToken = TK_BINARY_XOR;
+ NextChar();
+ if (mTokenChar == '=')
+ {
+ NextChar();
+ mToken = TK_ASSIGN_XOR;
+ }
+ break;
+
+ case '&':
+ mToken = TK_BINARY_AND;
+ NextChar();
+ if (mTokenChar == '&')
+ {
+ NextChar();
+ mToken = TK_LOGICAL_AND;
+ }
+ else if (mTokenChar == '=')
+ {
+ NextChar();
+ mToken = TK_ASSIGN_AND;
+ }
+ break;
+ case '|':
+ mToken = TK_BINARY_OR;
+ NextChar();
+ if (mTokenChar == '|')
+ {
+ NextChar();
+ mToken = TK_LOGICAL_OR;
+ }
+ else if (mTokenChar == '=')
+ {
+ NextChar();
+ mToken = TK_ASSIGN_OR;
+ }
+ break;
+
+ case '(':
+ mToken = TK_OPEN_PARENTHESIS;
+ NextChar();
+ break;
+ case ')':
+ mToken = TK_CLOSE_PARENTHESIS;
+ NextChar();
+ break;
+ case '{':
+ mToken = TK_OPEN_BRACE;
+ NextChar();
+ break;
+ case '}':
+ mToken = TK_CLOSE_BRACE;
+ NextChar();
+ break;
+ case '[':
+ mToken = TK_OPEN_BRACKET;
+ NextChar();
+ break;
+ case ']':
+ mToken = TK_CLOSE_BRACKET;
+ NextChar();
+ break;
+
+ case '.':
+ mToken = TK_DOT;
+ NextChar();
+ if (mTokenChar == '.')
+ {
+ NextChar();
+ mToken = TK_DOTDOT;
+ if (mTokenChar == '.')
+ {
+ NextChar();
+ mToken = TK_ELLIPSIS;
+ }
+ }
+ break;
+ case ',':
+ mToken = TK_COMMA;
+ NextChar();
+ break;
+ case ';':
+ mToken = TK_SEMICOLON;
+ NextChar();
+ break;
+ case ':':
+ mToken = TK_COLON;
+ NextChar();
+ break;
+ case '?':
+ mToken = TK_QUESTIONMARK;
+ NextChar();
+ break;
+
+ case '=':
+ mToken = TK_ASSIGN;
+ NextChar();
+ if (mTokenChar == '=')
+ {
+ mToken = TK_EQUAL;
+ NextChar();
+ }
+
+ break;
+ case '!':
+ mToken = TK_LOGICAL_NOT;
+ NextChar();
+ if (mTokenChar == '=')
+ {
+ mToken = TK_NOT_EQUAL;
+ NextChar();
+ }
+ break;
+ case '<':
+ mToken = TK_LESS_THAN;
+ NextChar();
+ if (mTokenChar == '=')
+ {
+ NextChar();
+ mToken = TK_LESS_EQUAL;
+ }
+ else if (mTokenChar == '<')
+ {
+ NextChar();
+ mToken = TK_LEFT_SHIFT;
+ if (mTokenChar == '=')
+ {
+ NextChar();
+ mToken = TK_ASSIGN_SHL;
+ }
+ }
+ break;
+ case '>':
+ mToken = TK_GREATER_THAN;
+ NextChar();
+ if (mTokenChar == '=')
+ {
+ NextChar();
+ mToken = TK_GREATER_EQUAL;
+ }
+ else if (mTokenChar == '>')
+ {
+ mToken = TK_RIGHT_SHIFT;
+ NextChar();
+ if (mTokenChar == '=')
+ {
+ NextChar();
+ mToken = TK_ASSIGN_SHR;
+ }
+ }
+ break;
+
+ case '\'':
+ CharToken();
+ break;
+ case '"':
+ StringToken(mTokenChar);
+ break;
+
+ case '#':
+ {
+ if (!mAssemblerMode)
+ {
+ int n = 0;
+ char tkprep[128];
+
+ while (NextChar() && IsAlpha(mTokenChar))
+ {
+ tkprep[n++] = mTokenChar;
+ }
+ tkprep[n] = 0;
+
+ if (!strcmp(tkprep, "define"))
+ mToken = TK_PREP_DEFINE;
+ else if (!strcmp(tkprep, "include"))
+ mToken = TK_PREP_INCLUDE;
+ else if (!strcmp(tkprep, "if"))
+ mToken = TK_PREP_IF;
+ else if (!strcmp(tkprep, "ifdef"))
+ mToken = TK_PREP_IFDEF;
+ else if (!strcmp(tkprep, "ifndef"))
+ mToken = TK_PREP_IFNDEF;
+ else if (!strcmp(tkprep, "elif"))
+ mToken = TK_PREP_ELIF;
+ else if (!strcmp(tkprep, "else"))
+ mToken = TK_PREP_ELSE;
+ else if (!strcmp(tkprep, "endif"))
+ mToken = TK_PREP_ENDIF;
+ else if (!strcmp(tkprep, "pragma"))
+ mToken = TK_PREP_PRAGMA;
+ else
+ mErrors->Error(mLocation, "Invalid preprocessor command", tkprep);
+ }
+ else
+ {
+ NextChar();
+ mToken = TK_HASH;
+ }
+ break;
+ }
+
+ case '$':
+
+ if (mAssemblerMode)
+ {
+ int n = 0;
+ __int64 mant = 0;
+ while (NextChar())
+ {
+ if (mTokenChar >= '0' && mTokenChar <= '9')
+ mant = mant * 16 + (int)mTokenChar - (int)'0';
+ else if (mTokenChar >= 'a' && mTokenChar <= 'f')
+ mant = mant * 16 + 10 + (int)mTokenChar - (int)'a';
+ else if (mTokenChar >= 'A' && mTokenChar <= 'F')
+ mant = mant * 16 + 10 + (int)mTokenChar - (int)'A';
+ else
+ break;
+ n++;
+ }
+
+ if (n == 0)
+ mErrors->Error(mLocation, "Missing digits in hex constant");
+
+ mToken = TK_INTEGER;
+ mTokenInteger = mant;
+ }
+ else
+ {
+ NextChar();
+ mToken = TK_DOLLAR;
+ }
+ break;
+
+ default:
+ if (mTokenChar >= '0' && mTokenChar <= '9')
+ {
+ ParseNumberToken();
+ }
+ else if (mTokenChar >= 'A' && mTokenChar <= 'Z' || mTokenChar >= 'a' && mTokenChar <= 'z' || mTokenChar == '_')
+ {
+ int n = 0;
+ char tkident[128];
+ for (;;)
+ {
+ if (IsIdentChar(mTokenChar))
+ {
+ tkident[n++] = mTokenChar;
+ NextChar();
+ }
+ else
+ break;
+ }
+ tkident[n] = 0;
+
+ if (!strcmp(tkident, "true"))
+ mToken = TK_TRUE;
+ else if (!strcmp(tkident, "false"))
+ mToken = TK_FALSE;
+ else if (!strcmp(tkident, "nullptr"))
+ mToken = TK_NULL;
+ else if (!strcmp(tkident, "int"))
+ mToken = TK_INT;
+ else if (!strcmp(tkident, "float"))
+ mToken = TK_FLOAT;
+ else if (!strcmp(tkident, "bool"))
+ mToken = TK_BOOL;
+ else if (!strcmp(tkident, "char"))
+ mToken = TK_CHAR;
+ else if (!strcmp(tkident, "short"))
+ mToken = TK_SHORT;
+ else if (!strcmp(tkident, "long"))
+ mToken = TK_LONG;
+ else if (!strcmp(tkident, "unsigned"))
+ mToken = TK_UNSIGNED;
+ else if (!strcmp(tkident, "const"))
+ mToken = TK_CONST;
+ else if (!strcmp(tkident, "volatile"))
+ mToken = TK_VOLATILE;
+ else if (!strcmp(tkident, "if"))
+ mToken = TK_IF;
+ else if (!strcmp(tkident, "else"))
+ mToken = TK_ELSE;
+ else if (!strcmp(tkident, "while"))
+ mToken = TK_WHILE;
+ else if (!strcmp(tkident, "do"))
+ mToken = TK_DO;
+ else if (!strcmp(tkident, "for"))
+ mToken = TK_FOR;
+ else if (!strcmp(tkident, "switch"))
+ mToken = TK_SWITCH;
+ else if (!strcmp(tkident, "case"))
+ mToken = TK_CASE;
+ else if (!strcmp(tkident, "default"))
+ mToken = TK_DEFAULT;
+ else if (!strcmp(tkident, "break"))
+ mToken = TK_BREAK;
+ else if (!strcmp(tkident, "continue"))
+ mToken = TK_CONTINUE;
+ else if (!strcmp(tkident, "return"))
+ mToken = TK_RETURN;
+ else if (!strcmp(tkident, "void"))
+ mToken = TK_VOID;
+ else if (!strcmp(tkident, "struct"))
+ mToken = TK_STRUCT;
+ else if (!strcmp(tkident, "union"))
+ mToken = TK_UNION;
+ else if (!strcmp(tkident, "enum"))
+ mToken = TK_ENUM;
+ else if (!strcmp(tkident, "sizeof"))
+ mToken = TK_SIZEOF;
+ else if (!strcmp(tkident, "typedef"))
+ mToken = TK_TYPEDEF;
+ else if (!strcmp(tkident, "__asm"))
+ mToken = TK_ASM;
+ else
+ {
+ mToken = TK_IDENT;
+ mTokenIdent = Ident::Unique(tkident);
+ }
+ }
+ else
+ {
+ NextChar();
+ }
+ break;
+ }
+ }
+ else
+ {
+ mToken = TK_EOF;
+ }
+
+}
+
+void Scanner::Warning(const char* error)
+{
+ mErrors->Warning(mLocation, error);
+}
+
+void Scanner::Error(const char* error)
+{
+ mErrors->Error(mLocation, error);
+}
+
+void Scanner::StringToken(char terminator)
+{
+ int n = 0;
+
+ while (mLine[mOffset] && mLine[mOffset] != terminator && mLine[mOffset] != '\n')
+ {
+ mTokenChar = mLine[mOffset++];
+
+ if (mTokenChar == '\\' && mLine[mOffset])
+ {
+ mTokenChar = mLine[mOffset++];
+ switch (mTokenChar)
+ {
+ case '0':
+ mTokenChar = '\0';
+ break;
+ case 'n':
+ mTokenChar = '\n';
+ break;
+ case 'r':
+ mTokenChar = '\r';
+ break;
+ case 't':
+ mTokenChar = '\t';
+ break;
+ case 'f':
+ mTokenChar = '\f';
+ break;
+ case 'b':
+ mTokenChar = '\b';
+ break;
+ case 'v':
+ mTokenChar = '\v';
+ break;
+ case 'x':
+ {
+ char c0 = mLine[mOffset++];
+ char c1 = mLine[mOffset++];
+
+ if (IsHex(c0) && IsHex(c1))
+ mTokenChar = 16 * HexValue(c0) + HexValue(c1);
+ else
+ mErrors->Error(mLocation, "Invalid hex escape code");
+ }
+ break;
+ default:
+ ;
+ }
+ }
+
+ mTokenString[n++] = mTokenChar;
+ }
+
+ mTokenString[n] = 0;
+
+ if (mLine[mOffset] && mLine[mOffset] == terminator)
+ {
+ mToken = TK_STRING;
+ mOffset++;
+ NextChar();
+ }
+ else
+ {
+ NextChar();
+ Error("String constant not terminated");
+ mToken = TK_ERROR;
+ }
+
+}
+
+void Scanner::CharToken(void)
+{
+ int n = 0;
+
+ mTokenChar = mLine[mOffset++];
+
+ if (mTokenChar == '\\' && mLine[mOffset])
+ {
+ mTokenChar = mLine[mOffset++];
+ switch (mTokenChar)
+ {
+ case '0':
+ mTokenChar = '\0';
+ break;
+ case 'n':
+ mTokenChar = '\n';
+ break;
+ case 'r':
+ mTokenChar = '\r';
+ break;
+ case 't':
+ mTokenChar = '\t';
+ break;
+ case 'f':
+ mTokenChar = '\f';
+ break;
+ case 'b':
+ mTokenChar = '\b';
+ break;
+ case 'v':
+ mTokenChar = '\v';
+ break;
+ case 'x':
+ {
+ char c0 = mLine[mOffset++];
+ char c1 = mLine[mOffset++];
+
+ if (IsHex(c0) && IsHex(c1))
+ mTokenChar = 16 * HexValue(c0) + HexValue(c1);
+ else
+ mErrors->Error(mLocation, "Invalid hex escape code");
+ }
+ break;
+ default:
+ ;
+ }
+ }
+
+ mTokenInteger = mTokenChar;
+
+ if (mLine[mOffset] && mLine[mOffset] == '\'')
+ {
+ mToken = TK_INTEGER;
+ mOffset++;
+ NextChar();
+ }
+ else
+ {
+ NextChar();
+ Error("Character constant not terminated");
+ mToken = TK_ERROR;
+ }
+}
+
+bool Scanner::NextChar(void)
+{
+ while (!(mLine[mOffset]))
+ {
+ if (mMacroExpansion)
+ {
+ MacroExpansion* mac = mMacroExpansion->mLink;
+ delete mDefineArguments;
+
+ mLine = mMacroExpansion->mLine;
+ mOffset = mMacroExpansion->mOffset;
+ mTokenChar = mMacroExpansion->mChar;
+ mDefineArguments = mMacroExpansion->mDefinedArguments;
+
+ delete mMacroExpansion;
+ mMacroExpansion = mac;
+ return true;
+ }
+ else if (mPreprocessor->NextLine())
+ {
+ mOffset = 0;
+ }
+ else
+ {
+ mTokenChar = 0;
+ return false;
+ }
+ }
+
+ mTokenChar = mLine[mOffset++];
+ return true;
+}
+
+void Scanner::ParseNumberToken(void)
+{
+ unsigned __int64 mant = (int)mTokenChar - (int)'0';
+
+ NextChar();
+
+ if (mant == 0 && (mTokenChar == 'x' || mTokenChar == 'X'))
+ {
+ int n = 0;
+ while (NextChar())
+ {
+ if (mTokenChar >= '0' && mTokenChar <= '9')
+ mant = mant * 16 + (int)mTokenChar - (int)'0';
+ else if (mTokenChar >= 'a' && mTokenChar <= 'f')
+ mant = mant * 16 + 10 + (int)mTokenChar - (int)'a';
+ else if (mTokenChar >= 'A' && mTokenChar <= 'F')
+ mant = mant * 16 + 10 + (int)mTokenChar - (int)'A';
+ else
+ break;
+ n++;
+ }
+
+ if (n == 0)
+ Error("Missing digits in hex constant");
+
+ mToken = TK_INTEGER;
+ mTokenInteger = mant;
+ }
+ else
+ {
+ int n = 0;
+ if (mTokenChar >= '0' && mTokenChar <= '9')
+ {
+ mant = mant * 10 + (int)mTokenChar - (int)'0';
+ while (NextChar())
+ {
+ if (mTokenChar >= '0' && mTokenChar <= '9')
+ mant = mant * 10 + (int)mTokenChar - (int)'0';
+ else
+ break;
+ n++;
+ }
+ }
+
+ if (mTokenChar != '.')
+ {
+ mToken = TK_INTEGER;
+ mTokenInteger = mant;
+ }
+ else
+ {
+ double facc = mant, fract = 1.0;
+
+ NextChar();
+
+ while (mTokenChar >= '0' && mTokenChar <= '9')
+ {
+ facc *= 10;
+ fract *= 10;
+ facc += (int)mTokenChar - (int)'0';
+ NextChar();
+ }
+
+ facc /= fract;
+
+ if (mTokenChar == 'e' || mTokenChar == 'E')
+ {
+ NextChar();
+ bool sign = false;
+ if (mTokenChar == '+')
+ NextChar();
+ else if (mTokenChar == '-')
+ {
+ NextChar();
+ sign = true;
+ }
+
+ int expval = 0;
+
+ while (mTokenChar >= '0' && mTokenChar <= '9')
+ {
+ expval = expval * 10 + (int)mTokenChar - (int)'0';
+ NextChar();
+ }
+
+ if (expval > 600)
+ expval = 600;
+
+ double fexp = pow(10.0, expval);
+
+ if (sign)
+ facc /= fexp;
+ else
+ facc *= fexp;
+ }
+
+ mTokenNumber = facc;
+ mToken = TK_NUMBER;
+ }
+ }
+}
diff --git a/oscar64/Scanner.h b/oscar64/Scanner.h
new file mode 100644
index 0000000..1096749
--- /dev/null
+++ b/oscar64/Scanner.h
@@ -0,0 +1,211 @@
+#pragma once
+
+#include "Ident.h"
+#include "Errors.h"
+#include "Preprocessor.h"
+
+enum Token
+{
+ TK_NONE,
+ TK_EOF,
+ TK_ERROR,
+ TK_EOL,
+
+ TK_IF,
+ TK_ELSE,
+ TK_WHILE,
+ TK_DO,
+ TK_FOR,
+ TK_VOID,
+ TK_INT,
+ TK_CHAR,
+ TK_FLOAT,
+ TK_UNSIGNED,
+ TK_SWITCH,
+ TK_CASE,
+ TK_DEFAULT,
+ TK_BREAK,
+ TK_RETURN,
+ TK_SHORT,
+ TK_LONG,
+ TK_CONTINUE,
+ TK_INTEGER,
+ TK_BOOL,
+ TK_CONST,
+ TK_VOLATILE,
+ TK_TYPEDEF,
+ TK_STRUCT,
+ TK_UNION,
+ TK_ENUM,
+ TK_SIZEOF,
+
+ TK_ASM,
+
+ TK_NUMBER,
+ TK_STRING,
+ TK_IDENT,
+ TK_TRUE,
+ TK_FALSE,
+ TK_NULL,
+
+ TK_ADD,
+ TK_SUB,
+ TK_MUL,
+ TK_DIV,
+ TK_MOD,
+
+ TK_LEFT_SHIFT,
+ TK_RIGHT_SHIFT,
+
+ TK_INC,
+ TK_DEC,
+
+ TK_LOGICAL_NOT,
+ TK_LOGICAL_AND,
+ TK_LOGICAL_OR,
+
+ TK_BINARY_NOT,
+ TK_BINARY_AND,
+ TK_BINARY_OR,
+ TK_BINARY_XOR,
+
+ TK_EQUAL,
+ TK_NOT_EQUAL,
+ TK_GREATER_THAN,
+ TK_GREATER_EQUAL,
+ TK_LESS_THAN,
+ TK_LESS_EQUAL,
+
+ TK_ASSIGN,
+ TK_ASSIGN_ADD,
+ TK_ASSIGN_SUB,
+ TK_ASSIGN_MUL,
+ TK_ASSIGN_DIV,
+ TK_ASSIGN_MOD,
+ TK_ASSIGN_SHL,
+ TK_ASSIGN_SHR,
+ TK_ASSIGN_AND,
+ TK_ASSIGN_XOR,
+ TK_ASSIGN_OR,
+
+ TK_ARROW,
+ TK_HASH,
+ TK_DOLLAR,
+
+ TK_OPEN_PARENTHESIS,
+ TK_CLOSE_PARENTHESIS,
+
+ TK_OPEN_BRACE,
+ TK_CLOSE_BRACE,
+
+ TK_OPEN_BRACKET,
+ TK_CLOSE_BRACKET,
+
+ TK_DOT,
+ TK_DOTDOT,
+ TK_ELLIPSIS,
+ TK_COMMA,
+ TK_SEMICOLON,
+ TK_COLON,
+ TK_QUESTIONMARK,
+
+ TK_PREP_DEFINE,
+ TK_PREP_INCLUDE,
+ TK_PREP_IF,
+ TK_PREP_ELIF,
+ TK_PREP_ELSE,
+ TK_PREP_ENDIF,
+ TK_PREP_IFDEF,
+ TK_PREP_IFNDEF,
+ TK_PREP_PRAGMA,
+
+ NUM_TOKENS
+};
+
+extern const char* TokenNames[];
+
+class Macro
+{
+public:
+ Macro(const Ident* ident);
+ ~Macro(void);
+
+ void SetString(const char* str);
+ void SetString(const char* str, int length);
+ void AddArgument(const Ident * ident);
+
+ const Ident* mIdent;
+ const char* mString;
+ int mNumArguments;
+ const Ident * mArguments[32];
+};
+
+typedef Macro* MacroPtr;
+
+class MacroDict
+{
+public:
+ MacroDict(void);
+ ~MacroDict(void);
+
+ void Insert(Macro * macro);
+ Macro* Lookup(const Ident* ident);
+
+protected:
+ MacroPtr * mHash;
+ int mHashSize, mHashFill;
+};
+
+class Scanner
+{
+public:
+ Scanner(Errors * errors, Preprocessor * preprocessor);
+ ~Scanner(void);
+
+ const char* TokenName(Token token) const;
+
+ void NextToken(void);
+
+ void Warning(const char * error);
+ void Error(const char * error);
+
+ Errors* mErrors;
+ Preprocessor * mPreprocessor;
+
+ int mPrepCondition, mPrepPending;
+
+ int mOffset;
+ const char * mLine;
+
+ const Ident * mTokenIdent;
+ char mTokenString[1024], mTokenChar;
+
+ Token mToken;
+ double mTokenNumber;
+ unsigned int mTokenInteger;
+
+ Location mLocation;
+
+ void SetAssemblerMode(bool mode);
+
+ bool mAssemblerMode;
+protected:
+ void NextRawToken(void);
+
+ struct MacroExpansion
+ {
+ MacroExpansion * mLink;
+ const char * mLine;
+ int mOffset;
+ char mChar;
+ MacroDict* mDefinedArguments;
+ } * mMacroExpansion;
+
+ MacroDict* mDefines, * mDefineArguments;
+
+ void StringToken(char terminator);
+ void CharToken(void);
+ bool NextChar(void);
+ void ParseNumberToken(void);
+
+};
diff --git a/oscar64/Type.h b/oscar64/Type.h
new file mode 100644
index 0000000..5a27b95
--- /dev/null
+++ b/oscar64/Type.h
@@ -0,0 +1,24 @@
+#pragma once
+
+enum TType
+{
+ TT_VOID,
+ TT_NULL,
+ TT_BOOL,
+ TT_INTEGER,
+ TT_FLOAT,
+ TT_POINTER,
+ TT_ARRAY,
+ TT_STRUCT,
+ TT_UNION,
+ TT_FUNCTION
+};
+
+class Type
+{
+public:
+ TType mType;
+ Type* mBase;
+ Scope* mScope;
+};
+
diff --git a/oscar64/oscar64.cpp b/oscar64/oscar64.cpp
new file mode 100644
index 0000000..c5e7566
--- /dev/null
+++ b/oscar64/oscar64.cpp
@@ -0,0 +1,152 @@
+#include
+#include
+#include "Compiler.h"
+
+bool GetProductAndVersion(char* strProductName, char* strProductVersion)
+{
+ // get the filename of the executable containing the version resource
+ TCHAR szFilename[MAX_PATH + 1] = { 0 };
+ if (GetModuleFileName(NULL, szFilename, MAX_PATH) == 0)
+ {
+ return false;
+ }
+
+ // allocate a block of memory for the version info
+ DWORD dummy;
+ DWORD dwSize = GetFileVersionInfoSize(szFilename, &dummy);
+ if (dwSize == 0)
+ {
+ return false;
+ }
+
+ BYTE* data = new BYTE[dwSize];
+
+ // load the version info
+ if (!GetFileVersionInfo(szFilename, NULL, dwSize, data))
+ {
+ return false;
+ }
+
+ // get the name and version strings
+ LPVOID pvProductName = NULL;
+ unsigned int iProductNameLen = 0;
+ LPVOID pvProductVersion = NULL;
+ unsigned int iProductVersionLen = 0;
+
+ // replace "040904e4" with the language ID of your resources
+ if (!VerQueryValueA(&data[0], "\\StringFileInfo\\000904b0\\ProductName", &pvProductName, &iProductNameLen) ||
+ !VerQueryValueA(&data[0], "\\StringFileInfo\\000904b0\\ProductVersion", &pvProductVersion, &iProductVersionLen))
+ {
+ return false;
+ }
+
+
+ strcpy_s(strProductName, 100, (LPCSTR)pvProductName);
+ strcpy_s(strProductVersion, 100, (LPCSTR)pvProductVersion);
+
+ return true;
+}
+
+
+int main(int argc, const char** argv)
+{
+ InitDeclarations();
+ InitAssembler();
+
+ if (argc > 0)
+ {
+ char basePath[200], crtPath[200], includePath[200], targetPath[200];
+ char strProductName[100], strProductVersion[200];
+
+ if (GetProductAndVersion(strProductName, strProductVersion))
+ {
+ printf("Starting %s %s\n", strProductName, strProductVersion);
+ }
+
+ DWORD length = ::GetModuleFileNameA(NULL, basePath, sizeof(basePath));
+
+ while (length > 0 && basePath[length - 1] != '/' && basePath[length - 1] != '\\')
+ length--;
+
+#ifdef _DEBUG
+ if (length > 0)
+ {
+ length--;
+ while (length > 0 && basePath[length - 1] != '/' && basePath[length - 1] != '\\')
+ length--;
+ }
+#endif
+
+ basePath[length] = 0;
+
+ Compiler* compiler = new Compiler();
+
+ Location loc;
+
+ compiler->mPreprocessor->AddPath(basePath);
+ strcpy_s(includePath, basePath);
+ strcat_s(includePath, "include/");
+ compiler->mPreprocessor->AddPath(includePath);
+ strcpy_s(crtPath, includePath);
+ strcat_s(crtPath, "crt.c");
+
+ bool emulate = false;
+
+ targetPath[0] = 0;
+
+ for (int i = 1; i < argc; i++)
+ {
+ const char* arg = argv[i];
+ if (arg[0] == '-')
+ {
+ if (arg[1] == 'i' && arg[2] == '=')
+ {
+ compiler->mPreprocessor->AddPath(arg + 3);
+ }
+ else if (arg[1] == 'o' && arg[2] == '=')
+ {
+ strcpy_s(targetPath, arg + 3);
+ }
+ else if (arg[1] == 'r' && arg[2] == 't' && arg[3] == '=')
+ {
+ strcpy_s(crtPath, arg + 4);
+ }
+ else if (arg[1] == 'e')
+ {
+ emulate = true;
+ }
+ else
+ compiler->mErrors->Error(loc, "Invalid command line argument", arg);
+ }
+ else
+ {
+ if (!targetPath[0])
+ strcpy_s(targetPath, argv[i]);
+ compiler->mCompilationUnits->AddUnit(loc, argv[i], nullptr);
+ }
+ }
+
+ // Add runtime module
+
+ compiler->mCompilationUnits->AddUnit(loc, crtPath, nullptr);
+
+ if (compiler->ParseSource() && compiler->GenerateCode())
+ {
+ compiler->WriteOutputFile(targetPath);
+
+ if (emulate)
+ compiler->ExecuteCode();
+ }
+
+ if (compiler->mErrors->mErrorCount != 0)
+ return 20;
+ }
+ else
+ {
+ printf("oscar64 {-i=includePath} [-o=output.prg] [-cr=runtime.c] [-e] {source.c}\n");
+ return 0;
+ }
+
+ return 0;
+}
+
diff --git a/oscar64/oscar64.rc b/oscar64/oscar64.rc
new file mode 100644
index 0000000..aab1c08
--- /dev/null
+++ b/oscar64/oscar64.rc
@@ -0,0 +1,110 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL
+#pragma code_page(1252)
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,20
+ PRODUCTVERSION 1,0,0,20
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "000904b0"
+ BEGIN
+ VALUE "CompanyName", "oscar64"
+ VALUE "FileDescription", "oscar64 compiler"
+ VALUE "FileVersion", "1.0.0.20"
+ VALUE "InternalName", "oscar64.exe"
+ VALUE "LegalCopyright", "Copyright (C) 2021"
+ VALUE "OriginalFilename", "oscar64.exe"
+ VALUE "ProductName", "oscar64"
+ VALUE "ProductVersion", "1.0.0.20"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x9, 1200
+ END
+END
+
+#endif // English resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// German (Germany) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU)
+LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
+#pragma code_page(1252)
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""winres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // German (Germany) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/oscar64/oscar64.vcxproj b/oscar64/oscar64.vcxproj
new file mode 100644
index 0000000..d3edcc7
--- /dev/null
+++ b/oscar64/oscar64.vcxproj
@@ -0,0 +1,187 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {1dbc623e-6109-41fe-b1bb-9b43fc984f7d}
+ oscar64
+ 10.0
+
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;version.lib;%(AdditionalDependencies)
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+ kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;version.lib;%(AdditionalDependencies)
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/oscar64/oscar64.vcxproj.filters b/oscar64/oscar64.vcxproj.filters
new file mode 100644
index 0000000..b8231f3
--- /dev/null
+++ b/oscar64/oscar64.vcxproj.filters
@@ -0,0 +1,128 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Resource Files
+
+
+
\ No newline at end of file
diff --git a/oscar64/resource.h b/oscar64/resource.h
new file mode 100644
index 0000000..f85f7a5
--- /dev/null
+++ b/oscar64/resource.h
@@ -0,0 +1,14 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by oscar64.rc
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif