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