├── LICENSE
├── Makefile
├── README.md
├── ctype1.c
├── initvar1.c
├── lkoptim
├── optim.c
├── optim1.c
├── optim1.h
├── part21.c
└── part31.c
/LICENSE:
--------------------------------------------------------------------------------
  1 |                     GNU GENERAL PUBLIC LICENSE
  2 |                        Version 3, 29 June 2007
  3 | 
  4 |  Copyright (C) 2007 Free Software Foundation, Inc. 
  5 |  Everyone is permitted to copy and distribute verbatim copies
  6 |  of this license document, but changing it is not allowed.
  7 | 
  8 |                             Preamble
  9 | 
 10 |   The GNU General Public License is a free, copyleft license for
 11 | software and other kinds of works.
 12 | 
 13 |   The licenses for most software and other practical works are designed
 14 | to take away your freedom to share and change the works.  By contrast,
 15 | the GNU General Public License is intended to guarantee your freedom to
 16 | share and change all versions of a program--to make sure it remains free
 17 | software for all its users.  We, the Free Software Foundation, use the
 18 | GNU General Public License for most of our software; it applies also to
 19 | any other work released this way by its authors.  You can apply it to
 20 | your programs, too.
 21 | 
 22 |   When we speak of free software, we are referring to freedom, not
 23 | price.  Our General Public Licenses are designed to make sure that you
 24 | have the freedom to distribute copies of free software (and charge for
 25 | them if you wish), that you receive source code or can get it if you
 26 | want it, that you can change the software or use pieces of it in new
 27 | free programs, and that you know you can do these things.
 28 | 
 29 |   To protect your rights, we need to prevent others from denying you
 30 | these rights or asking you to surrender the rights.  Therefore, you have
 31 | certain responsibilities if you distribute copies of the software, or if
 32 | you modify it: responsibilities to respect the freedom of others.
 33 | 
 34 |   For example, if you distribute copies of such a program, whether
 35 | gratis or for a fee, you must pass on to the recipients the same
 36 | freedoms that you received.  You must make sure that they, too, receive
 37 | or can get the source code.  And you must show them these terms so they
 38 | know their rights.
 39 | 
 40 |   Developers that use the GNU GPL protect your rights with two steps:
 41 | (1) assert copyright on the software, and (2) offer you this License
 42 | giving you legal permission to copy, distribute and/or modify it.
 43 | 
 44 |   For the developers' and authors' protection, the GPL clearly explains
 45 | that there is no warranty for this free software.  For both users' and
 46 | authors' sake, the GPL requires that modified versions be marked as
 47 | changed, so that their problems will not be attributed erroneously to
 48 | authors of previous versions.
 49 | 
 50 |   Some devices are designed to deny users access to install or run
 51 | modified versions of the software inside them, although the manufacturer
 52 | can do so.  This is fundamentally incompatible with the aim of
 53 | protecting users' freedom to change the software.  The systematic
 54 | pattern of such abuse occurs in the area of products for individuals to
 55 | use, which is precisely where it is most unacceptable.  Therefore, we
 56 | have designed this version of the GPL to prohibit the practice for those
 57 | products.  If such problems arise substantially in other domains, we
 58 | stand ready to extend this provision to those domains in future versions
 59 | of the GPL, as needed to protect the freedom of users.
 60 | 
 61 |   Finally, every program is threatened constantly by software patents.
 62 | States should not allow patents to restrict development and use of
 63 | software on general-purpose computers, but in those that do, we wish to
 64 | avoid the special danger that patents applied to a free program could
 65 | make it effectively proprietary.  To prevent this, the GPL assures that
 66 | patents cannot be used to render the program non-free.
 67 | 
 68 |   The precise terms and conditions for copying, distribution and
 69 | modification follow.
 70 | 
 71 |                        TERMS AND CONDITIONS
 72 | 
 73 |   0. Definitions.
 74 | 
 75 |   "This License" refers to version 3 of the GNU General Public License.
 76 | 
 77 |   "Copyright" also means copyright-like laws that apply to other kinds of
 78 | works, such as semiconductor masks.
 79 | 
 80 |   "The Program" refers to any copyrightable work licensed under this
 81 | License.  Each licensee is addressed as "you".  "Licensees" and
 82 | "recipients" may be individuals or organizations.
 83 | 
 84 |   To "modify" a work means to copy from or adapt all or part of the work
 85 | in a fashion requiring copyright permission, other than the making of an
 86 | exact copy.  The resulting work is called a "modified version" of the
 87 | earlier work or a work "based on" the earlier work.
 88 | 
 89 |   A "covered work" means either the unmodified Program or a work based
 90 | on the Program.
 91 | 
 92 |   To "propagate" a work means to do anything with it that, without
 93 | permission, would make you directly or secondarily liable for
 94 | infringement under applicable copyright law, except executing it on a
 95 | computer or modifying a private copy.  Propagation includes copying,
 96 | distribution (with or without modification), making available to the
 97 | public, and in some countries other activities as well.
 98 | 
 99 |   To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies.  Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 | 
103 |   An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License.  If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 | 
112 |   1. Source Code.
113 | 
114 |   The "source code" for a work means the preferred form of the work
115 | for making modifications to it.  "Object code" means any non-source
116 | form of a work.
117 | 
118 |   A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 | 
123 |   The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form.  A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 | 
134 |   The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities.  However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work.  For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 | 
147 |   The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 | 
151 |   The Corresponding Source for a work in source code form is that
152 | same work.
153 | 
154 |   2. Basic Permissions.
155 | 
156 |   All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met.  This License explicitly affirms your unlimited
159 | permission to run the unmodified Program.  The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work.  This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 | 
164 |   You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force.  You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright.  Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 | 
175 |   Conveying under any other circumstances is permitted solely under
176 | the conditions stated below.  Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 | 
179 |   3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 | 
181 |   No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 | 
187 |   When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 | 
195 |   4. Conveying Verbatim Copies.
196 | 
197 |   You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 | 
205 |   You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 | 
208 |   5. Conveying Modified Source Versions.
209 | 
210 |   You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 | 
214 |     a) The work must carry prominent notices stating that you modified
215 |     it, and giving a relevant date.
216 | 
217 |     b) The work must carry prominent notices stating that it is
218 |     released under this License and any conditions added under section
219 |     7.  This requirement modifies the requirement in section 4 to
220 |     "keep intact all notices".
221 | 
222 |     c) You must license the entire work, as a whole, under this
223 |     License to anyone who comes into possession of a copy.  This
224 |     License will therefore apply, along with any applicable section 7
225 |     additional terms, to the whole of the work, and all its parts,
226 |     regardless of how they are packaged.  This License gives no
227 |     permission to license the work in any other way, but it does not
228 |     invalidate such permission if you have separately received it.
229 | 
230 |     d) If the work has interactive user interfaces, each must display
231 |     Appropriate Legal Notices; however, if the Program has interactive
232 |     interfaces that do not display Appropriate Legal Notices, your
233 |     work need not make them do so.
234 | 
235 |   A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit.  Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 | 
245 |   6. Conveying Non-Source Forms.
246 | 
247 |   You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 | 
252 |     a) Convey the object code in, or embodied in, a physical product
253 |     (including a physical distribution medium), accompanied by the
254 |     Corresponding Source fixed on a durable physical medium
255 |     customarily used for software interchange.
256 | 
257 |     b) Convey the object code in, or embodied in, a physical product
258 |     (including a physical distribution medium), accompanied by a
259 |     written offer, valid for at least three years and valid for as
260 |     long as you offer spare parts or customer support for that product
261 |     model, to give anyone who possesses the object code either (1) a
262 |     copy of the Corresponding Source for all the software in the
263 |     product that is covered by this License, on a durable physical
264 |     medium customarily used for software interchange, for a price no
265 |     more than your reasonable cost of physically performing this
266 |     conveying of source, or (2) access to copy the
267 |     Corresponding Source from a network server at no charge.
268 | 
269 |     c) Convey individual copies of the object code with a copy of the
270 |     written offer to provide the Corresponding Source.  This
271 |     alternative is allowed only occasionally and noncommercially, and
272 |     only if you received the object code with such an offer, in accord
273 |     with subsection 6b.
274 | 
275 |     d) Convey the object code by offering access from a designated
276 |     place (gratis or for a charge), and offer equivalent access to the
277 |     Corresponding Source in the same way through the same place at no
278 |     further charge.  You need not require recipients to copy the
279 |     Corresponding Source along with the object code.  If the place to
280 |     copy the object code is a network server, the Corresponding Source
281 |     may be on a different server (operated by you or a third party)
282 |     that supports equivalent copying facilities, provided you maintain
283 |     clear directions next to the object code saying where to find the
284 |     Corresponding Source.  Regardless of what server hosts the
285 |     Corresponding Source, you remain obligated to ensure that it is
286 |     available for as long as needed to satisfy these requirements.
287 | 
288 |     e) Convey the object code using peer-to-peer transmission, provided
289 |     you inform other peers where the object code and Corresponding
290 |     Source of the work are being offered to the general public at no
291 |     charge under subsection 6d.
292 | 
293 |   A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 | 
297 |   A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling.  In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage.  For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product.  A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 | 
310 |   "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source.  The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 | 
318 |   If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information.  But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 | 
329 |   The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed.  Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 | 
337 |   Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 | 
343 |   7. Additional Terms.
344 | 
345 |   "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law.  If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 | 
354 |   When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it.  (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.)  You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 | 
361 |   Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 | 
365 |     a) Disclaiming warranty or limiting liability differently from the
366 |     terms of sections 15 and 16 of this License; or
367 | 
368 |     b) Requiring preservation of specified reasonable legal notices or
369 |     author attributions in that material or in the Appropriate Legal
370 |     Notices displayed by works containing it; or
371 | 
372 |     c) Prohibiting misrepresentation of the origin of that material, or
373 |     requiring that modified versions of such material be marked in
374 |     reasonable ways as different from the original version; or
375 | 
376 |     d) Limiting the use for publicity purposes of names of licensors or
377 |     authors of the material; or
378 | 
379 |     e) Declining to grant rights under trademark law for use of some
380 |     trade names, trademarks, or service marks; or
381 | 
382 |     f) Requiring indemnification of licensors and authors of that
383 |     material by anyone who conveys the material (or modified versions of
384 |     it) with contractual assumptions of liability to the recipient, for
385 |     any liability that these contractual assumptions directly impose on
386 |     those licensors and authors.
387 | 
388 |   All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10.  If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term.  If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 | 
398 |   If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 | 
403 |   Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 | 
407 |   8. Termination.
408 | 
409 |   You may not propagate or modify a covered work except as expressly
410 | provided under this License.  Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 | 
415 |   However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 | 
422 |   Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 | 
429 |   Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License.  If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 | 
435 |   9. Acceptance Not Required for Having Copies.
436 | 
437 |   You are not required to accept this License in order to receive or
438 | run a copy of the Program.  Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance.  However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work.  These actions infringe copyright if you do
443 | not accept this License.  Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 | 
446 |   10. Automatic Licensing of Downstream Recipients.
447 | 
448 |   Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License.  You are not responsible
451 | for enforcing compliance by third parties with this License.
452 | 
453 |   An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations.  If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 | 
463 |   You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License.  For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 | 
471 |   11. Patents.
472 | 
473 |   A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based.  The
475 | work thus licensed is called the contributor's "contributor version".
476 | 
477 |   A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version.  For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 | 
487 |   Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 | 
492 |   In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement).  To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 | 
499 |   If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients.  "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 | 
513 |   If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 | 
521 |   A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License.  You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 | 
536 |   Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 | 
540 |   12. No Surrender of Others' Freedom.
541 | 
542 |   If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License.  If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all.  For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 | 
552 |   13. Use with the GNU Affero General Public License.
553 | 
554 |   Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work.  The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 | 
563 |   14. Revised Versions of this License.
564 | 
565 |   The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time.  Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 | 
570 |   Each version is given a distinguishing version number.  If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation.  If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 | 
579 |   If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 | 
584 |   Later license versions may give you additional or different
585 | permissions.  However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 | 
589 |   15. Disclaimer of Warranty.
590 | 
591 |   THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 | 
600 |   16. Limitation of Liability.
601 | 
602 |   IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 | 
612 |   17. Interpretation of Sections 15 and 16.
613 | 
614 |   If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 | 
621 |                      END OF TERMS AND CONDITIONS
622 | 
623 |             How to Apply These Terms to Your New Programs
624 | 
625 |   If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 | 
629 |   To do so, attach the following notices to the program.  It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 | 
634 |     
635 |     Copyright (C)   
636 | 
637 |     This program is free software: you can redistribute it and/or modify
638 |     it under the terms of the GNU General Public License as published by
639 |     the Free Software Foundation, either version 3 of the License, or
640 |     (at your option) any later version.
641 | 
642 |     This program is distributed in the hope that it will be useful,
643 |     but WITHOUT ANY WARRANTY; without even the implied warranty of
644 |     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
645 |     GNU General Public License for more details.
646 | 
647 |     You should have received a copy of the GNU General Public License
648 |     along with this program.  If not, see .
649 | 
650 | Also add information on how to contact you by electronic and paper mail.
651 | 
652 |   If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 | 
655 |       Copyright (C)   
656 |     This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 |     This is free software, and you are welcome to redistribute it
658 |     under certain conditions; type `show c' for details.
659 | 
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License.  Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 | 
664 |   You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 | 
669 |   The GNU General Public License does not permit incorporating your program
670 | into proprietary programs.  If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library.  If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License.  But first, please read
674 | .
675 | 
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
 1 | ########################################################################
 2 | #
 3 | #  Use this Makefile to build the CGEN for HiTech C v3.09 under Linux
 4 | #  using John Elliott's zxcc emulator.
 5 | #
 6 | ########################################################################
 7 | 
 8 | VERSION = 3.0
 9 | 
10 | CSRCS =	optim1.c \
11 | 	part21.c \
12 | 	part31.c \
13 | 	ctype1.c \
14 | 	initvar1.c
15 | 
16 | 
17 | COBJS = $(CSRCS:.c=.obj)
18 | 
19 | 
20 | OBJS = $(COBJS)
21 | 
22 | all:	$(COBJS) optim.com 
23 | 
24 | .SUFFIXES:		# delete the default suffixes
25 | .SUFFIXES: .c .obj
26 | 
27 | $(COBJS): %.obj: %.c
28 | 	zxc -c -o  $<
29 | 
30 | #$(AOBJS): %.obj: %.asm
31 | #	zxas -n $<
32 | #	zxas -j -n $<
33 | 
34 | optim.com: $(OBJS)
35 | 	zxcc link -"<" +lkoptim
36 | 	sort optim1.sym | uniq > optim1.sym.sorted
37 | 
38 | clean:
39 | 	rm -f $(OBJS) optim1.com *.\$$\$$\$$ optim1.map optim1.sym optim1.sym.sorted
40 | 
41 | 
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
  1 | The C source code was RESTORED by disassembling the original executable file OPTIM.COM from the Hi-Tech v3.09 compiler.
  2 | 
  3 | This file is compiled by Hi-Tech C compiler v3.09 and the resulting executable file performs all the functions provided. To compile, use the following command:
  4 | 
  5 |     cc -o optim.c
  6 | 
  7 | The created executable file almost completely matches the original image.
  8 | 
  9 | The OPTIM utility tries to perform 18 types of optimizations.
 10 | 
 11 | OPTIM has 5 options not described in the manual
 12 | 
 13 | -l - Prints additional information on each pass;
 14 | 
 15 | -n - Prints statistics: number of iterations and number of optimization types performed;
 16 | 
 17 | -r - disables register load optimisation;
 18 | 
 19 | -f - use inline frame initialisation;
 20 | 
 21 | -s - Unbuffered stdout.
 22 | 
 23 | Options are unknown to ordinary users and are not used when compiling a program using optimization. These options are probably intended for compiler support to find errors while performing optimization.
 24 | 
 25 | Mark Ogden took part in the work on the restoration of the source code of the optimization program in C language. He assigned names to the variables, gave the structures an understandable look, corrected some C functions to exclude labels in the function body, suggested how to interpret and fix several obscure places in the decompiled code, and found errors in the original optimization program.
 26 | 
 27 | Mark Ogden's contribution is very large. Without his participation, code restoration would be much slower.
 28 | 
 29 | Thanks to Mark Ogden for the effort and time spent on this thankless event. In fact, he is a co-author of the recovered code. 
 30 | 
 31 | This version includes support for windows and linux both 32 & 64 bit. It also fixes some bugs in the original code
 32 | 
 33 | For compilation to CP / M, the optim.c file is split into the following files:
 34 | optim1.h - define common data for a program
 35 | 
 36 | optim1.c - functions 1 to 30
 37 | 
 38 | part21.c - functions 31 to 49
 39 | 
 40 | part31.c - other functions
 41 | 
 42 | ctype1.c - Definitions of valid characters and their types in oprtmizer
 43 | 
 44 | initvar1.c - Definitions of uninitialized variables and arrays
 45 | 
 46 | To compile, you need to run the command
 47 | 
 48 | cc -o optim1.c part21.c part31.c ctype1.c initvar1.c
 49 | 
 50 | or execute
 51 | 
 52 | make
 53 | 
 54 | The optimizer program is compiled without diagnostic messages and an executable file is created.
 55 | 
 56 | To test the operation of the created executable file, you can create a file in assembly language without optimization using the command
 57 | 
 58 | cc -s optim.c
 59 | 
 60 | then perform optimization with additional information output
 61 | 
 62 | optim1 -n optim.as optim.asm
 63 | 
 64 | As a result, information about the performed optimizations will be displayed on the screen.
 65 | 
 66 | 24K, 3 iterations
 67 | 
 68 | 370 Redundant labels
 69 | 
 70 | 499 Jumps to jumps
 71 | 
 72 | 367 Stack adjustments
 73 | 
 74 | 731 Temporary labels
 75 | 
 76 | 683 Unref'ed labels
 77 | 
 78 | 487 Unreachable code
 79 | 
 80 | 49 Jumps to. +1
 81 | 
 82 | 148 Skips over jumps
 83 | 
 84 | 183 Common code seq's
 85 | 
 86 | 15 Ex (sp), hl's used
 87 | 
 88 | 87 Redundant operations
 89 | 
 90 | 488 Redundant loads/stores
 91 | 
 92 | 71 Simplified addresses
 93 | 
 94 | 5 Xor a's used
 95 | 
 96 | 5 Redundant ex de, hl's
 97 | 
 98 | 46 Code motions
 99 | 
100 | and the optimized code will be written to the optim.asm file. 
101 | 
102 | Andrey Nikitin 12.11.2021
103 | 
--------------------------------------------------------------------------------
/ctype1.c:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * The ctype1.c file is part of the restored optimization program
 3 |  * from the Hi-Tech C compiler v3.09 package.
 4 |  *
 5 |  *	Andrey Nikitin 04.11.2021
 6 |  */
 7 | 
 8 | #define	_Z	 0	// 0000 0000
 9 | #define	_U	 1	// 0000 0001
10 | #define	_L	 2	// 0000 0010
11 | #define	_D	 4	// 0000 0100
12 | #define	_H	 8	// 0000 1000
13 | #define	_S	16	// 0001 0000
14 | 
15 | /*
16 |  *	Definitions of valid characters and their types in oprtmizer 
17 |  */
18 | char ccClass[] = {	//62cc
19 |        _Z,    _Z,    _Z,    _Z,    _Z,    _Z,    _Z,    _Z,
20 |        _S,    _S,    _Z,    _Z,    _S,    _S,    _Z,    _Z,
21 |        _Z,    _Z,    _Z,    _Z,    _Z,    _Z,    _Z,    _Z,
22 |        _Z,    _Z,    _Z,    _Z,    _Z,    _Z,    _Z,    _Z,
23 |        _S,    _Z,    _Z,    _Z,    _L,    _Z,    _Z,    _Z,
24 |        _Z,    _Z,    _Z,    _Z,    _Z,    _Z,    _Z,    _Z,
25 |     _D|_H, _D|_H, _D|_H, _D|_H, _D|_H, _D|_H, _D|_H, _D|_H,
26 |     _D|_H, _D|_H,    _Z,    _Z,    _Z,    _Z,    _Z,    _L,
27 |        _Z, _U|_H, _U|_H, _U|_H, _U|_H, _U|_H, _U|_H,    _U,
28 |        _U,    _U,    _U,    _U,    _U,    _U,    _U,    _U,
29 |        _U,    _U,    _U,    _U,    _U,    _U,    _U,    _U,
30 |        _U,    _U,    _U,    _Z,    _Z,    _Z,    _Z,    _L,
31 |        _Z, _L|_H, _L|_H, _L|_H, _L|_H, _L|_H, _L|_H,    _L,
32 |        _L,    _L,    _L,    _L,    _L,    _L,    _L,    _L,
33 |        _L,    _L,    _L,    _L,    _L,    _L,    _L,    _L,
34 |        _L,    _L,    _L,    _Z,    _Z,    _Z,    _Z,    _Z 
35 | };
36 | 
--------------------------------------------------------------------------------
/initvar1.c:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * The initvar1.c file is part of the restored optimization program
 3 |  * from the Hi-Tech C compiler v3.09 package.
 4 |  *
 5 |  *	Andrey Nikitin & Mark Ogden 11.11.2021
 6 |  */
 7 | #include 
 8 | #include 
 9 | #include "optim1.h"
10 | 
11 | /****************************************************************
12 |  *	Descriptions of uninitialized variables and arrays
13 |  ****************************************************************/
14 | 
15 | char 	           yyline[80];			/* 6f00	Working buffer */
16 | int                charsLeft;			/* 6f50	Length string in input buffer */
17 | char             * ptr_inbuf;			/* 6f52	Pointer to input buffer  */
18 | int	           yytype;			/* 6f54 */
19 | char	           inp_buf[512];			/* 6f56	Input buffer (In the original it was 80) */
20 | bool	           key_l;			/* 6fa6	Prints additional information on each pass */
21 | bool	           key_n;			/* 6fa7	Prints statistics */
22 | bool	           key_f;			/* 6fa8	The action is not clear */
23 | bool	           key_s;			/* 6fa9	Key_s = 1 Unbuffered stdout */
24 | int	           num_warn;			/* 6faa	Number of warnings */
25 | bool	           key_r;			/* 6fac */
26 | operator_t const * tableBase;			/* 6fad	Pointer to keyword[] */
27 | char	         * yytext;			/* 6faf */
28 | YYSTYPE	           yylval;			/* 6fb1	Contains different types of data */
29 | int	           symbolId;			/* 6fb3 */
30 | sym_t            * gPs;				/* 6fb5 */
31 | inst_t           * gPi;				/* 6fb7 */
32 | /*int	           word_6fb9;		           6fb9 Moved to function as static variable */
33 | bool 	           hasChanged;			/* 6fbb */
34 | bool 	           usesIXorIY;			/* 6fbc */
35 | int	           optimiseCounters[18];	/* 6fbd	Array of counters types of optimizations */
36 | 						/* 6fbd	[  0] Redundant labels */
37 | 						/* 6fbf	[  1] Jumps to jumps */
38 | 						/* 6fc1	[  2] Stack adjustments */
39 | 						/* 6fc3	[  3] Temporary labels */
40 | 						/* 6fc5	[  4] Unref'ed labels */
41 | 						/* 6fc7	[  5] Unreachable code */
42 | 						/* 6fc9	[  6] Jumps to .+1 */
43 | 						/* 6fcb	[  7] Skips over jumps */
44 | 						/* 6fcd	[  8] Common code seq's */
45 | 						/* 6fcf	[  9] Redundant exx's */
46 | 						/* 6fd1	[ 10] Ex (sp),hl's used */
47 | 						/* 6fd3	[ 11] Redundant operations */
48 | 						/* 6fd5	[ 12] Redundant loads/stores */
49 | 						/* 6fd7	[ 13] Simplified addresses */
50 | 						/* 6fd9	[ 14] Xor a's used */
51 | 						/* 6fdb	[ 15] Redundant ex de,hl's */
52 | 						/* 6fdd	[ 16] Code motions */
53 | 						/* 6fdf	[ 17] Loops inverted */
54 | list_t           * freeOperandList;		/* 6fe1	ptr to struct size 6 */
55 | inst_t           * seq1;			/* 6fe3 */
56 | inst_t           * seq2;			/* 6fe5 */
57 | inst_t           * freeInstList;		/* 6fe7 */
58 | char               psect;			/* 6fe9	Program section */
59 | int                cur_psect;			/* 6fea	Current program section */
60 | int                expectCond;			/* 6fec */
61 | inst_t           * word_6fee;			/* 6fee */
62 | int                tokType;			/* 6ff0	Token value */
63 | inst_t           * switchVectors; //word_6ff2;			/* 6ff2 */
64 | /*static term_t    termTmp;		           6ff4	[4] Moved to function as static variable */
65 | inst_t           * root;			/* 6ff8 */
66 | int                cntOperand;              	/* 6ffa	Used only in sub_39a3 */
67 | inst_t           * word_6ffc;			/* 6ffc */
68 | 
69 | #ifndef CPM
70 | char             * heapBase;
71 | char             * heapTop;
72 | #endif
73 | 
74 | jmp_buf            jmpbuf;			/* 6ffe	[8] */
75 | int	           hlDelta; /* word_7006;*/			/* 7006 */
76 | operand_t          regValues[19];		/* 7008 */
77 | char             * alloct;			/* 707a is the top of the current region */
78 | char             * name_fun;			/* 707c	Function name */
79 | 						/* 707e */
80 | 						/* 707f */
81 | list_t           * freeItemList;		/* 7080 */
82 | char             * allocs;			/* 7082	is the current next allocated heap location */
83 | char             * programBreak;		/* 7084	ok */
84 | 
85 | #define HASHSIZE 311
86 | 
87 | sym_t            * hashtab[HASHSIZE];		/* 7086	[622] */
88 | 
89 | 
--------------------------------------------------------------------------------
/lkoptim:
--------------------------------------------------------------------------------
 1 | -Z -Doptim11.sym -N -C -Moptim11.map -Ptext=0,data,bss -C100H -Ooptim1.COM crtcpm.obj \
 2 | optim1.obj part21.obj part31.obj ctype1.obj initvar1.obj \
 3 | LIBC.LIB \
 4 |  \
 5 |  \
 6 |  \
 7 |  \
 8 |  \
 9 |  \
10 | 
--------------------------------------------------------------------------------
/optim1.c:
--------------------------------------------------------------------------------
   1 | /*
   2 |  * File optim1.c created 14.08.2021, last modified 11.11.2021.
   3 |  *
   4 |  * The optim1.c file is part of the restored optimization program
   5 |  * from the Hi-Tech C compiler v3.09 package.
   6 |  *
   7 |  * The C source code was RESTORED by disassembling the original executable
   8 |  * file OPTIM.COM from the Hi-Tech v3.09 compiler.
   9 |  *
  10 |  * This file is compiled by Hi-Tech C compiler v3.09 and the resulting
  11 |  * executable file performs all the functions provided. To compile, use
  12 |  * the following command:
  13 |  *
  14 |  *    cc -o optim1.c part21.c part31.c ctype1.c initvar1.c
  15 |  *
  16 |  * The created executable file almost completely matches the original image.
  17 |  *
  18 |  * Mark Ogden took part in the work on the restoration of the source code of
  19 |  * the optimization program in C language.
  20 |  * He assigned names to the variables, gave the structures an understandable
  21 |  * look, corrected some C functions to exclude labels in the function body,
  22 |  * suggested how to interpret and fix several obscure places in the decompiled
  23 |  * code, and found errors in the original optimization program. Mark Ogden's
  24 |  * contribution is very large. Without his participation, code restoration
  25 |  * would be much slower. Thanks to Mark Ogden for the effort and time spent
  26 |  * on this thankless event. In fact, he is a co-author of the recovered code. 
  27 |  * 
  28 |  * The OPTIM utility tries to perform 18 types of optimizations.
  29 |  *
  30 |  * OPTIM has 5 options not described in the manual:
  31 |  *    -l - Prints additional information on each pass;
  32 |  *    -n - Prints statistics: number of iterations and number of
  33 |  *         optimization types performed;
  34 |  *    -r - disables register load optimisation
  35 |  *    -f - use inline frame initialisation
  36 |  *    -s - Unbuffered stdout;
  37 |  *
  38 |  * Options are unknown to ordinary users and are not used when compiling a
  39 |  * program using optimization. These options are probably intended for compiler
  40 |  * support to find errors while performing optimization.
  41 |  *
  42 |  * Not a commercial goal of this laborious work is to popularize among potential
  43 |  * fans of 8-bit computers the old HI-TECH C compiler V3.09 (HI-TECH Software)
  44 |  * and extend its life, outside of the CP/M environment (Digital Research, Inc),
  45 |  * for full operation in a Unix-like operating system UZI-180 without using the
  46 |  * CP/M emulator.
  47 |  *
  48 |  *	Andrey Nikitin & Mark Ogden 11.11.2021
  49 |  */
  50 | 
  51 | #include 
  52 | #include 
  53 | #include 
  54 | #include 
  55 | #include 
  56 | 
  57 | #if defined(__STDC__) || defined(__STDC_VERSION__)
  58 | #include 
  59 | #include 
  60 | #include 
  61 | #endif
  62 | 
  63 | #include "optim1.h"
  64 | 
  65 | #define	_Z	 0	/* 0000 0000 */
  66 | #define	_U	 1	/* 0000 0001 */
  67 | #define	_L	 2	/* 0000 0010 */
  68 | #define	_D	 4	/* 0000 0100 */
  69 | #define	_H	 8	/* 0000 1000 */
  70 | #define	_S	16	/* 0001 0000 */
  71 | 
  72 | #define ISALPHA(c)     ( ccClass[c] & (_U|_L) )
  73 | #define ISUPPER(c)     ( ccClass[c] & _U )
  74 | #define ISDIGIT(c)     ( ccClass[c] & _D )
  75 | #define ISXDIGIT(c)    ( ccClass[c] & _H )
  76 | #define ISSPACE(c)     ( ccClass[c] & _S )
  77 | #define ISALNUM(c)     ( ccClass[c] & (_U|_L|_D) )
  78 | 
  79 | /****************************************************************
  80 |  *	Initialized variables 
  81 |  ****************************************************************/
  82 | char * conditions[] = {
  83 |     0,          /* 63db	 0          */
  84 |     "nz",       /* 63dd	 1 COND_NZ  */
  85 |     "z",        /* 63df	 2 COND_Z   */
  86 |     "nc",       /* 63e1	 3 COND_LGE */
  87 |     "c",        /* 63e3	 4 COND_LLT */
  88 |     "po",       /* 63e5	 5 COND_PO  */
  89 |     "pe",       /* 63e7	 6 COND_PE  */
  90 |     "p",        /* 63e9	 7 COND_GE  */
  91 |     "m"         /* 63eb	 8 COND_LT  */
  92 | };
  93 | 
  94 | char * regs[] = {
  95 |     "b",	/* 63ed  0 REG_B   */
  96 |     "c",	/* 63ef  1 REG_C   */
  97 |     "d",	/* 63f1  2 REG_D   */
  98 |     "e",	/* 63f3  3 REG_E   */
  99 |     "h",	/* 63f5  4 REG_H   */
 100 |     "l",	/* 63f7  5 REG_L   */
 101 |     "",		/* 63f9  6 REG_F   */
 102 |     "a",	/* 63fb  7 REG_A   */
 103 |     "i",	/* 63fd  8 REG_I   */
 104 |     "r",	/* 63ff  9 REG_R  Memory Refresh Register */
 105 |     "bc",	/* 6401 10 REG_BC  */
 106 |     "de",	/* 6403 11 REG_DE  */
 107 |     "hl",	/* 6405 12 REG_HL  */
 108 |     "sp",	/* 6407 13 REG_SP  */
 109 |     "af",	/* 6409 14 REG_AF  */
 110 |     "af'",	/* 640b 15 REG_AF1 */
 111 |     "ix",	/* 640d 16 REG_IX  */
 112 |     "iy"	/* 640f 17 REG_IY  */
 113 | };
 114 | 
 115 | operator_t operators[] = {
 116 |     /* 6411 */
 117 |     { "&",      T_AND,     P_AND    },  /*   0   0   Bitwise AND */
 118 |     { "(",      T_OPAR,    P_OPAR   },  /*   1   1   Open parenthesis */
 119 |     { ")",      T_CPAR,    P_CPAR   },  /*   2   2   Closing parenthesis */
 120 |     { "*",      T_MUL,     P_MUL    },  /*   3   3   Multiplication */
 121 |     { "+",      T_PLUS,    P_ADD    },  /*   4   4   Addition */
 122 |     { ",",      T_COMM,    P_NA     },  /*   5   5   Comma */
 123 |     { "-",      T_MINUS,   P_SUB    },  /*   6   6   Subtraction */
 124 |     { ".and.",  T_AND,     P_AND    },  /*   7   7   Bitwise AND */
 125 |     { ".high.", T_HI,      P_HI     },  /*   8   8   Hi byte of operand */
 126 |     { ".low.",  T_LOW,     P_LOW    },  /*   9   9   Low byte of operand */
 127 |     { ".mod.",  T_MOD,     P_MOD    },  /*  10   a   Modulus */
 128 |     { ".not.",  T_NOT,     P_NOT    },  /*  11   b   Bitwise complement */
 129 |     { ".or.",   T_OR,      P_OR     },  /*  12   c   Bitwise or */
 130 |     { ".res.",  T_RES,     P_RES    },  /*  13   d   */
 131 |     { ".shl.",  T_SHL,     P_SHL    },  /*  14   e   Shift left */
 132 |     { ".shr.",  T_SHR,     P_SHR    },  /*  15   f   Shift right */
 133 |     { ".xor.",  T_XOR,     P_XOR    },  /*  16   10  Exclusive or */
 134 |     { "/",      T_DIV,     P_DIV    },  /*  17   11  Divison */
 135 |     { ":",      T_COLN,    P_NA     },  /*  18   12  Label separator */
 136 |     { "<",      T_GE,      P_GE     },  /*  19   13  Signed less than */
 137 |     { "=",      T_EQ,      P_EQU    },  /*  20   14  Equality */
 138 |     { ">",      T_LE,      P_LE     },  /*  21   15  Signed greater than */
 139 |     { "\\",     T_NOT,     P_NOT    },  /*  22   16  Bitwise complement */
 140 |     { "^",      T_OR,      P_OR     },  /*  23   17  Bitwise or */
 141 |     { "a",      T_REG,     REG_A    },  /*  24   18  Register */
 142 |     { "adc",    T_CARR,    I_ADC    },  /*  25   19 Add with Carry */
 143 |     { "add",    T_CADD,    I_ADD    },  /*  26   1a  Add */
 144 |     { "af",     T_REG,     REG_AF   },  /*  27   1b  Register */
 145 |     { "af'",    T_REG,     REG_AF1  },  /*  28   1c  Register */
 146 |     { "age",    T_COND,    COND_GE  },  /*  29   1d  Condition code Arithmetic greater or equal */
 147 |     { "alt",    T_COND,    COND_LT  },  /*  30   1e  Condition code Arithmetic less than */
 148 |     { "and",    T_3,       I_AND    },  /*  31   1f Logical AND */
 149 |     { "anz",    T_COND,    COND_NZ  },  /*  32   20  Condition code */
 150 |     { "az",     T_COND,    COND_Z   },  /*  33   21  Condition code */
 151 |     { "b",      T_REG,     REG_B    },  /*  34   22  Register b */
 152 |     { "bc",     T_REG,     REG_BC   },  /*  35   23  Register bc */
 153 |     { "bit",    T_BIT,     I_BIT    },  /*  36   24 Tests if the specified bit is set */
 154 |     { "c",      T_REG,     REG_C    },  /*  37   25  Register c */
 155 |     { "call",   T_CALL,    P_NA     },  /*  38   26  Call */
 156 |     { "ccf",    T_SIMPLE,  I_CCF    },  /*  39   27 Complement Carry Flag */
 157 |     { "cp",     T_3,       I_CP     },  /*  40   28 Compare */
 158 |     { "cpl",    T_SIMPLE,  I_CPL    },  /*  41   29 Complement */
 159 |     { "d",      T_REG,     REG_D    },  /*  42   2a  Register d */
 160 |     { "de",     T_REG,     REG_DE   },  /*  43   2b  Register de */
 161 |     { "dec",    T_INCDEC,  SI_DEC   },  /*  44   2c Decrement */
 162 |     { "defb",   T_DEFB,    P_NA     },  /*  45   2d  Definition byte */
 163 |     { "deff",   T_DEFF,    P_NA     },  /*  46   2e  Definition real */
 164 |     { "defl",   T_DEFL,    P_NA     },  /*  47   2f  Definition label */
 165 |     { "defm",   T_DEFM,    P_NA     },  /*  48   30  Definition a message */
 166 |     { "defs",   T_DEFS,    P_NA     },  /*  49   31  memory reservation */
 167 |     { "defw",   T_DEFW,    P_NA     },  /*  50   32  Definition word */
 168 |     { "di",     T_SIMPLE,  I_DI     },  /*  51   33 Disable Interrupts */
 169 |     { "djnz",   T_DJNZ,    I_DJNZ   },  /*  52   34  Dec., Jump Non-Zero */
 170 |     { "e",      T_REG,     REG_E    },  /*  53   35  Register */
 171 |     { "ei",     T_SIMPLE,  I_EI     },  /*  54   36 Enable Interrupts */
 172 |     { "equ",    T_EQU,     P_NA     },  /*  55   37  set value of symbol */
 173 |     { "ex",     T_EX,      P_NA     },  /*  56   38  Exchange */
 174 |     { "exx",    T_SIMPLE,  I_EXX    },  /*  57   39 Exchange */
 175 |     { "fge",    T_COND,    COND_GE  },  /*  58   3a  Condition code ge */
 176 |     { "flt",    T_COND,    COND_LT  },  /*  59   3b  Condition code lt */
 177 |     { "fnz",    T_COND,    COND_NZ  },  /*  60   3c  Condition code nz */
 178 |     { "fz",     T_COND,    COND_Z   },  /*  61   3d  Condition code z */
 179 |     { "global", T_GLB,     P_NA     },  /*  62   3e  Global */
 180 |     { "h",      T_REG,     REG_H    },  /*  63   3f  Register h */
 181 |     { "hl",     T_REG,     REG_HL   },  /*  64   40  Register hl */
 182 |     { "inc",    T_INCDEC,  SI_INC   },  /*  65   41 Increment */
 183 |     { "ix",     T_REG,     REG_IX   },  /*  66   42  Register ix */
 184 |     { "iy",     T_REG,     REG_IY   },  /*  67   43  Register iy */
 185 |     { "jp",     T_JP,      P_NA     },  /*  68   44  Absolute jumps to the address */
 186 |     { "jr",     T_JR,      I_JR     },  /*  69   45  Relative jumps to the address */
 187 |     { "l",      T_REG,     REG_L    },  /*  70   46  Register l */
 188 |     { "ld",     T_LD,      P_NA     },  /*  71   47  Load */
 189 |     { "ldir",   T_TWOBYTE, I_LDIR   },  /*  72   48 Load, Inc., Repeat */
 190 |     { "lge",    T_COND,    COND_LGE },  /*  73   49  Condition code Logical greater or equal */
 191 |     { "llt",    T_COND,    COND_LLT },  /*  74   4a  Condition code Logical less than */
 192 |     { "lnz",    T_COND,    COND_NZ  },  /*  75   4b  Condition code nz */
 193 |     { "lz",     T_COND,    COND_Z   },  /*  76   4c  Condition code z */
 194 |     { "m",      T_COND,    COND_LT  },  /*  77   4d  Condition code Arithmetic less than */
 195 |     { "nc",     T_COND,    COND_LGE },  /*  78   4e  Condition code lge */
 196 |     { "neg",    T_SIMPLE,  I_NEG    },  /*  79   4f Negates the accumulator */
 197 |     { "nop",    T_SIMPLE,  I_NOP    },  /*  80   50 No operation */
 198 |     { "nz",     T_COND,    COND_NZ  },  /*  81   51  Condition code */
 199 |     { "or",     T_3,       I_OR     },  /*  82   52 Logical inclusive OR */
 200 |     { "p",      T_COND,    COND_GE  },  /*  83   53  Condition code Arithmetic greater or equal */
 201 |     { "pop",    T_STK,     I_POP    },  /*  84   54  Stack operation pop */
 202 |     { "psect",  T_PSCT,    P_NA     },  /*  85   55  Psect */
 203 |     { "push",   T_STK,     I_PUSH   },  /*  86   56  Stack operation push */
 204 |     { "r",      T_REG,     REG_R    },  /*  87   57  Register r */
 205 |     { "res",    T_BIT,     I_RESB   },  /*  88   58 Reset bit */
 206 |     { "rl",     T_SHIFT,   I_RL     },  /*  89   59 */
 207 |     { "rla",    T_SIMPLE,  I_RLA    },  /*  90   5a */
 208 |     { "rlc",    T_SHIFT,   I_RLC    },  /*  91   5b */
 209 |     { "rlca",   T_SIMPLE,  I_RLCA   },  /*  92   5c */
 210 |     { "rld",    T_TWOBYTE, I_RLD    },  /*  93   5d */
 211 |     { "rr",     T_SHIFT,   I_RR     },  /*  94   5e */
 212 |     { "rra",    T_SIMPLE,  I_RRA    },  /*  95   5f */
 213 |     { "rrc",    T_SHIFT,   I_RRC    },  /*  96   60 */
 214 |     { "rrca",   T_SIMPLE,  I_RRCA   },  /*  97   61 */
 215 |     { "rrd",    T_TWOBYTE, I_RRD    },  /*  98   62 */
 216 |     { "rst",    T_RST,     I_RST    },  /*  99   63  Restart Commands */
 217 |     { "sbc",    T_CARR,    I_SBC    },  /* 100   64 Subtract with Carry */
 218 |     { "scf",    T_SIMPLE,  I_SCF    },  /* 101   65 Set Carry Flag */
 219 |     { "set",    T_BIT,     I_SETB   },  /* 102   66 Set bit */
 220 |     { "sla",    T_SHIFT,   I_SLA    },  /* 103   67 */
 221 |     { "sll",    T_SHIFT,   I_SLL    },  /* 104   68 */
 222 |     { "sp",     T_REG,     REG_SP   },  /* 105   69  Register sp */
 223 |     { "sra",    T_SHIFT,   I_SRA    },  /* 106   6a */
 224 |     { "srl",    T_SHIFT,   I_SRL    },  /* 107   6b */
 225 |     { "sub",    T_3,       I_SUB    },  /* 108   6c */
 226 |     { "xor",    T_3,       I_XOR    },  /* 109   6d */
 227 |     { "z",      T_COND,    COND_Z   }   /* 110   6e  Condition code */
 228 | };
 229 | 
 230 | #define NOPERATORS (sizeof(operators) / sizeof(operators[0]))
 231 | 
 232 | char * opt_msg[] = {				/* 68a3 */
 233 |     "Redundant labels",		/*  0	 0 */
 234 |     "Jumps to jumps",		/*  1	 1 */
 235 |     "Stack adjustments",	/*  2	 2 */
 236 |     "Temporary labels",		/*  3	 3 */
 237 |     "Unref'ed labels",		/*  4	 4 */
 238 |     "Unreachable code",		/*  5	 5 */
 239 |     "Jumps to .+1",		/*  6	 6 */
 240 |     "Skips over jumps",		/*  7	 7 */
 241 |     "Common code seq's",	/*  8	 8 */
 242 |     "Redundant exx's",		/*  9	 9 */
 243 |     "Ex (sp),hl's used",	/* 10	 a */
 244 |     "Redundant operations",	/* 11	 b */
 245 |     "Redundant loads/stores",	/* 12	 c */
 246 |     "Simplified addresses",	/* 13	 d */
 247 |     "Xor a's used",		/* 14	 e */
 248 |     "Redundant ex de,hl's",	/* 15	 f */
 249 |     "Code motions",		/* 16	10 */
 250 |     "Loops inverted"		/* 17	11 */
 251 | };
 252 | 
 253 | #define NOPTIM     (sizeof(opt_msg) / sizeof(opt_msg[0]))
 254 | 
 255 | int ccSwap[] = {				/* 68c7 */
 256 |     0, 2, 1, 4, 3, 6, 5, 8, 7
 257 | };
 258 | 
 259 | char * psectNames[] = {				/* 6a59 */
 260 |     "",		/*  0 */
 261 |     "text",	/*  1 */
 262 |     "data",	/*  2 */
 263 |     "bss",	/*  3 */
 264 |     "data"	/*  4 */
 265 | };
 266 | 
 267 | struct _s1 regHiLoMap[] = {
 268 |     { 0,     0     },				/* 6c50	REG_B  */
 269 |     { 0,     0     },				/* 6c52	REG_C  */
 270 |     { 0,     0     },				/* 6c54	REG_D  */
 271 |     { 0,     0     },				/* 6c56	REG_E  */
 272 |     { 0,     0     },				/* 6c58	REG_H  */
 273 |     { 0,     0     },				/* 6c5a	REG_L  */
 274 |     { 0,     0     },				/* 6c5c	REG_F  */
 275 |     { 0,     0     },				/* 6c5e	REG_A  */
 276 |     { 0,     0     },				/* 6c60	REG_I  */
 277 |     { 0,     0     },				/* 6c62	REG_R  */
 278 |     { REG_B, REG_C },				/* 6c64	REG_BC */
 279 |     { REG_D, REG_E },				/* 6c66	REG_DE */
 280 |     { REG_H, REG_L },				/* 6c68	REG_HL */
 281 | };
 282 | 
 283 | struct _s2 regHiLoValMap[] = {
 284 |     { ®Values[REG_BC], NULL	           },	/* 6c6a	REG_B   */
 285 |     { ®Values[REG_BC], NULL	           },	/* 6c6e REG_C   */
 286 |     { ®Values[REG_DE], NULL	           },	/* 6c72 REG_D   */
 287 |     { ®Values[REG_DE], NULL	           },	/* 6c76 REG_E   */
 288 |     { ®Values[REG_HL], NULL	           },	/* 6c7a REG_H   */
 289 |     { ®Values[REG_HL], NULL	           },	/* 6c7e REG_L   */
 290 |     { ®Values[REG_AF], NULL	           },	/* 6c82 REG_F   */
 291 |     { ®Values[REG_AF], NULL	           },	/* 6c86 REG_A   */
 292 |     { NULL,               NULL	           },	/* 6c8a REG_I   */
 293 |     { NULL,               NULL	           },	/* 6c8e REG_R   */
 294 |     { ®Values[REG_B], ®Values[REG_C] },	/* 6c92 REG_BC  */
 295 |     { ®Values[REG_D], ®Values[REG_E] },	/* 6c96 REG_DE  */
 296 |     { ®Values[REG_H], ®Values[REG_L] },	/* 6c9a REG_HL  */
 297 |     { NULL,               NULL	           },	/* 6c9e REG_SP  */
 298 |     { ®Values[REG_A], ®Values[REG_F] },	/* 6ca2 REG_AF  */
 299 |     { NULL,               NULL	           },	/* 6ca6 REG_AF1 */
 300 |     { NULL,               NULL	           },	/* 6caa REG_IX  */
 301 |     { NULL,               NULL	           }    /* 6cae REG_IY  */
 302 | };
 303 | 
 304 | /*
 305 |  *	Common code sequences
 306 |  */
 307 | #define PEEKCH() (charsLeft > 0 ? *ptr_inbuf : '\n')
 308 | #define GETCH()  (--charsLeft >= 0 ? *ptr_inbuf++ : get_line())
 309 | 
 310 | /**************************************************************************
 311 |  1	strtoi	sub_013d	ok++	Used in const_value
 312 |  *
 313 |  *	Converts a numeric string, in various bases, to a integer
 314 |  **************************************************************************/
 315 | int strtoi(char const *s, int base) {
 316 |     int val;   /* number */
 317 |     int digit; /* digit */
 318 | 
 319 |     val = 0;
 320 |     while (*s) {
 321 |         val *= base;
 322 |         if (ISDIGIT(*s)) {
 323 |             digit = *(s++) - '0';
 324 |         } else {
 325 |             if (ISXDIGIT(*s)) {
 326 |                 digit = (ISUPPER(*s) ? (char)(*s | 0x20) : (char) * s) - ('a' - 10);
 327 |             }
 328 |         }
 329 |         /* #pragma warning(suppress : 6001) /* function only called after verified there is a digit */
 330 |         if (digit >= base) {
 331 |             pr_warning("Digit out of range");
 332 |             return 0;
 333 |         }
 334 |         val += digit;
 335 |     }
 336 |     return val;
 337 | }
 338 | 
 339 | /**************************************************************************
 340 |  2	ptr_token	sub_020f	ok++
 341 |  *
 342 |  *	Returns a pointer to a token
 343 |  **************************************************************************/
 344 | char *ptr_token() {
 345 |     register char *s;
 346 | 
 347 |     s = yyline;
 348 |     while (PEEKCH() != 0 && PEEKCH() != '\n') {
 349 |         *s++ = GETCH();
 350 |     }
 351 |     *s        = '\0';
 352 |     charsLeft = 0;
 353 |     return yyline;
 354 | }
 355 | 
 356 | /**************************************************************************
 357 |  3	const_value	sub_0289	ok+
 358 |  *
 359 |  *	Rerurn integer value numeric string in various bases
 360 |  *	Generates correct code, but in a different sequence
 361 |  **************************************************************************/
 362 | int const_value() {
 363 |     register char *pc;
 364 |     uint8_t base;
 365 | 
 366 |     pc   = yyline + 1;
 367 |     base = 0;
 368 |     while (ISXDIGIT(PEEKCH())) {
 369 |         *pc++ = GETCH();
 370 |     }
 371 | 
 372 |     switch (PEEKCH()) { /* m17: */
 373 |         case 'H':
 374 |         case 'h':
 375 |             base = 16;
 376 |             /* #pragma warning(suppress : 6269) /* deference ignored - original code did the dreference */
 377 |             GETCH();
 378 |             break;
 379 | 
 380 |         case 'O':
 381 |         case 'o':
 382 |         case 'Q':
 383 |         case 'q':
 384 |             base = 8;
 385 |             /* #pragma warning(suppress : 6269) /* deference ignored - original code did the dreference */
 386 |             GETCH();
 387 |             break;
 388 |         default:
 389 |             if (pc[-1] == 'f' || pc[-1] == 'b') {
 390 |                 yytype   = *--pc == 'f' ? T_FWD : T_BWD;
 391 |                 *pc      = '\0';
 392 |                 yylval.i = (int16_t)strtoi(yyline, 10);
 393 |                 return yytype;
 394 |             }
 395 |             if (pc[-1] == 'B') {
 396 |                 pc--;
 397 |                 base = 2;
 398 |             }
 399 |             break;
 400 |     }
 401 |     *pc = '\0';
 402 |     if (base == 0) {
 403 |         base = 10;
 404 |     }
 405 |     yylval.i = (int16_t)strtoi(yyline, base);
 406 |     return T_CONST;
 407 | }
 408 | 
 409 | /**************************************************************************
 410 |  4  get_token   sub_03c7    ok++ (PMO)
 411 |  **************************************************************************/
 412 | int get_token() {
 413 |     int c;
 414 |     register char *pc;
 415 | 
 416 |     for (;;) {
 417 |         pc = yyline;
 418 | 
 419 |         switch (c = GETCH()) {
 420 |             case -1:
 421 |                 return -1;
 422 |             case '\t':
 423 |             case '\f':
 424 |             case ' ':
 425 |                 continue;
 426 |             case 0:
 427 |             case ';':
 428 |                 return T_EOL;
 429 |             case '\'': /* Single quote (apostrophe) */
 430 |                 while (PEEKCH() && PEEKCH() != '\'') {
 431 |                     *pc++ = GETCH();
 432 |                 }
 433 |                 if (PEEKCH() == '\'')
 434 |                     /* #pragma warning(suppress : 6269) /* deference ignored - original code did the dreference */
 435 |                 {
 436 |                     GETCH();
 437 |                 } else {
 438 |                     pr_warning("Unterminated string");
 439 |                 }
 440 |                 *pc          = '\0';
 441 |                 yylval.pChar = yyline;
 442 |                 return T_STRING;
 443 | 
 444 |             case '.':
 445 |                 *pc++ = c;
 446 |                 while (ISALPHA(PEEKCH())) {
 447 |                     *pc++ = GETCH();
 448 |                 }
 449 |                 if (PEEKCH() == '.') {			/* m27: */
 450 |                     *pc++ = GETCH();
 451 |                 }
 452 |                 break;
 453 |             case ',':
 454 |                 return T_COMM;				/* m31: */
 455 | 
 456 |             case ':':
 457 |                 return T_COLN;				/* m32: */
 458 | 
 459 |             case '(':
 460 |                 yylval.i = P_OPAR;			/* m33: */
 461 |                 return T_OPAR;
 462 | 
 463 |             case ')':
 464 |                 yylval.i = P_CPAR;			/* m34: */
 465 |                 return T_CPAR;
 466 | 
 467 |             case '+':
 468 |                 yylval.i = P_ADD;			/* m35: */
 469 |                 return T_PLUS;
 470 | 
 471 |             case '-':
 472 |                 yylval.i = P_SUB;			/* m36: */
 473 |                 return T_MINUS;
 474 | 
 475 |             case '*':
 476 |                 if (ptr_inbuf == inp_buf + 1) {
 477 |                     printf("%s\n", inp_buf);
 478 |                     charsLeft = 0;
 479 |                     continue;
 480 |                 }
 481 |             default:
 482 |                 *pc++ = c;
 483 |                 if (ISALPHA(c)) {
 484 |                     while (ISALNUM(PEEKCH())) {		/* m41: */
 485 |                         *pc++ = GETCH();
 486 |                     }
 487 |                     if (pc == yyline + 2) {
 488 |                         if (PEEKCH() == '\'') {
 489 |                             *pc++ = GETCH();
 490 |                         }
 491 |                     }
 492 |                 } else if (ISDIGIT(c)) {
 493 |                     return const_value();
 494 |                 }
 495 |                 break;
 496 |         }
 497 |         while (ISSPACE(PEEKCH()))
 498 |             /* #pragma warning(suppress : 6269) /* deference ignored - original code did the dreference */
 499 |         {
 500 |             GETCH();
 501 |         }
 502 | 
 503 |         *pc = '\0';
 504 |         if (yyline[0] == '_' || ISDIGIT(pc[-1]) || ((yytype = num_token(yyline)) == -1)) {
 505 |             if (ISALPHA(yyline[0])) {			/* m57: */
 506 |                 yylval.pSym = lookupSym(yyline);
 507 |                 return T_SYMBOL;
 508 |             }
 509 |             pr_warning("Lexical error");		/* m58: */
 510 |         } else {
 511 |             return yytype;				/* m59: */
 512 |         }
 513 |     }
 514 | }
 515 | 
 516 | /**************************************************************************
 517 |  5	get_line	sub_0758	ok++ (PMO)
 518 |  *	Optimiser eliminates a jump otherwise code is identical
 519 |  **************************************************************************/
 520 | /* PMO this code contains a bug. If strlen returns a 0 it accesses inp_buf[-1]
 521 |  * and could overwrite with a 0, this could occur if there is a '\0' in the input stream
 522 |  * it is also not clear whether a blank line i.e. one with just a '\n' should
 523 |  * return with a '\0' as it currently does or try another line
 524 |  *
 525 |  * Note needs fixing for linux as '\r' will not be removed on input
 526 |  *
 527 |  * The compiler can generate comment lines > 80 chars, this causes this function
 528 |  * to split the line which may cause the optimiser to get confused
 529 |  * a simple option would be to extend the size of inp_buf alternatively as the only
 530 |  * long lines appear to be comment ones. A better option would be to detect for a missing '\n'
 531 |  * and junk the rest of the line
 532 |  *
 533 |  * WARNING: The Hitech fgets contains a bug in that if line read has length >= size
 534 |  * it will write a 0 at buf[size], for optim this is the -l option flag
 535 |  *
 536 |  */
 537 | #ifdef CPM
 538 | int get_line() {
 539 |     for (;;) {
 540 |         if (fgets(inp_buf, sizeof(inp_buf), stdin) == NULL) {
 541 |             return -1;
 542 |         }
 543 |         charsLeft = (int)strlen(ptr_inbuf = inp_buf);
 544 |         if (inp_buf[charsLeft - 1] == '\n') { /* If penultimate character is */
 545 |             inp_buf[charsLeft - 1] = '\0';    /* '\n' then replace it with 0 */
 546 |         }
 547 |         if (--charsLeft >= 0) {             /* got something */
 548 |             return *ptr_inbuf++;            /* otherwise, return first character of string */
 549 |         }
 550 |     }
 551 | }
 552 | 
 553 | #else
 554 | #define CPMEOF  0x1A
 555 | 
 556 | int get_line() {
 557 |     int c;
 558 | 
 559 |     charsLeft = 0;
 560 |     while ((c = getchar()) != '\n' && c != EOF && c != CPMEOF)
 561 |         if (charsLeft < sizeof(inp_buf) - 1 && c != '\r') {
 562 |             inp_buf[charsLeft++] = c;
 563 |         }
 564 |     inp_buf[charsLeft] = '\0';
 565 |     ptr_inbuf          = inp_buf;
 566 |     return charsLeft || (c != EOF && c != CPMEOF) ? *ptr_inbuf++ : EOF;
 567 | }
 568 | #endif
 569 | 
 570 | /**************************************************************************
 571 |  6	clr_len_inbuf	sub_0758  ok++	Used in: getOperands, loadFunction
 572 |  **************************************************************************/
 573 | void clr_len_inbuf() {
 574 | 
 575 |     charsLeft = 0;
 576 | }
 577 | 
 578 | /**************************************************************************
 579 |  7  main    sub_07b1    ok++ (PMO)
 580 |  *
 581 |  *  In the switch statement the location of the code blocks for 's' and
 582 |  *  default are swapped by the optimiser, otherwise the code is identical
 583 |  **************************************************************************/
 584 | int main(int argc, char **argv) {
 585 | 
 586 |     --argc, ++argv; /* would be cleaner as a for loop */
 587 |     while (0 < argc && argv[0][0] == '-') {
 588 |         switch (argv[0][1]) {
 589 |             case 'N':
 590 |             case 'n':
 591 |                 key_n = true;
 592 |                 break; /* Enables statistics printing */
 593 | 
 594 |             case 'L':
 595 |             case 'l':
 596 |                 key_l = true;
 597 |                 break; /* Enables printing of additional information */
 598 | 
 599 |             case 'R':
 600 |             case 'r':
 601 |                 key_r = true;
 602 |                 break; /* Disables register load optimisation */
 603 | 
 604 |             case 'F':
 605 |             case 'f':
 606 |                 key_f = true;
 607 |                 break; /* use inline frame initialisation */
 608 | 
 609 |             case 's':
 610 |                 key_s = true;
 611 |                 break; /* Unbuffered stdout */
 612 |             default:
 613 |                 pr_error("Illegal switch %c", argv[0][1]);
 614 |                 break;
 615 |         }
 616 |         ++argv, --argc;
 617 |     }
 618 |     if (argc > 0) {
 619 |         if (!freopen(*argv, "r", stdin)) {
 620 |             pr_error("Can't open %s", *argv);
 621 |         }
 622 | 
 623 |         if (argc > 1 && !freopen(*(argv + 1), "w", stdout)) {
 624 |             pr_error("Can't create %s", *(argv + 1));
 625 |         }
 626 |     }
 627 |     if (key_s) {
 628 |         setbuf(stdout, 0);    /* Unbuffered stdout (Turns off buffering) */
 629 |     }
 630 | 
 631 |     optimise();
 632 | 
 633 |     if (fclose(stdout) == -1) {
 634 |         pr_warning("Error closing output file");
 635 |         ++num_warn;
 636 |     }
 637 |     exit(num_warn != 0);
 638 | }
 639 | 
 640 | /**************************************************************************
 641 |  8	pr_error	sub-0941	ok++
 642 |  **************************************************************************/
 643 | #ifdef CPM
 644 | void pr_error(fmt, p2, p3) char * fmt;
 645 | {
 646 |     pr_message(fmt, p2, p3);
 647 |     fclose(stdout);
 648 |     exit(1);
 649 | }
 650 | 
 651 | /**************************************************************************
 652 |  9	pr_warning	sub_096f	ok++
 653 |  **************************************************************************/
 654 | void pr_warning(fmt, p2, p3) char *fmt;
 655 | {
 656 |     pr_message(fmt, p2, p3);
 657 |     ++num_warn;
 658 | }
 659 | 
 660 | /**************************************************************************
 661 |  10	pr_message	sub_0994	ok++
 662 |  **************************************************************************/
 663 | void pr_message(fmt, p2, p3) char * fmt;
 664 | {
 665 |     fprintf(stderr, "optim: ");
 666 |     fprintf(stderr, fmt, p2, p3);
 667 |     fputc('\n', stderr);
 668 | }
 669 | 
 670 | #else
 671 | 
 672 | void pr_error(char const * fmt, ...) {
 673 |     va_list args;
 674 | 
 675 |     va_start(args, fmt);
 676 |     pr_message(fmt, args);
 677 |     va_end(args);
 678 |     exit(1);
 679 | }
 680 | 
 681 | void pr_warning(char const * fmt, ...) {
 682 |     va_list args;
 683 | 
 684 |     va_start(args, fmt);
 685 |     pr_message(fmt, args);
 686 |     va_end(args);
 687 |     ++num_warn;
 688 | }
 689 | 
 690 | void pr_message(char const * fmt, va_list args) {
 691 | 
 692 |     fprintf(stderr, "optim: ");
 693 |     vfprintf(stderr, fmt, args);
 694 |     fputc('\n', stderr);
 695 | }
 696 | 
 697 | #endif
 698 | 
 699 | /**************************************************************************
 700 |  11	find_token	sub_09d0	ok++	Used in: num_token
 701 |  *
 702 |  *	Binary search is used
 703 |  * Minor difference after strcmp. the code sequence
 704 |  * original           new
 705 |  * ld (ix-1),l        ld a,l
 706 |  * ld a,l             ld (ix-1),a
 707 | **************************************************************************/
 708 | int find_token(register char const *str, operator_t const *p2, int p3) {
 709 |     char    cmp;
 710 |     uint8_t high, low, mid;
 711 | 
 712 |     tableBase = p2;
 713 |     low       = 0;
 714 |     high      = p3 - 1;
 715 |     do {
 716 |         mid = (high + low) / 2;
 717 |         cmp = strcmp(str, tableBase[mid].str);
 718 |         if (cmp == 0) {
 719 |             yylval.i = tableBase[mid].aux;
 720 |             yytext   = tableBase[mid].str;
 721 |             return tableBase[mid].type;
 722 |         }
 723 |         if (cmp < 0) {
 724 |             high = mid - 1;
 725 |         } else {
 726 |             low = mid + 1;
 727 |         }
 728 |     } while (high >= low);
 729 |     return -1;
 730 | }
 731 | 
 732 | /**************************************************************************
 733 |  12	num_token	sub_0a97	ok++	Used in
 734 |  **************************************************************************/
 735 | int num_token(char const *fmt) {
 736 | 
 737 |     return find_token(fmt, operators, NOPERATORS);
 738 | }
 739 | 
 740 | /**************************************************************************
 741 |  13	pr_token	sub_0ab2	ok++ (PMO)
 742 |  Only difference is the new code jumps to a location that cleans up
 743 |  stack after a call before jumping to cret. The direct jp cret also works
 744 |  **************************************************************************/
 745 | void pr_token(register inst_t const *pi) {
 746 |     operator_t const *po;
 747 | 
 748 |     if (pi->opCode) {
 749 |         printf("%s", pi->opCode);
 750 |         return;							/* m1: */
 751 |     }
 752 | 
 753 |     switch (pi->type) {						/* m2: */
 754 |         case T_JP:
 755 |             printf("jp");
 756 |             return;
 757 |         case T_CALL:
 758 |             printf("call");
 759 |             return;
 760 |         case T_RET:
 761 |             printf("ret");
 762 |             return;
 763 |     }
 764 | 
 765 |     po = operators + NOPERATORS; /* PMO should not be + 1 */
 766 |     do {
 767 |         if (--po < operators) {					/* m3: */
 768 |             pr_error("Can't find op");
 769 |             return;
 770 |         }
 771 |     } while ((pi->type != po->type) || (po->aux != pi->aux));	/* m8: */
 772 | 
 773 |     printf("%s", po->str);
 774 |     return;
 775 | }
 776 | 
 777 | /**************************************************************************
 778 |  14	freeOperand	sub_0b6a	ok++
 779 |  **************************************************************************/
 780 | void freeOperand(register operand_t *po) {
 781 | 
 782 |     if (!po) {
 783 |         return;
 784 |     }
 785 |     ((list_t *)po)->pNext = freeOperandList;
 786 |     freeOperandList       = (list_t *)po;
 787 | }
 788 | 
 789 | /**************************************************************************
 790 |  15	freeInst	sub_0b8b	ok++
 791 |  **************************************************************************/
 792 | void freeInst(register inst_t *pi) {
 793 | 
 794 |     pi->pAlt     = freeInstList;
 795 |     freeInstList = pi;
 796 | }
 797 | 
 798 | /**************************************************************************
 799 |  16	allocOperand	sub_0ba7	ok++
 800 |  *			Used in: sub_1795, sub_1c67, sub_1d94, sub_29c3,
 801 |  *				 sub_2bdb, sub_3053, evalOperand
 802 |  **************************************************************************/
 803 | operand_t *allocOperand() {
 804 |     register operand_t *pi;
 805 | 
 806 |     if (freeOperandList) {
 807 |         pi = (operand_t *)freeOperandList;
 808 |         HEAP(pi);
 809 |         freeOperandList = ((list_t *)pi)->pNext;
 810 |         pi->type = pi->aux = 0;
 811 |         pi->oVal           = 0;
 812 |         pi->oPSym          = NULL;
 813 |         return pi;
 814 |     }
 815 |     return (operand_t *)alloc_mem(sizeof(operand_t));
 816 | }
 817 | 
 818 | /**************************************************************************
 819 |  17	allocInst	sub_0be2	ok++		Used in:
 820 |  **************************************************************************/
 821 | inst_t *allocInst(register inst_t *pi) {
 822 |     inst_t *l1;
 823 | 
 824 |     HEAP(pi->pNext);
 825 |     if ((l1 = freeInstList)) {
 826 |         HEAP(l1);
 827 |         freeInstList = l1->pAlt;
 828 |         l1->type = l1->aux = 0;
 829 |         l1->iLhs = l1->iRhs = NULL;
 830 |         l1->opCode          = NULL;
 831 |     } else {
 832 |         l1 = alloc_mem(sizeof(inst_t));
 833 |     }
 834 |     l1->pNext = pi->pNext;
 835 |     l1->pAlt  = pi;
 836 |     if (pi->pNext) {
 837 |         HEAP(pi->pNext);
 838 |         pi->pNext->pAlt = l1;
 839 |     }
 840 |     HEAP(l1);
 841 |     return pi->pNext = l1;
 842 | }
 843 | 
 844 | /**************************************************************************
 845 |  18	syntheticLabel	sub_0ca2	ok++		Used in: 
 846 |  **************************************************************************/
 847 | inst_t *syntheticLabel(register inst_t *pi) {
 848 | 
 849 |     pi                = allocInst(pi);
 850 |     pi->iPSym         = allocBlankSym();
 851 |     pi->iSymId        = ++symbolId;
 852 |     pi->iPSym->tPInst = pi;
 853 |     pi->type          = T_SYMBOL;
 854 |     return pi;
 855 | }
 856 | 
 857 | /**************************************************************************
 858 | 19  optimise    sub-0ce4    ok++ (PMO)
 859 | Apart from bug fix change, the code is the same
 860 | **************************************************************************/
 861 | void optimise() {
 862 |     int   l1;
 863 |     int   l2;
 864 |     int   iteration;
 865 |     char *l4;
 866 |     bool  l5;
 867 |     char *l6;
 868 | 
 869 |     l6 = l4   = sbrk(0); /* PMO bug fix set l6 */
 870 |     iteration = 0;
 871 |     while (!feof(stdin)) { /* not eof */
 872 |         freeInstList    = NULL;
 873 |         freeOperandList = NULL;
 874 |         resetHeap();
 875 |         loadFunction();
 876 |         freeHashtab();
 877 |         sub_0ed1();
 878 |         chkIXYUsage();
 879 |         sub_122f();
 880 | 
 881 |         l2 = 0;
 882 |         do {
 883 |             if (iteration < ++l2) {
 884 |                 iteration = l2;
 885 |             }
 886 | 
 887 |             if (key_l) {
 888 |                 printf("***** Pass %d\n", l2);
 889 |                 sub_404d();
 890 |             }
 891 |             l5 = false;
 892 |             do {
 893 |                 hasChanged = false; /* m5: */
 894 |                 sub_15ad();
 895 |                 l5 |= hasChanged;
 896 |             } while (hasChanged);
 897 |             do {
 898 |                 hasChanged = false; /* m6: */
 899 |                 sub_1ec1();
 900 |             } while (hasChanged);
 901 | 
 902 |         } while ((l5 |= hasChanged));
 903 | 
 904 |         sub_404d();
 905 | 
 906 |         if (l6 < (char *)sbrk(0)) {
 907 |             l6 = sbrk(0);
 908 |         }
 909 |     } /* end while */
 910 | 
 911 |     if (!key_n) {
 912 |         return;
 913 |     }
 914 | 			/*    / This statement results in an error when */
 915 |     fclose(stdout);	/* <-+  standard output is closed again in main */
 916 | 			/*    \ program. It can be removed.             */
 917 | 
 918 |     fprintf(stderr, "%dK, %d iterations\n", ((int)(l6 - l4) + 0x3ff) / 0x400, iteration);
 919 | 
 920 |     for (l1 = 0; l1 < NOPTIM; l1++)
 921 |         if (optimiseCounters[l1] != 0) {
 922 |             fprintf(stderr, "%d %s\n", optimiseCounters[l1], opt_msg[l1]);
 923 |         }
 924 | }
 925 | 
 926 | /**************************************************************************
 927 |  20	chkIXYUsage	sub_0e67	ok++	Used in: optimise
 928 |  **************************************************************************/
 929 | void chkIXYUsage() {
 930 |     register inst_t const *pi;
 931 | 
 932 |     usesIXorIY = false;
 933 |     for (pi = root; pi; pi = pi->pNext) {
 934 |         if (pi->type != T_SYMBOL &&
 935 |                 ((pi->iLhs && pi->iLhs->type == T_INDEXED) || (pi->iRhs && pi->iRhs->type == T_INDEXED) ||
 936 |                  (pi->iLhs && pi->iLhs->type == T_REG && pi->iLhs->aux >= REG_IX))) {
 937 |             usesIXorIY = true;
 938 |             return;
 939 |         }
 940 |     }
 941 | }
 942 | 
 943 | /**************************************************************************
 944 |  21	sub_0ed1			ok++	used in optimise
 945 |  **************************************************************************/
 946 | void sub_0ed1() {
 947 |     inst_t    *pi2;
 948 |     operand_t *po;
 949 |     bool       newLabel; /* Flag of the sub_0ca2 call */
 950 |     register inst_t *pi1;
 951 | 
 952 |     for (pi1 = word_6ffc; pi1; pi1 = pi1->pAlt) {
 953 |         if (pi1->type == T_CONST) {
 954 |             newLabel = false;
 955 |             logOptimise(O_TMP_LAB); /* 6fc3 opt_msg[3] = "Temporary labels" */
 956 |             for (pi2 = pi1->pAlt; pi2; pi2 = pi2->pAlt) {
 957 |                 if (pi2->type == T_CONST && pi2->aux == pi1->aux) {
 958 |                     break;
 959 |                 }
 960 |                 if ((po = pi2->iLhs) && po->type == T_FWD && po->oVal == pi1->aux) {
 961 |                     if (!newLabel) {
 962 |                         syntheticLabel(pi1);
 963 |                         newLabel = true;
 964 |                     }
 965 |                     po->type      = T_CONST;
 966 |                     po->oPOperand = pi1->pNext->iLhs;
 967 |                     po->oVal      = 0;
 968 |                 }
 969 |             }
 970 |             if (pi1->aux < REG_BC) { /* m7: */
 971 |                 if (!newLabel) {
 972 |                     syntheticLabel(pi1);
 973 |                 }
 974 |                 for (pi2 = pi1->pNext; pi2; pi2 = pi2->pNext) {
 975 |                     if ((po = pi2->iLhs) && po->type == T_BWD && po->oVal == pi1->aux) {
 976 |                         po->type      = T_CONST;
 977 |                         po->oPOperand = pi1->pNext->iLhs;
 978 |                         po->oVal      = 0;
 979 |                         break;
 980 |                     }
 981 |                 }
 982 |             }
 983 |             pi1 = pi1->pNext; /* m12: */
 984 |             removeInstruction(pi1->pAlt);
 985 |         }
 986 |     }
 987 | }
 988 | 
 989 | /**************************************************************************
 990 |  22	sub_1071			ok++	used in sub_15ad
 991 |  **************************************************************************/
 992 | bool sub_1071(register inst_t *pi) {
 993 |     inst_t *pi1;
 994 |     inst_t *pi2;
 995 |     inst_t *pi3;
 996 | 
 997 |     if (pi->type != T_JP || pi->aux != 0 || pi->iLhs->type != T_CONST) {
 998 |         return false;
 999 |     }
1000 | 
1001 |     pi1 = pi->iLhs->oPSym->p.pInst;
1002 |     while (pi1->type == T_SYMBOL) {
1003 |         pi1 = pi1->pAlt;
1004 |     }
1005 | 
1006 |     if (pi1 == pi) {
1007 |         removeInstruction(pi);
1008 |         logOptimise(O_JMP_TO_PLUS1); /* 6fc9 opt_msg[6] = "Jumps to .+1" */
1009 |         return false;
1010 |     }
1011 |     if (pi1->type != T_JP || pi1->aux != 0) {
1012 |         return false;
1013 |     }
1014 | 
1015 |     for (pi3 = pi1->pNext; pi3->type && (pi3->type != T_JP || pi3->aux != 0); pi3 = pi3->pNext)
1016 |         ;
1017 | 
1018 |     if (pi3 == pi1->pNext || pi3->type == T_INVALID || pi3 == pi) {
1019 |         return false;
1020 |     }
1021 | 
1022 |     pi->pNext->pAlt  = pi3;
1023 |     pi1->pNext->pAlt = pi;
1024 | 
1025 |     pi3->pNext->pAlt = pi1;
1026 | 
1027 |     pi2              = pi1->pNext;
1028 |     pi1->pNext       = pi3->pNext;
1029 |     pi3->pNext       = pi->pNext;
1030 |     pi->pNext        = pi2;
1031 |     logOptimise(O_CODE_MOTIONS); /* 6fdd opt_msg[16] = "Code motions" */
1032 |     removeInstruction(pi);
1033 |     return logOptimise(O_JMP_TO_PLUS1); /* 6fc9 opt_msg[6] = "Jumps to .+1" */
1034 | }
1035 | 
1036 | /**************************************************************************
1037 |  23	sub_122f	ok++	Used in: optimise
1038 |  **************************************************************************/
1039 | void sub_122f() {
1040 |     operand_t *po;
1041 |     register inst_t *pi;
1042 | 
1043 |     for (pi = root->pNext; pi; pi = pi->pNext) /* set initial values for symbols */
1044 |         if (pi->type == T_SYMBOL)
1045 |             if (pi->iPSym->label[0] == '_') { /* check for public name */
1046 |                 pi->aux = INT_MAX;
1047 |             } else {
1048 |                 pi->aux = 0;
1049 |             }
1050 | 
1051 |     for (pi = root->pNext; pi; pi = pi->pNext) { /* update reference counts */
1052 |         if (pi->type == T_JP || pi->type == T_DJNZ) {
1053 |             if ((po = pi->iLhs) && po->type == T_CONST && po->oPSym && po->oPSym->p.pInst) {
1054 |                 po->oPSym->p.pInst->aux++;
1055 |             }
1056 |         }
1057 |     }
1058 |     for (pi = switchVectors; pi; pi = pi->pNext) { /* do the same for the jump tables */
1059 |         if (pi->type == T_DEFW) {
1060 |             if (pi->iLhs && (po = pi->iLhs)->type == T_CONST && po->oPSym && po->oPSym->p.pInst) {
1061 |                 po->oPSym->p.pInst->aux++;
1062 |             }
1063 |         }
1064 |     }
1065 | }
1066 | 
1067 | /**************************************************************************
1068 |  24	sub_1369	ok++ (PMO)
1069 |  **************************************************************************/
1070 | bool sub_1369(register operand_t const *pi) {
1071 | 
1072 |     return pi->type == T_CONST || pi->type == T_INDEXED || (pi->type == T_REGREF && pi->aux == REG_HL);
1073 | }
1074 | 
1075 | /**************************************************************************
1076 |  25	sub_1397	ok++ (PMO)
1077 |  **************************************************************************/
1078 | /* note there are occasions when pi is accessed after this is called so
1079 |  * freeInst has to preserve at least pi->pNext
1080 |  */
1081 | void removeInstruction(register inst_t *pi) {
1082 | 
1083 |     if (pi->type == T_JP && pi->iLhs->type == T_CONST && pi->iLhs->oPSym) {
1084 |         removeLabelRef(pi->iLhs->oPSym);
1085 |     }
1086 | 
1087 |     pi->pAlt->pNext = pi->pNext;
1088 |     pi->pNext->pAlt = pi->pAlt;
1089 |     if (pi->type != T_SYMBOL) {
1090 |         freeOperand(pi->iLhs);
1091 |         freeOperand(pi->iRhs);
1092 |     }
1093 |     freeInst(pi);
1094 | }
1095 | 
1096 | /**************************************************************************
1097 |  26	sub_140b	ok++
1098 |  **************************************************************************/
1099 | inst_t *getNextRealInst(register inst_t *pi) {
1100 | 
1101 |     while (pi->type == T_SYMBOL) {
1102 |         pi = pi->pNext;
1103 |     }
1104 |     return pi;
1105 | }
1106 | 
1107 | /**************************************************************************
1108 |  27	sub_142f	ok++
1109 |  **************************************************************************/
1110 | bool operandsSame(register operand_t const *po1, operand_t const *po2) {
1111 | 
1112 |     if (!po1 && !po2) {
1113 |         return true;
1114 |     }
1115 |     if (!po1 || !po2) {
1116 |         return false;
1117 |     }
1118 | 
1119 |     if (po1->type != po2->type || po1->aux != po2->aux || po1->type == T_INVALID) {
1120 |         return false;
1121 |     }
1122 | 
1123 |     return po1->oPSym == po2->oPSym && po1->oVal == po2->oVal;
1124 | }
1125 | 
1126 | /**************************************************************************
1127 |  28	instructionsSame	sub_14ac	ok++
1128 |  **************************************************************************/
1129 | bool instructionsSame(register inst_t const *pi1, inst_t const *pi2) {
1130 | 
1131 |     if (pi1->type == T_INVALID || pi1->type == T_SYMBOL || pi2->type == T_INVALID || pi2->type == T_SYMBOL) {
1132 |         return false;
1133 |     }
1134 | 
1135 |     if (pi1->type != pi2->type || pi1->aux != pi2->aux) {
1136 |         return false;
1137 |     }
1138 | 
1139 |     return operandsSame(pi1->iLhs, pi2->iLhs) && operandsSame(pi1->iRhs, pi2->iRhs);
1140 | }
1141 | 
1142 | /**************************************************************************
1143 |  29	sub_153d	ok++
1144 |  **************************************************************************/
1145 | void removeLabelRef(register sym_t *ps) {
1146 |     inst_t *pi;
1147 | 
1148 |     if (!(pi = ps->p.pInst)) {
1149 |         return;
1150 |     }
1151 |     if (pi->aux == 0) {
1152 |         pr_error("Refc == 0");
1153 |     }
1154 |     if (--pi->aux != 0) {
1155 |         return;
1156 |     }
1157 |     removeInstruction(pi);
1158 |     ps->p.pInst = NULL;
1159 |     freeSymbol(ps);
1160 |     logOptimise(O_UNREF_LAB); /* 6fc5 opt_msg[4] = "Unref'ed labels" */
1161 | }
1162 | 
1163 | /**************************************************************************
1164 |  30	sub_15ad	ok++	(PMO) Used in optimize
1165 |  *
1166 |  * code optimised over original as noted below, otherwise identical
1167 |  * 1) for loop iteration expression moved
1168 |  * 2) code to increment an optiminse counter & set hasChanged = true shared
1169 |  * 3) sub_1d94() == 0, test removed as code falls through in either case
1170 |  **************************************************************************/
1171 | #if 1
1172 | 
1173 | void sub_15ad() {
1174 | //    register inst_t *pi;
1175 | 
1176 |     for (gPi = root; gPi; gPi = gPi->pNext) {
1177 |         if (!sub_1795() && gPi->type == T_JP && !sub_1aec() && !sub_1b86()) {
1178 |             if (gPi->iLhs->type == T_CONST && gPi->iLhs->oPSym->p.pInst == gPi->pNext) {
1179 |                 removeInstruction(gPi);
1180 |                 logOptimise(O_JMP_TO_PLUS1); /* 6fc9 opt_msg[6] = "Jumps to .+1" */
1181 |             } else {
1182 |                 if (gPi->aux == 0) { /* 1648 / 164B */
1183 |                     while (gPi->pNext->type != T_INVALID && gPi->pNext->type != T_SYMBOL) {
1184 |                         removeInstruction(gPi->pNext);
1185 |                         logOptimise(O_UNREACH_LAB); /* 6fc7 opt_msg[5] = "Unreachable code" */
1186 |                     }
1187 |                     if (gPi->iLhs->type != T_REGREF && gPi->iLhs->oPSym->p.pInst && sub_1071(gPi)) {
1188 |                         continue;
1189 |                     }
1190 |                 }
1191 |                 if (gPi->iLhs->type == T_CONST && (gPi->pNext->type == T_CALL || gPi->pNext->type == T_JP) &&
1192 |                         gPi->pNext->aux == 0 && gPi->iLhs->oPSym->p.pInst == gPi->pNext->pNext) {
1193 |                     gPi->pNext->aux = ccSwap[gPi->aux]; /* swap condition code */
1194 |                     removeInstruction(gPi);
1195 |                     logOptimise(O_SKIP_OVER_JMP); /* 6fcb opt_msg[7] = "Skips over jumps" */
1196 |                 } else if (sub_1c67() || !sub_1d94())
1197 |                     ;
1198 |             }
1199 |         }
1200 |     }
1201 | }
1202 | 
1203 | #else
1204 | 
1205 | void sub_15ad() {
1206 |     register inst_t * pi;
1207 | 
1208 | #ifdef DDEBUG
1209 |     printf("\n\tsub_15ad\n");
1210 | #endif
1211 |     gPi = root;
1212 |     while(gPi != 0) {
1213 | 	if(sub_1795() == 0) {
1214 | 	    if(gPi->type == T_JP) {
1215 | 		if(sub_1aec() == 0) {
1216 | 		    if(sub_1b86() == 0) {
1217 | 			if(gPi->iLhs->type           !=    T_CONST) goto m5;
1218 | 			if(gPi->iLhs->oPSym->p.pInst != gPi->pNext) goto m5;
1219 | 			removeInstruction(gPi);
1220 | 			optimiseCounters[6]++;	/* 6fc9 opt_msg[6] = "Jumps to .+1" */
1221 | 			hasChanged = true;
1222 | 		    }
1223 | 		}
1224 | 	    }
1225 | 	}
1226 | m2:	gPi = gPi->pNext;
1227 |     }
1228 |     return;
1229 | 
1230 | m5: if(gPi->aux == 0) {
1231 | 	while((gPi->pNext->type != 0)					/* m8: */
1232 | 	&&    (gPi->pNext->type != T_SYMBOL)) {
1233 | 	    pi = gPi->pNext;						/* m7: */
1234 | 	    removeInstruction(pi);
1235 | 	    optimiseCounters[5]++; /* 6fc7 opt_msg[5] = "Unreachable code" */
1236 | 	    hasChanged = true;
1237 | 	}
1238 | 	if(gPi->iLhs->type != T_REGREF) {				/* m9: */
1239 | 
1240 | 	    if(gPi->iLhs->oPSym->p.pInst != 0) {
1241 | 
1242 | 		if(sub_1071(gPi) != 0) goto m2;
1243 | 	    }
1244 | 	}
1245 |     }
1246 |     if(gPi->iLhs->type == T_CONST) {					/* m10: */
1247 | 	if(gPi->pNext->type == T_CALL) goto m12;
1248 | 	if(gPi->pNext->type == T_JP) {
1249 | m12:	    if(gPi->pNext->aux == 0) {
1250 | 		if(gPi->iLhs->oPSym->p.pInst == gPi->pNext->pNext) {
1251 | 		    
1252 | 		    gPi->pNext->aux = ccSwap[gPi->aux]; /* swap condition code */
1253 | 		    
1254 | 		    removeInstruction(gPi);
1255 | 		    optimiseCounters[7]++; /* 6fcb opt_msg[7] = "Skips over jumps" */
1256 | 		    hasChanged = true;
1257 | 		    goto m2;
1258 | 		}
1259 | 	    }
1260 | 	}
1261 |     }
1262 |     if(sub_1c67() != 0) goto m2;					/* m13: */
1263 |     if(sub_1d94() == 0) goto m2;
1264 |     goto m2;
1265 | }
1266 | 
1267 | #endif
1268 | 
--------------------------------------------------------------------------------
/optim1.h:
--------------------------------------------------------------------------------
  1 | /*
  2 |  * File optim1.h created 14.08.2021, last modified 11.11.2021.
  3 |  *
  4 |  * The optim1.h file is part of the restored optimization program
  5 |  * from the Hi-Tech C compiler v3.09 package.
  6 |  *
  7 |  *	Andrey Nikitin & Mark Ogden 11.11.2021
  8 |  */
  9 | 
 10 | /*#define _DEBUG  1 */
 11 | 
 12 | /*
 13 |  * instructions only used in the tables
 14 |  */
 15 | #define I_ADC  0x88 /*   Add */
 16 | #define I_ADD  0x80 /* */
 17 | #define I_BIT  0x40 /*   Tests if the specified bit is set */
 18 | #define I_DJNZ 0x10 /* */
 19 | #define I_JR   0x18 /* */
 20 | #define I_LDIR 0xB0 /*   Load, Inc., Repeat */
 21 | #define I_RESB 0x80 /*   Reset bit */
 22 | #define I_RL   0x10 /*   rl */
 23 | #define I_RLA  0x17 /*   rla */
 24 | #define I_RLC  0    /*   rlc */
 25 | #define I_RLCA 7    /*   rlca */
 26 | #define I_RLD  0x6F /*   rld */
 27 | #define I_RR   0x18 /*   rr */
 28 | #define I_RRA  0x1F /*   rra */
 29 | #define I_RRC  8    /*   rrc */
 30 | #define I_RRCA 0xF  /*   rrca */
 31 | #define I_RRD  0x67 /*   rrd */
 32 | #define I_RST  0xC7 /* */
 33 | #define I_SBC  0x98 /*   Subtract */
 34 | #define I_SETB 0xC0 /*   Set bit */
 35 | #define I_SLA  0x20 /*   sla */
 36 | #define I_SLL  0x20 /*   sll */
 37 | #define I_SRA  0x28 /*   sra */
 38 | #define I_SRL  0x38 /*   srl */
 39 | /*
 40 |  * instructions used in the code
 41 |  */
 42 | #define I_AND  0xA0 /*   Logical AND */
 43 | #define I_CCF  0x3F /*   Complement Carry Flag */
 44 | #define I_CP   0xB8 /*   Compare */
 45 | #define I_CPL  0x2F /*   Complement */
 46 | #define I_DI   0xF3 /*   Disable Interrupts */
 47 | #define I_EI   0xFB /*   Enable Interrupts */
 48 | #define I_EXX  0xD9 /*   Exchange */
 49 | #define I_HALT 0x76
 50 | #define I_NEG  0x44 /*   Negates the accumulator */
 51 | #define I_NOP  0    /*   No operation */
 52 | #define I_OR   0xB0 /*   Logical inclusive OR */
 53 | #define I_POP  0xC1 /*   pop */
 54 | #define I_PUSH 0xC5 /*   push */
 55 | #define I_SCF  0x37 /*   Set Carry Flag */
 56 | #define I_SUB  0x90 /*   sub */
 57 | #define I_XOR  0xA8 /*   xor */
 58 | /*
 59 |  * special shared instruction
 60 |  */
 61 | #define SI_DEC 5    /*   Decrement */
 62 | #define SI_INC 4    /*   Increment */
 63 | 
 64 | /*
 65 |  * The precedence values P_NA is for not applicable
 66 |  */
 67 | #define P_ADD  5 /* */
 68 | #define P_AND  4 /* */
 69 | #define P_CPAR 1 /* */
 70 | #define P_DIV  6 /* */
 71 | #define P_EQU  2 /* */
 72 | #define P_GE   2 /* */
 73 | #define P_HI   8 /* */
 74 | #define P_LE   2 /* */
 75 | #define P_LOW  8 /* */
 76 | #define P_MOD  6 /* */
 77 | #define P_MUL  6 /* */
 78 | #define P_NA   0 /* */
 79 | #define P_NOT  8 /* */
 80 | #define P_OPAR 9 /* */
 81 | #define P_OR   3 /* */
 82 | #define P_RES  7 /* */
 83 | #define P_SHL  6 /* */
 84 | #define P_SHR  6 /* */
 85 | #define P_SUB  5 /* */
 86 | #define P_XOR  3 /* */
 87 | 
 88 | /****************************************************************
 89 |  *  Token definitions
 90 |  *
 91 |  *  Symbol    Code  Description
 92 |  */
 93 | enum type {
 94 |     T_INVALID = 0,
 95 |     T_SIMPLE,         /*    1  one byte instruction: */
 96 |     T_TWOBYTE,        /*    2  two byte instruction: */
 97 |     T_3,              /*    3  Unknown: */
 98 |     T_INCDEC,         /*    4  Unknown: */
 99 |     T_5,              /*    5  Unknown */
100 |     T_SHIFT,          /*    6  Unknown: */
101 |     T_BIT,            /*    7  Bit operations */
102 |     T_JP,             /*    8  Absolute jumps to address */
103 |     T_JR,             /*    9  Relative jumps to address */
104 |     T_DJNZ,           /*  0xA  Dec., Jump Non-Zero */
105 |     T_CALL,           /*  0xB  Call */
106 |     T_RET,            /*  0xC  Uunknown */
107 |     T_RST,            /*  0xD  Restart Commands */
108 |     T_0xE,            /*  0xE  Unknown */
109 |     T_0xF,            /*  0xF  Unknown */
110 |     T_STK,            /* 0x10  Stack operation: */
111 |     T_EX,             /* 0x11  Exchange */
112 |     T_CARR,           /* 0x12  With Carry: */
113 |     T_CADD,           /* 0x13  Add */
114 |     T_LD,             /* 0x14  Load */
115 |     T_UPLUS,          /* 0x15  unary + */
116 |     T_UMINUS,         /* 0x16  unary - */
117 |     T_NOT,            /* 0x17  Bitwise complement */
118 |     T_HI,             /* 0x18  Hi byte of operand */
119 |     T_LOW,            /* 0x19  Low byte of operand */
120 |     T_RES,            /* 0x1A  .res. */
121 |     T_MARKER,         /* 0x1B  used to demark types */
122 |     T_PLUS,           /* 0x1C  Addition */
123 |     T_MINUS,          /* 0x1D  Subtraction */
124 |     T_MUL,            /* 0x1E  Multiplication */
125 |     T_DIV,            /* 0x1F  Divison */
126 |     T_MOD,            /* 0x20  Modulus */
127 |     T_SHR,            /* 0x21  Shift right */
128 |     T_SHL,            /* 0x22  Shift left */
129 |     T_AND,            /* 0x23  Bitwise AND */
130 |     T_OR,             /* 0x24  Bitwise or */
131 |     T_XOR,            /* 0x25  Exclusive or */
132 |     T_EQ,             /* 0x26  Equality */
133 |     T_LE,             /* 0x27  Signed greater than */
134 |     T_GE,             /* 0x28  Signed less than */
135 |     T_ULE,            /* 0x29  Unigned greater than */
136 |     T_UGE,            /* 0x2A  Unigned less than */
137 |     T_OPAR,           /* 0x2B  Open parenthesis */
138 |     T_CPAR,           /* 0x2C  Closing parenthesis */
139 |     T_LASTOP,         /* 0x2D  used to demark end of ops */
140 |     T_FWD,            /* 0x2E  Local refernce forward */
141 |     T_BWD,            /* 0x2F  Local reference backward */
142 |     T_SYMBOL = 0x31,  /* 0x31  Symbol */
143 |     T_CONST,          /* 0x32  Constants */
144 |     T_STRING,         /* 0x33  String of characters */
145 |     T_PSCT,           /* 0x34  Psect */
146 |     T_GLB,            /* 0x35  Global */
147 |     T_COMM,           /* 0x36  Comma */
148 |     T_DEFW,           /* 0x37  Definition word */
149 |     T_DEFL,           /* 0x38  Definition label */
150 |     T_DEFB,           /* 0x39  Definition byte */
151 |     T_DEFM,           /* 0x3A  Definition a message */
152 |     T_DEFS,           /* 0x3B  Memory reservation */
153 |     T_DEFF,           /* 0x3C  Definition real */
154 |     T_EQU,            /* 0x3D  Set value of symbol */
155 | 
156 |     T_EOL = 0x40,     /* 0x40  end of line      ';' */
157 |     T_COLN,           /* 0x41  Label separator  ':' */
158 | 
159 |     T_REG = 0x46,     /* 0x46  Registers */
160 |     T_COND,           /* 0x47  Condition code: */
161 | 
162 |     T_INDEXED = 0x64, /* 0x64  (IX / IY) */
163 |     T_ADDRREF,        /* 0x65  (addr expression) */
164 |     T_REGREF          /* 0x66  (reg) */
165 | };
166 | 
167 | /*
168 |  *	Determining register number
169 |  *	(its offset in regs[offset] table) 
170 |  */
171 | #define REG_B		0x00
172 | #define REG_C		0x01
173 | #define REG_D		0x02
174 | #define REG_E		0x03
175 | #define REG_H		0x04
176 | #define REG_L		0x05
177 | #define REG_F   	0x06
178 | #define REG_A		0x07
179 | #define REG_I		0x08
180 | #define REG_R		0x09
181 | #define REG_BC		0x0A
182 | #define REG_DE		0x0B
183 | #define REG_HL		0x0C
184 | #define REG_SP		0x0D
185 | #define REG_AF		0x0E
186 | #define REG_AF1		0x0F
187 | #define REG_IX		0x10
188 | #define REG_IY		0x11
189 | #define REG_TRACKER 	0x12
190 | /*
191 |  * Determining the condition number
192 |  * (its offset in the conditions[offset] table) */
193 | 
194 | #define	COND_NZ		1 /*   anz, fnz, lnz,   nz */
195 | #define	COND_Z		2 /*    az,  fz,  lz,   z  */
196 | #define	COND_LGE	3 /* 	          lge,  nc */
197 | #define	COND_LLT	4 /*              llt      */
198 | /*#define COND_PO	5                       po */
199 | /*#define COND_PE	6                       pe */
200 | #define	COND_GE		7 /*    age, fge,       p  */	
201 | #define	COND_LT		8 /*    alt, flt,       m  */
202 | 
203 | /*
204 |  *	psect definitions 
205 |  */
206 | #define	TEXT	1
207 | #define	DATA	2
208 | #define	BSS	3
209 | #define	SWDATA	4
210 | 
211 | /*
212 |  *	Assigned type abbreviations
213 |  */
214 | 
215 | #ifdef CPM
216 | //typedef unsigned short uint16_t;
217 | //typedef short int16_t;
218 | //typedef unsigned char uint8_t;
219 | #define const
220 | #endif
221 | 
222 | typedef short int16_t;
223 | typedef unsigned short uint16_t;
224 | typedef unsigned char  uint8_t;
225 | 
226 | #ifndef bool
227 | #define bool char /* int may be better */
228 | #define true  1
229 | #define false 0
230 | #endif
231 | 
232 | #ifndef INT_MAX
233 | #define INT_MAX 32767 /* max for int */
234 | #endif
235 | 
236 | /*
237 |  *	Definitions of structures
238 |  *
239 |  * Mark Ogden has given structure members meaningful names 
240 |  */
241 | typedef struct {
242 |     char *str;
243 |     int type;
244 |     int aux;
245 | } operator_t;
246 | 
247 | typedef struct _list {
248 |     struct _list *pNext;
249 | } list_t;
250 | 
251 | typedef struct _term {
252 |     int val;			   /* term's numeric value */
253 |     union {
254 |         struct _sym *pSym;         /* base symbol */
255 |         struct _operand *pOperand; /* or rest of expression */
256 |     } p;
257 | } term_t;
258 | 
259 | typedef struct _operand {
260 |     uint8_t type;
261 |     uint8_t aux;
262 |     term_t term;
263 | } operand_t;
264 | 
265 | typedef struct _inst {
266 |     char *opCode;
267 |     uint8_t type;
268 |     int aux;
269 |     struct _inst *pNext;
270 |     struct _inst *pAlt;
271 |     union {
272 |         struct {
273 |             operand_t *lhs; /* used for operands */
274 |             operand_t *rhs;
275 |         } o;
276 |         struct { /* used for symbols */
277 |             struct _sym *pSym;
278 |             int symId;
279 |         } s;
280 |     } u;
281 | } inst_t;
282 | 
283 | typedef struct _sym {
284 |     char *label;
285 |     union {
286 |         inst_t *pInst;       /* is either a pointer to the instruction associated with label */
287 |         operand_t *pOperand; /* or the constant associated with the label */
288 |     } p;
289 | } sym_t;
290 | 
291 | typedef union {
292 |     char   *pChar;
293 |     sym_t  *pSym;
294 |     int16_t i;
295 | } YYSTYPE;
296 | 
297 | /*
298 |  * to avoid lots of u.o. and u.s. used some #defines to simpilfy
299 |  */
300 | #define iLhs      u.o.lhs	/* used in inst */
301 | #define iRhs      u.o.rhs
302 | #define iPSym     u.s.pSym
303 | #define iSymId    u.s.symId
304 | #define tPSym     p.pSym	/* used in term */
305 | #define tPInst    p.pInst
306 | #define sPOperand p.pOperand	/* used in sym_t && term_t */
307 | #define oPSym     term.tPSym	/* used in operand */
308 | #define oPOperand term.sPOperand
309 | #define oVal      term.val
310 | 
311 | struct _s1 {
312 |     char hiReg;
313 |     char loReg;
314 | };
315 | 
316 | struct _s2 {
317 |     operand_t *pHiRegVal;
318 |     operand_t *pLoRegVal;
319 | };
320 | 
321 | /*
322 |  *	Descriptions of uninitialized variables and arrays
323 |  */
324 | extern char 	            yyline[80];			/* Working buffer */
325 | extern int                  charsLeft;			/* Length string in input buffer */
326 | extern char               * ptr_inbuf;			/* Pointer to input buffer  */
327 | extern int	            yytype;
328 | extern char	            inp_buf[512];		/* Input buffer (In the original it was 80) */
329 | extern bool	            key_l;			/* Prints additional information on each pass */
330 | extern bool	            key_n;			/* Prints statistics */
331 | extern bool	            key_f;			/* The action is not clear */
332 | extern bool	            key_s;			/* Key_s = 1 Unbuffered stdout */
333 | extern int	            num_warn;			/* Number of warnings */
334 | extern bool	            key_r;
335 | extern operator_t const   * tableBase;			/* Pointer to keyword[] */
336 | extern char	          * yytext;
337 | extern YYSTYPE	            yylval;			/* Contains different types of data */
338 | extern int	            symbolId;
339 | extern sym_t              * gPs;
340 | extern inst_t             * gPi;
341 | extern int	            word_6fb9;
342 | extern bool 	            hasChanged;
343 | extern bool 	            usesIXorIY;
344 | extern int	            optimiseCounters[18];	/* Array of counters types of optimizations */
345 | 
346 | enum {
347 |     O_RED_LAB = 0,                /* 6fbd   0 Redundant labels */
348 |     O_JMP_TO_JMP,                 /* 6fbf   1 Jumps to jumps */
349 |     O_STK_ADJUST,                 /* 6fc1   2 Stack adjustments */
350 |     O_TMP_LAB,                    /* 6fc3   3 Temporary labels */
351 |     O_UNREF_LAB,                  /* 6fc5   4 Unref'ed labels */
352 |     O_UNREACH_LAB,                /* 6fc7   5 Unreachable code */
353 |     O_JMP_TO_PLUS1,               /* 6fc9   6 Jumps to .+1 */
354 |     O_SKIP_OVER_JMP,              /* 6fcb   7 Skips over jumps */
355 |     O_CMN_CODE_SEQ,               /* 6fcd   8 Common code seq's */
356 |     O_RED_EXX,                    /* 6fcf   9 Redundant exx's */
357 |     O_EX_SPHL,                    /* 6fd1  10 Ex (sp),hl's used */
358 |     O_RED_OPS,                    /* 6fd3  11 Redundant operations */
359 |     O_RED_LD,                     /* 6fd5  12 Redundant loads/stores */
360 |     O_SIMPLE_ADDR,                /* 6fd7  13 Simplified addresses */
361 |     O_XOR_A,                      /* 6fd9  14 Xor a's used */
362 |     O_RED_EX_DEHL,                /* 6fdb  15 Redundant ex de,hl's */
363 |     O_CODE_MOTIONS,               /* 6fdd  16 Code motions */
364 |     O_LOOPS_INV                   /* 6fdf  17 Loops inverted */
365 | };
366 | 
367 | extern list_t             * freeOperandList;		/* ptr to struct size 6 */
368 | extern inst_t             * seq1;
369 | extern inst_t             * seq2;
370 | extern inst_t             * freeInstList;
371 | extern char                 psect;			/* Program section */
372 | extern int                  cur_psect;			/* Current program section */
373 | extern int                  expectCond;
374 | extern inst_t             * word_6fee;
375 | extern int                  tokType;			/* Token value */
376 | extern inst_t             * switchVectors; //word_6ff2;
377 | extern inst_t             * root;
378 | extern int                  cntOperand;			/* used only in sub_39a3 */
379 | extern inst_t             * word_6ffc;
380 | 
381 | #ifndef CPM
382 | #define MAXHEAP 0xff00
383 | 
384 | extern char               * heapBase;
385 | extern char               * heapTop;
386 | #endif
387 | 
388 | extern jmp_buf              jmpbuf;			/* [8] */
389 | extern int	            hlDelta;	/* word_7006; */
390 | extern operand_t            regValues[19];
391 | extern char               * alloct;
392 | extern char               * name_fun;			/* Function name */
393 | extern list_t             * freeItemList;		/* 7080 */
394 | extern char               * allocs;
395 | extern char               * programBreak;
396 | 
397 | #define HASHSIZE 311
398 | 
399 | extern sym_t              * hashtab[HASHSIZE];		/* [622] */
400 | 
401 | /*
402 |  *	Initialized variables 
403 |  */
404 | extern char                 ccClass[];
405 | extern char               * conditions[];
406 | extern char               * regs[];
407 | extern operator_t           operators[];
408 | extern char               * opt_msg[];
409 | extern int                  ccSwap[];
410 | extern char               * psectNames[];
411 | extern struct _s1           regHiLoMap[];
412 | extern struct _s2           regHiLoValMap[];
413 | extern int                  regTestMasks[];
414 | 
415 | /****************************************************************
416 |  * Prototype functions are located in sequence of being in
417 |  * original binary image of OPTIM.COM
418 |  *
419 |  * ok++ - Full binary compatibility with code in original file;
420 |  * ok+  - Code generated during compilation differs slightly,
421 |  *        but is logically correct;
422 |  ****************************************************************/
423 | /*
424 |  * File OPTIM1.C
425 |  */
426 | int            strtoi(char const *fmt, int p2);              	   /*  1 sub_013d ok++ */
427 | char         * ptr_token();                            		   /*  2 sub-020f ok++ */
428 | int            const_value();                          		   /*  3 sub_0289 ok+  */
429 | int            get_token();                            		   /*  4 sub_03c7 ok+  */
430 | int            get_line();                             		   /*  5 sub_0758 ok+  */
431 | void           clr_len_inbuf();                        		   /*  6 sub_07aa ok++ */
432 | int            main(int, char **);                     		   /*  7 sub_07b1 ok+  */
433 | #if defined(__STDC__) || defined(__STDC_VERSION__)
434 | void _Noreturn pr_error(char const * fmt, ...);
435 | void           pr_warning(char const * fmt, ...);
436 | void           pr_message(char const * fmt, va_list args);
437 | #else
438 | void           pr_error();                             		   /*  8 sub_0941 ok++ */
439 | void           pr_warning();                           		   /*  9 sub_096f ok++ */
440 | void           pr_message();                           		   /* 10 sub_0994 ok++ */
441 | #endif
442 | int            find_token(char const *, operator_t const *, int);  /* 11 sub_09d0 ok++ */
443 | int            num_token(char const *);				   /* 12 sub_0a97 ok++ */
444 | void           pr_token(inst_t const *);                     	   /* 13 sub_0ab2 ok++ */
445 | void           freeOperand(register operand_t *);                  /* 14 sub_0b6a ok++ */
446 | void           freeInst(register inst_t *);                        /* 15 sub_0b8b ok++ */
447 | operand_t    * allocOperand();                         		   /* 16 sub_0ba7 ok++ */
448 | inst_t       * allocInst(inst_t *);                    		   /* 17 sub_0be2 ok++ */
449 | inst_t       * syntheticLabel(inst_t *);                  	   /* 18 sub_0ca2 ok++ */
450 | void           optimise();                             		   /* 19 sub_0ce4 ok++ */
451 | void           chkIXYUsage();                          		   /* 20 sub_0e67 ok++ */
452 | void           sub_0ed1();                             		   /* 21 sub_0ed1 ok++ */
453 | bool           sub_1071(inst_t *);                     		   /* 22 sub_1071 ok++ */
454 | void           sub_122f();                             		   /* 23 sub_122f ok++ */
455 | bool           sub_1369(operand_t const *);			   /* 24 sub_1369 ok++ */
456 | void           removeInstruction(inst_t *);            		   /* 25 sub_1397 ok++ */
457 | inst_t       * getNextRealInst(inst_t *);			   /* 26 sub_140b ok++ */
458 | bool           operandsSame(operand_t const *, operand_t const *); /* 27 sub_142f ok++ */
459 | bool           instructionsSame(inst_t const *, inst_t const *);   /* 28 sub_14ac ok++ */
460 | void           removeLabelRef(sym_t *);                		   /* 29 sub_153d ok++ */
461 | void           sub_15ad();                             		   /* 30 sub_15ad ok++ */
462 | /*
463 |  * File PART2.C
464 |  */
465 | bool           sub_1795();                             		   /* 31 sub_1795 ok++ */
466 | bool           sub_1aec();                             		   /* 32 sub_1aec ok++ */
467 | bool           sub_1b86();                             		   /* 33 sub_1b86 ok++ */
468 | bool           sub_1c67();                             		   /* 34 sub_1c67 ok++ */
469 | bool           sub_1d94();                             		   /* 35 sub_1d94 ok++ */
470 | void           sub_1ec1();                             		   /* 36 sub_1ec1 ok++ */
471 | bool           sub_23c1();                             		   /* 37 sub_23c1 ok++ */
472 | bool           sub_24c0();                             		   /* 38 sub_24c0 ok++ */
473 | bool           sub_29c3();                             		   /* 39 sub_29c3 ok+  */
474 | bool           sub_2bdb();                             		   /* 40 sub_2bdb ok++ */
475 | 
476 | bool           sub_2d3b();                             		   /* 41 sub_2d3b ok+  */
477 | bool           sub_2ef8();                             		   /* 42 sub_2ef8 ok++ */
478 | bool           sub_3053();                             		   /* 42asub_3053 ok+  */
479 | void           swapHLDE();                             		   /* 43 sub_31ee ok++ */
480 | void           pr_psect(int psect);                    		   /* 44 sub_328a ok++ */
481 | int            num_psect(char const *);				   /* 45 sub_32bf ok++ */
482 | term_t       * evalExpr();					   /* 46 sub_3313 ok++ */
483 | void           exp_err();					   /* 47 sub_3595 ok++ */
484 | void           uconv(int, term_t *);				   /* 48 sub_359e ok+  */
485 | void           bconv(int, term_t *, term_t const *);		   /* 49 sub_3630 ok++ */
486 | /*
487 |  * File PART2.3
488 |  */
489 | void           rel_err();					   /* 50 sub_384d ok++ */
490 | operand_t    * evalOperand();					   /* 51 sub_3856 ok+  */
491 | void           oper_err();					   /* 52 sub_398e ok++ */
492 | void           getOperands(inst_t *);				   /* 53 sub_39a3 ok++ */
493 | void           loadFunction();					   /* 54 sub_3a15 ok+  */
494 | bool           sub_4000(inst_t const *);			   /* 55 sub_4000 ok+  */
495 | void           sub_404d();                             		   /* 56 sub_404d ok++ */
496 | void           pr_instruction(inst_t *);			   /* 57 sub_420a ok+  */
497 | void           sub_436e(operand_t const *);			   /* 58 sub_436e ok++ */
498 | void           sub_44b2(operand_t const *);			   /* 59 sub_44b2 ok+  */
499 | void           sub_4544(int);					   /* 60 sub_4544 ok+  */
500 | void           sub_4601();					   /* 61 sub_4601 ok+  */
501 | bool           sub_4625(inst_t const *);			   /* 62 sub_4625 ok+  */
502 | bool           sub_4682(operand_t const *);			   /* 63 sub_4682 ok++ */
503 | int            sub_46b1(operand_t const *, int);		   /* 64 sub_46b1 ok++ */
504 | int            sub_475c(operand_t const *, int);		   /* 65 sub_475c ok++ */
505 | int            sub_47a2(operand_t const *, int);             	   /* 66 sub_47a2 ok++ */
506 | bool           sub_47e0(int, inst_t const *, inst_t const *);	   /* 67 sub_47e0 ok+  */
507 | sym_t        * allocItem();                            		   /* 68 sub_4c33 ok+  */
508 | void           freeSymbol(sym_t *);                    		   /* 69 sub_4c6b ok+  */
509 | int            hash_index(char const *, int);             	   /* 70 sub_4cab ok++ */
510 | sym_t        * lookupSym(char const *);                      	   /* 71 sub_4cf0 ok+  */
511 | sym_t        * allocBlankSym();                        		   /* 72 sub_4da7 ok++ */
512 | void           resetHeap();                            		   /* 73 sub_4dbf ok++ */
513 | void           sub_4e20();                             		   /* 74 sub_4e20 ok++ */
514 | void         * alloc_mem(int);                         		   /* 75 sub_4e2d ok+  */
515 | 
516 | #ifdef CPM
517 | #define new_sbrk sbrk
518 | #define new_brk  brk
519 | char         * sbrk(int);
520 | int            brk(void *);
521 | #else
522 | void         * sbrk(int size);
523 | int            brk(void *);
524 | void         * new_sbrk(int size);
525 | int            new_brk(void *);
526 | #endif
527 | 
528 | #ifdef _DEBUG
529 | void           heapchk(void const *p);
530 | #define HEAP(p) heapchk(p)
531 | #else
532 | #define HEAP(p)
533 | #endif
534 | 
535 | #define logOptimise(n) (optimiseCounters[n]++, hasChanged = true)
536 | 
537 | 
--------------------------------------------------------------------------------
/part21.c:
--------------------------------------------------------------------------------
   1 | /*
   2 |  * File part21.c created 14.08.2021, last modified 11.11.2021.
   3 |  *
   4 |  * The part21.c file is part of the restored optimization program
   5 |  * from the Hi-Tech C compiler v3.09 package.
   6 |  *
   7 |  *	Andrey Nikitin & Mark Ogden 11.11.2021
   8 |  */
   9 | 
  10 | #include 
  11 | #include 
  12 | #include 
  13 | #include 
  14 | #include "optim1.h"
  15 | 
  16 | /**************************************************************************
  17 |  31 sub_1795    ok++
  18 |  **************************************************************************/
  19 | bool sub_1795() {
  20 |     register inst_t *pi;
  21 |     static int stackAdjust;
  22 | 
  23 |     if (gPi->type != T_LD) {
  24 |         return false;
  25 |     }
  26 |     if (gPi->iLhs->type != T_REG || gPi->iLhs->aux != REG_SP) {
  27 |         return false;
  28 |     }
  29 |     if ((pi = gPi->pAlt)->type != T_CADD || (pi = pi->pAlt)->type != T_LD) {
  30 |         return false;
  31 |     }
  32 |     if (pi->iLhs->type != T_REG || pi->iLhs->aux != REG_HL || pi->iRhs->type != T_CONST) {
  33 |         return false;
  34 |     }
  35 |     if (pi->iRhs->oPOperand) {
  36 |         pr_error("Funny stack adjustment");
  37 |     }
  38 |     stackAdjust = pi->iRhs->oVal;
  39 |     pi          = gPi->pNext;
  40 |     if (pi->type == T_SIMPLE && pi->aux == I_EXX) {
  41 |         pi = pi->pNext;
  42 |     }
  43 |     for (; pi->type != T_CALL && pi->type != T_JP && pi->type != T_STK && (pi->type != T_EX || pi->iLhs->aux != REG_SP);
  44 |             pi = pi->pNext)
  45 |         ;
  46 | 
  47 |     if (stackAdjust > 0 && usesIXorIY && pi->aux == 0 && sub_4000(pi)) {
  48 |         removeInstruction(gPi->pAlt->pAlt);
  49 |         removeInstruction(gPi->pAlt);
  50 |         gPi = gPi->pAlt;
  51 |         removeInstruction(gPi->pNext);
  52 |         if (gPi->pNext->type == T_SIMPLE && gPi->pNext->aux == I_EXX && gPi->type == T_SIMPLE &&
  53 |                 gPi->aux == I_EXX) { /* exx */
  54 |             removeInstruction(gPi->pNext);
  55 |             removeInstruction(gPi);
  56 |         }
  57 |         return logOptimise(O_STK_ADJUST); /* 6fc1 opt_msg[2] = "Stack adjustments" m7: */
  58 |     }
  59 |     pi = gPi->pAlt->pAlt;
  60 |     if (stackAdjust < 0) {
  61 |         stackAdjust = -stackAdjust;
  62 |     }
  63 |     if (pi->pAlt->type == T_SIMPLE && pi->pAlt->aux == I_EXX) {
  64 |         stackAdjust -= 2;
  65 |     }
  66 | 
  67 |     if (stackAdjust > 8 || pi->iRhs->oVal < 0) {
  68 |         return false;
  69 |     }
  70 | 
  71 |     logOptimise(O_STK_ADJUST); /* 6fc1 opt_msg[2] = "Stack adjustments" */
  72 | 
  73 |     stackAdjust = pi->iRhs->oVal;
  74 |     pi          = pi->pAlt;
  75 |     removeInstruction(pi->pNext->pNext);
  76 |     removeInstruction(pi->pNext);
  77 |     removeInstruction(gPi);
  78 |     gPi = pi;
  79 | 
  80 |     while (stackAdjust != 0) {
  81 |         gPi             = allocInst(gPi);
  82 |         gPi->iLhs       = allocOperand();
  83 |         gPi->iLhs->type = T_REG;
  84 |         if (1 < stackAdjust) {
  85 |             gPi->iLhs->aux = REG_BC;
  86 |             gPi->type      = T_STK;
  87 |             stackAdjust -= 2;
  88 |             gPi->aux = I_POP;
  89 |         } else {
  90 |             gPi->iLhs->aux = REG_SP;
  91 |             gPi->type      = T_INCDEC; /* Decrement, Increment */
  92 |             --stackAdjust;
  93 |             gPi->aux = SI_INC;
  94 |         }
  95 |     }
  96 |     if (gPi->pNext->type == T_SIMPLE && gPi->pNext->aux == I_EXX && pi->type == T_SIMPLE && pi->aux == I_EXX) {
  97 |         removeInstruction(gPi->pNext);
  98 |         removeInstruction(pi);
  99 |     }
 100 |     return true;
 101 | }
 102 | 
 103 | /**************************************************************************
 104 |  32 sub_1aec    ok++
 105 |  **************************************************************************/
 106 | bool sub_1aec() {
 107 |     register inst_t *pi;
 108 | 
 109 |     if (gPi->iLhs->type != T_REGREF) {
 110 |         if ((gPs = gPi->iLhs->oPSym)->p.pInst) {
 111 |             pi = getNextRealInst(gPs->p.pInst);
 112 |             pi = pi->pAlt;
 113 |             if (gPs->p.pInst != pi) {
 114 |                 gPi->iLhs->oPOperand = pi->iLhs;
 115 |                 removeLabelRef(gPs);
 116 |                 ++pi->aux;                     /* safe const change */
 117 |                 return logOptimise(O_RED_LAB); /* 6fbd opt_msg[0] = "Redundant labels" */
 118 |             }
 119 |         }
 120 |     }
 121 |     return false;
 122 | }
 123 | 
 124 | /**************************************************************************
 125 |  33 sub_1b86    ok++
 126 |  **************************************************************************/
 127 | bool sub_1b86() {
 128 |     register inst_t *pi;
 129 | 
 130 |     if (gPi->type == T_JP || gPi->type == T_CALL) {
 131 |         if ((gPs = gPi->iLhs->oPSym) && (pi = gPs->p.pInst)) {
 132 |             pi = getNextRealInst(pi);
 133 |             if (pi->type == T_JP && (pi->aux == 0 || pi->aux == gPi->aux) && pi->iLhs->oPSym != gPs) {
 134 |                 removeLabelRef(gPs);
 135 |                 gPs              = pi->iLhs->oPSym;
 136 |                 gPi->iLhs->oPSym = gPs;
 137 |                 if (gPs->p.pInst) {
 138 |                     ++gPs->p.pInst->aux;
 139 |                 }
 140 |                 return logOptimise(O_JMP_TO_JMP); /* 6fbf opt_msg[1] = "Jumps to jumps" */
 141 |             }
 142 |         }
 143 |     }
 144 | 
 145 |     return false;
 146 | }
 147 | 
 148 | /**************************************************************************
 149 |  34 sub_1c67    ok++
 150 |  **************************************************************************/
 151 | bool sub_1c67() {
 152 |     register inst_t *pi;
 153 |     if (gPi->aux == 0) {
 154 |         for (pi = gPi->pNext; pi; pi = pi->pNext) {
 155 |             if (instructionsSame(pi, gPi)) {
 156 |                 seq1 = gPi;
 157 |                 seq2 = pi;
 158 |                 /* match chains of instructions */
 159 |                 while (instructionsSame(seq2->pAlt, seq1->pAlt)) {
 160 |                     seq1 = seq1->pAlt;
 161 |                     seq2 = seq2->pAlt;
 162 |                 }
 163 |                 if (seq1 != gPi) { /* we matched some common code */
 164 |                     seq1              = syntheticLabel(seq1->pAlt);
 165 |                     seq2              = allocInst(seq2->pAlt);
 166 |                     seq2->iLhs        = allocOperand();
 167 |                     seq2->type        = T_JP;
 168 |                     seq2->iLhs->type  = T_CONST;
 169 |                     seq2->iLhs->oPSym = seq1->iPSym;
 170 |                     ++seq1->aux;
 171 |                     removeInstruction(pi);
 172 |                     return logOptimise(O_CMN_CODE_SEQ); /* 6fcd opt_msg[8] = "Common code seq's" */
 173 |                 }
 174 |             }
 175 |         }
 176 |     }
 177 |     return false;
 178 | }
 179 | 
 180 | /**************************************************************************
 181 |  35 sub_1d94    ok++
 182 |  **************************************************************************/
 183 | bool sub_1d94() {
 184 |     register inst_t *pi;
 185 | 
 186 |     if (gPi->aux != 0 && (pi = gPi->iLhs->oPSym->p.pInst)) {
 187 |         for (seq1 = gPi; sub_4625(pi->pNext) && instructionsSame(seq1->pNext, pi->pNext); pi = pi->pNext) {
 188 |             HEAP(pi->pNext);
 189 |             HEAP(seq1->pNext);
 190 |             seq1 = seq1->pNext;
 191 |         }
 192 |         if (seq1 != gPi) {
 193 |             if (pi->pNext->type == T_SYMBOL) {
 194 |                 pi = pi->pNext;
 195 |             } else {
 196 |                 pi = syntheticLabel(pi);
 197 |             }
 198 |             seq1                  = allocInst(seq1);
 199 |             seq1->iLhs            = allocOperand();
 200 |             seq1->iLhs->type      = T_CONST;
 201 |             seq1->iLhs->oPOperand = pi->iLhs;
 202 |             seq1->type            = gPi->type;
 203 |             seq1->aux             = gPi->aux;
 204 |             ++pi->aux;
 205 |             removeInstruction(gPi);
 206 |             return logOptimise(O_CMN_CODE_SEQ); /* 6fcd opt_msg[8] = "Common code seq's" */
 207 |         }
 208 |     }
 209 |     return false;
 210 | }
 211 | 
 212 | /**************************************************************************
 213 |  36 sub_1ec1    ok++    Used in: optimize
 214 |  **************************************************************************/
 215 | #if 1
 216 | 
 217 | void sub_1ec1() {
 218 |     int l1;
 219 | 
 220 |     sub_4601();
 221 |     for (gPi = root; gPi; gPi = gPi->pNext) {
 222 |         switch (gPi->type) {
 223 |             case T_LD:
 224 |                 if (!key_r) {
 225 |                     if (sub_24c0()) {
 226 |                         continue;
 227 |                     }
 228 |                     if (gPi->iLhs->type == T_REG && gPi->iLhs->aux == REG_A && sub_4682(gPi->iRhs) &&
 229 |                             !sub_47e0(REG_F, gPi->pNext, gPi)) {
 230 |                         gPi->iRhs   = NULL;
 231 |                         gPi->type   = T_3;
 232 |                         gPi->aux    = I_XOR; /* xor */
 233 |                         gPi->opCode = NULL;
 234 |                         logOptimise(O_XOR_A); /* 6fbf opt_msg[14] = "xor a's used" */
 235 |                     }
 236 |                 }
 237 |                 break;
 238 | 
 239 |             case T_SYMBOL:
 240 |                 for (; gPi->type == T_SYMBOL && gPi->aux == 0; gPi = gPi->pNext) {
 241 |                     removeInstruction(gPi);
 242 |                     logOptimise(O_UNREF_LAB); /* 6fc5 opt_msg[4] = "Unref'ed labels" */
 243 |                 }
 244 |             /* fall through */
 245 | 
 246 |             case T_TWOBYTE:
 247 |             case T_CALL:
 248 |                 sub_4601();
 249 |                 break;
 250 | 
 251 |             case T_EX:
 252 |                 if (gPi->iLhs->type == T_REG) {
 253 |                     if (sub_23c1()) {
 254 |                         continue;
 255 |                     }
 256 |                     swapHLDE();
 257 |                 } else {
 258 |                     sub_4544(gPi->iRhs->aux);
 259 |                 }
 260 |                 break;
 261 | 
 262 |             case T_SIMPLE:
 263 |                 switch (gPi->aux) {
 264 |                     case I_NOP:
 265 |                     case I_SCF:
 266 |                     case I_CCF:
 267 |                     case I_HALT:
 268 |                     case I_DI:
 269 |                     case I_EI:
 270 |                         break;
 271 |                     case I_EXX:
 272 |                         sub_4601();
 273 |                         break;
 274 |                     default:
 275 |                         sub_4544(REG_AF);
 276 |                         break;
 277 |                 }
 278 |                 break;
 279 | 
 280 |             case T_BIT:
 281 |                 if (gPi->aux != 0x40)
 282 |                     if (gPi->iRhs->type == T_REG) {
 283 |                         sub_4544(gPi->iRhs->aux);
 284 |                     } else if ((l1 = sub_46b1(gPi->iRhs, 0)) != -1) {
 285 |                         sub_4544(l1);
 286 |                     }
 287 |                 break;
 288 | caseCommon:
 289 |             case T_CARR:
 290 |                 if (gPi->iLhs->type == T_REG && !sub_47e0(gPi->iLhs->aux, gPi->pNext, gPi)) {
 291 |                     if ((gPi->type == T_INCDEC && gPi->iLhs->aux >= REG_BC) || !sub_47e0(REG_F, gPi->pNext, gPi)) {
 292 |                         removeInstruction(gPi);
 293 |                         logOptimise(O_RED_OPS); /* 6fd3 opt_msg[11] = "Redundant operations" */
 294 |                         continue;
 295 |                     }
 296 |                 }
 297 |                 /* fall through */ /* m25 */
 298 | 
 299 |             case T_SHIFT:
 300 |             case T_0xE:
 301 |                 if (gPi->iLhs->type == T_REG) {
 302 |                     sub_4544(gPi->iLhs->aux);
 303 |                 } else {
 304 |                     sub_44b2(gPi->iLhs);
 305 |                 }
 306 |                 break;
 307 | 
 308 |             case T_CADD:
 309 |                 if (!sub_47e0(gPi->iLhs->aux, gPi->pNext, gPi)) {
 310 |                     removeInstruction(gPi);
 311 |                     logOptimise(O_RED_OPS); /* 6fd3 opt_msg[11] = "Redundant operations" */
 312 |                     continue;
 313 |                 } else if (gPi->iRhs->type == T_CONST && abs(gPi->iRhs->oVal) == 1 && !gPi->iRhs->oPOperand) {
 314 |                     gPi->type   = T_INCDEC;
 315 |                     gPi->aux    = gPi->iRhs->oVal != 1 ? SI_DEC : SI_INC;
 316 |                     gPi->opCode = NULL;
 317 |                     freeOperand(gPi->iRhs);
 318 |                     gPi->iRhs = NULL;
 319 |                     logOptimise(O_SIMPLE_ADDR); /* 6fd7 opt_msg[13] = "Simplified addresses" */
 320 |                 } else {
 321 |                     goto caseCommon;
 322 |                 }
 323 |             /* fall through */
 324 | 
 325 |             case T_INCDEC:
 326 |                 if (gPi->iLhs->type != T_REG) {
 327 |                     goto caseCommon;
 328 |                 }
 329 |                 if (gPi->iLhs->aux != REG_HL) {
 330 |                     goto caseCommon;
 331 |                 }
 332 | 
 333 |                 if (sub_2ef8()) {
 334 |                     continue;
 335 |                 }
 336 |                 break;
 337 | 
 338 |             case T_DJNZ:
 339 |                 sub_4544(0);
 340 |                 break;
 341 | 
 342 |             case T_STK:
 343 |                 if (gPi->aux == I_PUSH) {
 344 |                     if (gPi->iLhs->aux == REG_IY && (l1 = sub_46b1(®Values[17], REG_IY)) != -1 && l1 != REG_IY) {
 345 |                         gPi->iLhs->aux = l1;
 346 |                         logOptimise(O_SIMPLE_ADDR); /* 6fd7 opt_msg[13] = "Simplified addresses" */
 347 |                     }
 348 |                     /* check for pop */
 349 |                     /* OTIMISER: fails to optimise the gPi->pNext-aux below */
 350 |                     if (gPi->pNext->type == T_STK && gPi->pNext->aux == I_POP && gPi->iLhs->aux == gPi->pNext->iLhs->aux) {
 351 |                         removeInstruction(gPi->pNext);
 352 |                         removeInstruction(gPi);
 353 |                         logOptimise(O_RED_OPS); /* 6fd3 opt_msg[11] = "Redundant operations" */
 354 |                     } else {
 355 |                         break;
 356 |                     }
 357 |                 } else {
 358 |                     sub_4544(gPi->iLhs->aux); /* m39: */
 359 |                     if (gPi->pAlt->type == T_STK && gPi->pAlt->aux == I_PUSH) {
 360 |                         regValues[gPi->iLhs->aux] = regValues[gPi->pAlt->iLhs->aux];
 361 |                         if (gPi->iLhs->aux == REG_IY && gPi->pNext->type == T_STK && gPi->pNext->iLhs->aux == REG_IY) {
 362 |                             gPi->pNext->iLhs->aux = gPi->pAlt->iLhs->aux;
 363 |                             logOptimise(O_SIMPLE_ADDR); /* 6fd7 opt_msg[13] = "Simplified addresses" */
 364 |                         }
 365 |                     }
 366 |                     break;
 367 |                 }
 368 |                 continue;
 369 | 
 370 |             case T_3:
 371 |                 if (sub_2d3b()) {
 372 |                     continue;
 373 |                 }
 374 |                 break;
 375 |         }
 376 |         sub_2bdb();
 377 |     }
 378 | }
 379 | 
 380 | #else
 381 | 
 382 | /*  This function generates correct code */
 383 | 
 384 | void sub_1ec1() {
 385 |     int l1;
 386 |     register inst_t *pi;
 387 | 
 388 |     sub_4601();
 389 | 
 390 |     gPi = root;
 391 |     while (gPi != 0) {                                                        /* m5: */
 392 |         pi = gPi;                                                             /* m1: */
 393 |         switch (pi->type) {
 394 |             case T_LD:
 395 |                 if (key_r == 0) {                                             /* m6: */
 396 |                     if (sub_24c0() != 0) {
 397 |                         goto m4;
 398 |                     }
 399 | 
 400 |                     if (((pi = gPi)->iLhs->type == T_REG)
 401 |                             && (pi->iLhs->aux == REG_A)
 402 |                             && (sub_4682(pi->iRhs) != 0)
 403 |                             && (sub_47e0(REG_F, (pi = gPi)->pNext, gPi) == 0)) {
 404 |                         pi       = gPi;
 405 |                         pi->iRhs = 0;
 406 |                         pi->type = T_3;
 407 |                         pi->aux  = P_XOR;
 408 |                         gPi->opCode = 0;
 409 |                         ++optimiseCounters[14]; /* 6fd9 opt_msg[14] = "Xor a's used" m7: */
 410 |                         hasChanged = true;
 411 |                     }
 412 |                 }
 413 |                 goto m2;
 414 | 
 415 |             case T_SYMBOL:
 416 |                 while (((pi = gPi)->type == T_SYMBOL) && (pi->aux == 0)) {      /* m9: */
 417 |                     removeInstruction(gPi);                     		/* m8: */
 418 |                     optimiseCounters[4]++; /* 6fc5 opt_msg[4] = "Unref'ed labels" */
 419 |                     hasChanged = true;
 420 |                     gPi = (pi = gPi)->pNext;
 421 |                 }
 422 |                 /* fall through */
 423 | 
 424 |             case T_TWOBYTE:
 425 |             case T_CALL:
 426 | m10:
 427 |                 sub_4601();                                                     /* m10: */
 428 |                 goto m2;
 429 | 
 430 |             case T_EX:
 431 |                 if ((pi = gPi)->iLhs->type == T_REG) {                          /* m11: */
 432 |                     if (sub_23c1() != 0) {
 433 |                         goto m3;
 434 |                     }
 435 |                     swapHLDE();
 436 |                     goto m2;
 437 |                 }
 438 |                 sub_4544((pi = gPi)->iRhs->aux);                                /* m13: */
 439 |                 goto m2;
 440 | 
 441 |             case T_ONEBYTE:
 442 |                 switch ((pi = gPi)->aux) {                                      /* m15: */
 443 |                     case P_NOP:
 444 |                     case P_SCF:
 445 |                     case P_CCF:
 446 |                     case P_HALT:
 447 |                     case P_DI:
 448 |                     case P_EI:
 449 |                         goto m2;
 450 |                     case P_EXX:
 451 |                         goto m10;
 452 |                     default:
 453 |                         sub_4544(REG_AF);
 454 |                         break;                                                  /* m16: */
 455 |                 }
 456 |                 goto m2;
 457 | 
 458 |             case T_BIT:
 459 |                 if ((pi = gPi)->aux == P_BIT) {
 460 |                     goto m2;    						/* m17: */
 461 |                 }
 462 |                 if (pi->iRhs->type == T_REG) {
 463 |                     sub_4544(pi->iRhs->aux);
 464 |                     goto m2;
 465 |                 }
 466 |                 if ((l1 = sub_46b1((pi = gPi)->iRhs, 0)) == -1) {
 467 |                     goto m2;    						/* m18: */
 468 |                 }
 469 |                 sub_4544(l1);
 470 |                 goto m2;
 471 | 
 472 |             case T_CARR:
 473 | m19:
 474 |                 pi = gPi;							/* m19: */
 475 | m20:
 476 | m21:
 477 |                 if ((pi = gPi)->iLhs->type == T_REG) {
 478 |                     if (sub_47e0(pi->iLhs->aux, (pi = gPi)->pNext, gPi) != 0) {
 479 |                         goto m26;
 480 |                     }
 481 | 
 482 |                     pi = gPi;
 483 |                     if ((pi->type != T_INCDEC) || (pi->iLhs->aux < REG_BC)) {
 484 |                         if (sub_47e0(REG_F, (pi = gPi)->pNext, gPi) == 0) {
 485 |                             goto m23;    					/* m22: */
 486 |                         }
 487 |                         goto m25;
 488 |                     }
 489 | m23:
 490 |                     removeInstruction(gPi);
 491 | m24:
 492 |                     optimiseCounters[11]++; /* 6fd3 opt_msg[11] = "Redundant operations" */
 493 |                     hasChanged = true;
 494 |                     goto m3;
 495 |                 }
 496 |                 /* fall through */
 497 |             case T_6:
 498 |             case T_0xE:
 499 | m25:
 500 |                 pi = gPi;
 501 | m26:
 502 |                 if ((pi = gPi)->iLhs->type == T_REG) {
 503 |                     sub_4544((pi = gPi)->iLhs->aux);                            /* m27: */
 504 |                 } else {
 505 |                     sub_44b2((pi = gPi)->iLhs);                                 /* m28: */
 506 |                 }
 507 |                 goto m2;
 508 | 
 509 |             case T_CADD:
 510 | 
 511 |                 if (sub_47e0(pi->iLhs->aux, (pi = gPi)->pNext, gPi) == 0) {     /* m29: */
 512 | m30:
 513 |                     removeInstruction(gPi);
 514 |                     goto m24;
 515 |                 }
 516 |                 if ((pi = gPi)->iRhs->type != T_CONST) {
 517 |                     goto m20;                                                   /* m31: */
 518 |                 }
 519 |                 if (abs(pi->iRhs->oVal) != 1) {
 520 |                     goto m20;
 521 |                 }
 522 |                 if ((pi = gPi)->iRhs->oPOperand != 0) {
 523 |                     goto m20;
 524 |                 }
 525 |                 pi->type = T_INCDEC;
 526 |                 (pi = gPi)->aux = (pi->iRhs->oVal  == 1) ? REG_H : REG_L;       /* m33: */
 527 |                 gPi->opCode = 0;
 528 |                 freeOperand(pi->iRhs);
 529 |                 (pi = gPi)->iRhs = 0;
 530 |                 optimiseCounters[13]++; /* 6fd7 opt_msg[13] = "Simplified addresses" */
 531 |                 hasChanged = true;
 532 |                 /* fall through */
 533 | 
 534 |             case T_INCDEC:
 535 |                 if ((pi = gPi)->iLhs->type != T_REG) {
 536 |                     goto m21;    //m34:
 537 |                 }
 538 |                 if (pi->iLhs->aux          != REG_HL) {
 539 |                     goto m19;
 540 |                 }
 541 |                 if (sub_2ef8() != 0) {
 542 |                     goto m3;                                                    /* m35: */
 543 |                 }
 544 |                 goto m2;
 545 | 
 546 |             case T_DJNZ:
 547 |                 sub_4544(0); //REG_B                                            /* m36: */
 548 |                 goto m2;
 549 | 
 550 |             case T_STK:
 551 |                 if ((pi = gPi)->aux == P_PUSH) {                                /* m37: */
 552 |                     if ((pi = gPi)->iLhs->aux == REG_IY) {
 553 |                         l1 = sub_46b1(®Values[17], REG_IY);
 554 |                         if (l1 != -1) {
 555 |                             if (l1 !=  REG_IY) {
 556 |                                 (pi = gPi)->iLhs->aux = pi->type;
 557 |                                 optimiseCounters[13]++; /* 6fd7 opt_msg[13] = "Simplified addresses" */
 558 |                                 hasChanged = true;
 559 |                             }
 560 |                         }
 561 |                     }
 562 |                     /* Check for pop */
 563 |                     if ((pi = gPi)->pNext->type != T_STK) {
 564 |                         goto m2;    						/* m38: */
 565 |                     }
 566 |                     if (pi->pNext->aux != P_POP) {
 567 |                         goto m2;
 568 |                     }
 569 |                     if (pi->iLhs->aux != pi->pNext->iLhs->aux) {
 570 |                         goto m2;
 571 |                     }
 572 |                     removeInstruction(pi->pNext);
 573 |                     goto m30;
 574 |                 }
 575 |                 sub_4544(pi->iLhs->aux);                                        /* m39: */
 576 |                 if ((pi = gPi)->pAlt->type != T_STK) {
 577 |                     goto m2;
 578 |                 }
 579 |                 if (pi->pAlt->aux          != P_PUSH) {
 580 |                     goto m2;
 581 |                 }
 582 | 
 583 |                 /* Ambiguious code - pi could be modified on rhs before using on lhs
 584 |                  * on hitech generated code gets lhs before rhs
 585 |                  */
 586 |                 regValues[(pi = gPi)->iLhs->aux] = regValues[pi->pAlt->iLhs->aux];
 587 |                 if ((pi = gPi)->iLhs->aux != REG_IY) {
 588 |                     goto m2;
 589 |                 }
 590 |                 if (pi->pNext->type       != T_STK) {
 591 |                     goto m2;
 592 |                 }
 593 |                 if (pi->pNext->iLhs->aux  != REG_IY) {
 594 |                     goto m2;
 595 |                 }
 596 |                 pi->pNext->iLhs->aux = pi->pAlt->iLhs->aux;
 597 |                 ++optimiseCounters[13]; /* 6fd7 opt_msg[13] = "Simplified addresses" */
 598 |                 hasChanged = true;
 599 |                 goto m2;
 600 | 
 601 |             case T_3:   //   -   -   -   -   -   -   -   -   -   -   -   -   -
 602 |                 if (sub_2d3b() != 0) {
 603 |                     goto m3;                                                    //m40: */
 604 |                 }
 605 |         }
 606 | m2:
 607 |         sub_2bdb();
 608 | m3:
 609 |         pi = gPi;
 610 | m4:
 611 |         gPi = (pi = gPi)->pNext;
 612 |     }
 613 | }
 614 | 
 615 | #endif
 616 | 
 617 | /**************************************************************************
 618 |  37 sub_23c1    ok++
 619 |  **************************************************************************/
 620 | bool sub_23c1() {
 621 |     register inst_t *pi;
 622 | 
 623 |     if ((pi = gPi->pNext)->type == T_STK && pi->aux == I_PUSH && pi->iLhs->aux == gPi->iLhs->aux &&
 624 |             !sub_47e0(gPi->iLhs->aux, pi->pNext, gPi) && !sub_47e0(gPi->iRhs->aux, pi, gPi)) {
 625 |         pi->iLhs->aux = gPi->iRhs->aux;
 626 |         removeInstruction(gPi);
 627 |         gPi = pi;
 628 |     } else if (gPi->pNext->type == T_EX && gPi->pNext->iLhs->type == T_REG) {
 629 |         removeInstruction(gPi->pNext);
 630 |         removeInstruction(gPi);
 631 |     } else {
 632 |         return false;
 633 |     }
 634 |     return logOptimise(O_RED_EX_DEHL); /* 6fdb opt_msg[15] = "Redundant ex de,hl's" */
 635 | }
 636 | 
 637 | /**************************************************************************
 638 |  38 sub_24c0    ok++
 639 |  **************************************************************************/
 640 | bool sub_24c0() {
 641 |     inst_t const *l1;
 642 |     operand_t    *l2;
 643 |     int           reg;
 644 | 
 645 |     if (sub_3053()) {
 646 |         return true;
 647 |     }
 648 |     if (gPi->iLhs->type == T_REG &&
 649 |             (gPi->iRhs->type == T_INDEXED || gPi->iRhs->type == T_ADDRREF || gPi->iRhs->type == T_CONST)) {
 650 |         if (sub_29c3()) {
 651 |             return true;
 652 |         }
 653 |     } else if (gPi->iRhs->type == T_CONST && gPi->iLhs->type == T_INDEXED) {
 654 |         if ((reg = sub_46b1(gPi->iRhs, REG_A)) != -1) {
 655 |             gPi->iRhs->type = T_REG; /* m6: */
 656 |             gPi->iRhs->aux  = reg;
 657 |             return logOptimise(O_SIMPLE_ADDR); /* 6fd7 opt_msg[13] = "Simplified addresses" */
 658 |         }
 659 |         sub_44b2(gPi->iLhs);
 660 |     } else if (gPi->iRhs->type == T_REG && (gPi->iLhs->type == T_INDEXED || gPi->iLhs->type == T_ADDRREF)) {
 661 |         if (operandsSame(gPi->iLhs, ®Values[gPi->iRhs->aux])) {
 662 | kill:
 663 |             removeInstruction(gPi);
 664 |             return logOptimise(O_RED_LD); /* 6fd5 opt_msg[12] = "Redundant loads/stores" */
 665 |         }
 666 |         sub_44b2(gPi->iLhs);
 667 |         if (regValues[gPi->iRhs->aux].type == T_INVALID) {
 668 |             sub_4544(gPi->iRhs->aux);
 669 |             regValues[gPi->iRhs->aux] = *gPi->iLhs;
 670 |         }
 671 | 
 672 |     } else if (gPi->iLhs->type == T_REG && gPi->iRhs->type == T_REG) { /* 2824 */
 673 |         if (gPi->iLhs->aux == gPi->iRhs->aux || operandsSame(®Values[gPi->iLhs->aux], ®Values[gPi->iRhs->aux])) {
 674 |             goto kill;
 675 |         }
 676 | 
 677 |         if ((seq2 = gPi->pNext)->type == T_LD && operandsSame(seq2->iLhs, gPi->iRhs) &&
 678 |                 operandsSame(seq2->iRhs, gPi->iLhs)) {
 679 |             removeInstruction(seq2);
 680 |             logOptimise(O_RED_LD); /* 6fd5 opt_msg[12] = "Redundant loads/stores" */
 681 |         }
 682 |         if (!sub_47e0(gPi->iLhs->aux, gPi->pNext, gPi)) {
 683 |             goto kill;
 684 |         }
 685 |         if (gPi->iLhs->aux == REG_E && gPi->iRhs->aux == REG_L && (seq2 = gPi->pNext)->type == T_LD &&
 686 |                 seq2->iLhs->type == T_REG && seq2->iLhs->aux == REG_D && seq2->iRhs->type == T_REG &&
 687 |                 seq2->iRhs->aux == REG_H && !sub_47e0(REG_HL, seq2->pNext, gPi)) {
 688 |             removeInstruction(gPi->pNext);
 689 |             gPi->type      = T_EX;
 690 |             gPi->opCode    = NULL;
 691 |             gPi->iLhs->aux = REG_DE;
 692 |             gPi->iRhs->aux = REG_HL;
 693 |             swapHLDE();
 694 |             return logOptimise(O_SIMPLE_ADDR); /* 6fd7 opt_msg[13] = "Simplified addresses" */
 695 |         }
 696 |         sub_4544(gPi->iLhs->aux);
 697 |         regValues[gPi->iLhs->aux] = regValues[gPi->iRhs->aux];
 698 |     } else if (gPi->iLhs->type == T_REG) {
 699 |         sub_4544(gPi->iLhs->aux);
 700 |     }
 701 | 
 702 |     if (gPi->iLhs->type == T_REG && gPi->iRhs->type == T_REG) {
 703 |         if ((l1 = gPi->pAlt)->type == T_LD && (l2 = l1->iLhs)->type == T_REG && l2->aux == gPi->iRhs->aux &&
 704 |                 !sub_47e0(l2->aux, gPi->pNext, l1) && sub_1369(l1->iRhs)) {
 705 |             sub_4544(l2->aux);
 706 |             regValues[l2->aux = gPi->iLhs->aux] = *l1->iRhs;
 707 |             goto kill;
 708 |         }
 709 |         if ((l1 = gPi->pNext)->type == T_LD && (l2 = l1->iRhs)->type == T_REG && l2->aux == gPi->iLhs->aux &&
 710 |                 !sub_47e0(l2->aux, l1->pNext, gPi) && sub_1369(l1->iLhs)) {
 711 |             sub_4544(l2->aux);
 712 |             l2->aux = gPi->iRhs->aux;
 713 |             goto kill;
 714 |         }
 715 |     }
 716 |     return false; /* m26: */
 717 | }
 718 | 
 719 | /**************************************************************************
 720 |  39 sub_29c3    ok+ (PMO)
 721 |  *
 722 |  * Code is identical, except that the optimiser moves the code in the
 723 |  * first if block to a different location. The jp conditions are changed to
 724 |  * reflect this)
 725 |  **************************************************************************/
 726 | bool sub_29c3() {
 727 |     int l1;
 728 |     inst_t *pi1;
 729 | 
 730 |     if (operandsSame(gPi->iRhs, ®Values[gPi->iLhs->aux]) || !sub_47e0(gPi->iLhs->aux, gPi->pNext, gPi)) {
 731 |         /* OPTIMISER: this block is located differently */
 732 |         removeInstruction(gPi);
 733 |         return logOptimise(O_RED_LD); /* 6fd5 opt_msg[12] = "Redundant loads/stores" */
 734 |     }
 735 |     sub_4544(gPi->iLhs->aux);
 736 |     if (gPi->iLhs->aux <= REG_HL) {
 737 |         if ((l1 = sub_46b1(gPi->iRhs, gPi->iLhs->aux)) != -1) {
 738 |             /* code hikes gPi->iLhs->aux before test !!! */
 739 |             regValues[gPi->iLhs->aux] = *gPi->iRhs;
 740 |             gPi                       = gPi;
 741 |             gPi->iRhs->type           = T_REG;
 742 |             gPi->iRhs->aux            = l1;
 743 |             if (gPi->iLhs->aux >= REG_BC) {
 744 |                 pi1             = allocInst(gPi);
 745 |                 pi1->iLhs       = allocOperand();
 746 |                 pi1->iRhs       = allocOperand();
 747 |                 pi1->iLhs->type = T_REG;
 748 |                 pi1->iRhs->type = T_REG;
 749 |                 pi1->iLhs->aux  = regHiLoMap[gPi->iLhs->aux].hiReg;
 750 |                 pi1->iRhs->aux  = regHiLoMap[gPi->iRhs->aux].hiReg;
 751 |                 gPi->iLhs->aux  = regHiLoMap[gPi->iLhs->aux].loReg;
 752 |                 gPi->iRhs->aux  = regHiLoMap[gPi->iRhs->aux].loReg;
 753 |                 pi1->type       = T_LD;
 754 |                 gPi             = pi1;
 755 |             }
 756 |             return logOptimise(O_SIMPLE_ADDR); /* 6fd7 opt_msg[13] = "Simplified addresses" */
 757 |         }
 758 |     }
 759 |     regValues[gPi->iLhs->aux] = *gPi->iRhs;
 760 |     return false;
 761 | }
 762 | 
 763 | /**************************************************************************
 764 |  40 sub_2bdb    ok++ (PMO)
 765 |  **************************************************************************/
 766 | bool sub_2bdb() {
 767 |     register inst_t *pi;
 768 | 
 769 |     if (gPi->type == T_STK && gPi->iLhs->aux == REG_BC && gPi->aux == I_POP && !sub_47e0(REG_BC, gPi->pNext, gPi)) {
 770 |         for (pi = gPi->pNext; pi && (pi->type != T_JP && pi->type != T_CALL && pi->type != T_SYMBOL); pi = pi->pNext) {
 771 |             if (pi->type == T_STK)
 772 |                 if (pi->aux != I_PUSH || pi->pNext->type != T_STK || pi->pNext->aux != I_POP) {
 773 |                     break;
 774 |                 } else {
 775 |                     pi = pi->pNext;
 776 |                 }
 777 |             if (pi->type == T_EX || (pi->type == T_LD && pi->iLhs->type == T_REG))
 778 |                 if (pi->iLhs->aux == REG_SP) {
 779 |                     break;
 780 |                 }
 781 |         }
 782 |         if (pi->type == T_STK && pi->aux == I_PUSH && pi->iLhs->aux == REG_HL && !sub_47e0(REG_HL, pi->pNext, pi)) {
 783 |             removeInstruction(gPi);
 784 |             pi->opCode     = NULL;
 785 |             pi->type       = T_EX;
 786 |             pi->aux        = 0;
 787 |             pi->iRhs       = pi->iLhs;
 788 |             pi->iLhs       = allocOperand();
 789 |             pi->iLhs->type = T_REGREF;
 790 |             pi->iLhs->aux  = REG_SP;
 791 |             return logOptimise(O_EX_SPHL); /* 6fd1 opt_msg[10] = "Ex (sp),hl'pi used" */
 792 |         }
 793 |     }
 794 |     return false;
 795 | }
 796 | 
 797 | /**************************************************************************
 798 |  41 sub_2d3b    ok++ (PMO)
 799 |  *
 800 |  * six of the basic blocks are in different positions but the code in the
 801 |  * block is the same and the logic flow is maintained.
 802 |  **************************************************************************/
 803 | #if 1
 804 | 
 805 | bool sub_2d3b() {
 806 |     register operand_t *po;
 807 | 
 808 |     switch (gPi->aux) {
 809 |         default:
 810 |             if (sub_4682(gPi->iLhs)) {
 811 |                 gPi->aux = I_OR;
 812 |             } else if ((po = gPi->iLhs)->type != T_REG || po->aux != REG_A) {
 813 |                 sub_4544(REG_AF);
 814 |                 return false;
 815 |             } else {
 816 |                 break;
 817 |             }
 818 |         /* fall through */
 819 |         case I_OR:
 820 |             po = gPi->iLhs; /* case 0xB0 */
 821 |             if (sub_4682(po)) {
 822 |                 po->type = T_REG;
 823 |                 po->aux  = REG_A;
 824 |             }
 825 |         /* fall through */
 826 |         case I_SUB:
 827 | caseP_SUB: /* common */
 828 |             if (gPi->iLhs->type == T_REG && gPi->iLhs->aux == REG_A) {
 829 |                 if (gPi->aux == I_SUB) {
 830 |                     break;
 831 |                 } else if (!sub_47e0(REG_F, gPi->pNext, gPi)) {
 832 |                     removeInstruction(gPi);
 833 |                     return logOptimise(O_RED_OPS); /* 6fd3 opt_msg[11] = "Redundant operations" */
 834 |                 }
 835 |                 return false;
 836 |             }
 837 |             sub_4544(REG_AF);
 838 |             return false;
 839 |         case I_AND:
 840 |             po = gPi->iLhs;
 841 |             if (sub_4682(po)) {
 842 |                 break;
 843 |             }
 844 |             if (po->type == T_CONST && !po->oPOperand && (po->oVal & 0xff) == 255 /* -1 */) {
 845 |                 gPi->aux = I_OR;
 846 |                 po->type = T_REG;
 847 |                 po->aux  = REG_A;
 848 |             }
 849 |             goto caseP_SUB;
 850 | 
 851 |         case I_CP:
 852 |             return false;
 853 |     }
 854 | 
 855 |     if (!sub_47e0(REG_F, gPi->pNext, gPi) && sub_4682(®Values[REG_A])) {
 856 |         removeInstruction(gPi);
 857 |         return logOptimise(O_RED_OPS); /* 6fd3 opt_msg[11] = "Redundant operations" */
 858 |     }
 859 |     gPi->aux                   = I_XOR;
 860 |     gPi->opCode                = NULL;
 861 |     gPi->iLhs->type            = T_REG;
 862 |     gPi->iLhs->aux             = REG_A;
 863 |     regValues[REG_A].type      = T_CONST;
 864 |     regValues[REG_A].oPOperand = NULL;
 865 |     regValues[REG_A].oVal      = 0;
 866 |     return false;
 867 | }
 868 | 
 869 | #else
 870 | 
 871 | /*  This function generates correct code */
 872 | 
 873 | bool sub_2d3b() {
 874 |     register operand_t *po;
 875 | 
 876 |     switch (gPi->aux) {
 877 |         case P_OR:
 878 |             po = gPi->iLhs;					/* m2: */
 879 |             if (sub_4682(po) != 0) {
 880 |                 po->type = T_REG;
 881 |                 po->aux  = REG_A;
 882 |             }
 883 |         /* fall through */
 884 | 
 885 |         case P_SUB:
 886 | m3:
 887 |             if ((gPi->iLhs->type != T_REG)
 888 |                     && (gPi->iLhs->aux  != REG_A)) {
 889 |                 sub_4544(REG_AF);				/* m8: */
 890 |                 return false;
 891 |             }
 892 |             if (gPi->aux == P_SUB)  {
 893 | m4:
 894 |                 if ((sub_47e0(REG_F, gPi->pNext, gPi)  != 0)
 895 |                         && (sub_4682(®Values[7]) == 0)) {
 896 |                     gPi->aux                   = P_XOR;		/* m12: */
 897 |                     gPi->opCode                = 0;
 898 |                     gPi->iLhs->type            = T_REG;
 899 |                     gPi->iLhs->aux             = REG_A;
 900 |                     regValues[REG_A].type      = T_CONST;
 901 |                     regValues[REG_A].oPOperand = 0;
 902 |                     regValues[REG_A].oVal      = 0;
 903 |                     return false;
 904 |                 }
 905 |                 goto m5;
 906 |             }
 907 |             if (sub_47e0(REG_F, gPi->pNext, gPi) != 0) {	/* m7: */
 908 |                 return false;
 909 |             }
 910 | 
 911 | m5:
 912 |             removeInstruction(gPi);
 913 |             ++optimiseCounters[11]; /* 6fd3 err_msg[11] = "Redundant operations" */
 914 |             return hasChanged = true;
 915 | 
 916 |         case P_AND:
 917 |             po = gPi->iLhs;					/* m6: */
 918 |             if (sub_4682(po) != 0) {
 919 |                 goto m4;
 920 |             }
 921 |             if ((po->type == T_CONST)
 922 |                     && (po->oPOperand == 0)
 923 |                     && (((int)(po->oVal & 0xff) == 255))) {
 924 |                 gPi->aux  = P_OR;
 925 |                 po->type  = T_REG;
 926 |                 po->aux   = REG_A;
 927 |             }
 928 |             goto m3;
 929 | 
 930 |         case P_CP:
 931 |             return false;					/* m9: */
 932 |     }
 933 |     if (sub_4682(gPi->iLhs) != 0) {				/* m1: */
 934 |         gPi->aux = P_OR;
 935 |     }
 936 |     if (((po = gPi->iLhs)->type == T_REG)			/* m10: */
 937 |             && (po->aux == REG_A)) {
 938 |         goto m4;
 939 |     }
 940 |     sub_4544(REG_AF);						/* m11: */
 941 |     return false;
 942 | }
 943 | 
 944 | #endif
 945 | 
 946 | /**************************************************************************
 947 |  42 sub_2ef8    ok++
 948 |  **************************************************************************/
 949 | bool sub_2ef8() {
 950 |     operand_t tmp;
 951 |     int       l2;
 952 | 
 953 |     if (gPi->pNext->type == T_INCDEC && operandsSame(gPi->iLhs, gPi->pNext->iLhs) && gPi->pNext->aux != gPi->aux) {
 954 |         removeInstruction(gPi->pNext);
 955 |     }
 956 | 
 957 |     else if (sub_47e0(REG_HL, gPi->pNext, gPi)) {
 958 |         tmp = regValues[REG_TRACKER];
 959 |         l2  = hlDelta;
 960 |         if (regValues[REG_HL].type != T_INVALID ||
 961 |                 (regValues[REG_L].type == T_INDEXED && regValues[REG_H].type == T_INDEXED &&
 962 |                  regValues[REG_L].aux == regValues[REG_H].aux && regValues[REG_L].oVal + 1 == regValues[REG_H].oVal)) {
 963 |             if (regValues[REG_HL].type != T_INVALID) {
 964 |                 tmp = regValues[REG_HL];
 965 |             } else {
 966 |                 tmp = regValues[REG_L];
 967 |             }
 968 |             l2 = 0;
 969 |         }
 970 |         sub_4544(REG_HL);
 971 |         regValues[REG_TRACKER] = tmp;
 972 |         hlDelta                = l2;
 973 |         if (gPi->aux == SI_INC) {
 974 |             ++hlDelta;
 975 |         } else {
 976 |             --hlDelta;
 977 |         }
 978 |         return false;
 979 |     }
 980 |     removeInstruction(gPi);
 981 |     return logOptimise(O_RED_OPS); /* 6fd3 opt_msg[11] = "Redundant operations" */
 982 | }
 983 | 
 984 | /**************************************************************************
 985 |  42a    sub_3053    ok+-
 986 |  **************************************************************************/
 987 | bool sub_3053() {
 988 |     int l1;
 989 |     int l2;
 990 | 
 991 |     if (gPi->iLhs->type != T_REG || ((l1 = gPi->iLhs->aux) != REG_HL && l1 != REG_L)) {
 992 |         return false;
 993 |     }
 994 | 
 995 |     if (!operandsSame(gPi->iRhs, ®Values[REG_TRACKER])) {
 996 |         return false;
 997 |     }
 998 | 
 999 |     l2 = hlDelta;
1000 |     if (gPi->iLhs->aux == REG_L) {
1001 |         if ((seq2 = gPi->pNext)->type != T_LD || seq2->iLhs->type != T_REG || seq2->iLhs->aux != REG_H ||
1002 |                 seq2->iRhs->oVal != gPi->iRhs->oVal + 1) {
1003 |             return false;
1004 |         }
1005 | 
1006 |         sub_4544(REG_HL);
1007 |         regValues[REG_L] = *gPi->iLhs;
1008 |         regValues[REG_H] = *seq2->iLhs;
1009 |         removeInstruction(seq2);
1010 |     } else {
1011 |         sub_4544(REG_HL);
1012 |         regValues[REG_HL] = *gPi->iLhs;
1013 |     }
1014 |     gPi = gPi->pAlt; /* m4: */
1015 |     removeInstruction(gPi->pNext);
1016 |     while (l2 != 0) {
1017 |         gPi             = allocInst(gPi);
1018 |         gPi->type       = T_INCDEC;
1019 |         gPi->iLhs       = allocOperand();
1020 |         gPi->iLhs->type = T_REG;
1021 |         gPi->iLhs->aux  = REG_HL;
1022 |         if (l2 < 0) {
1023 |             ++l2;
1024 |             gPi->aux = SI_INC;
1025 |         } else {
1026 |             --l2;
1027 |             gPi->aux = SI_DEC;
1028 |         }
1029 |     }
1030 |     return logOptimise(O_RED_LD); /* 6fd5 opt_msg[12] = "Redundant loads/stores" */
1031 | }
1032 | 
1033 | /**************************************************************************
1034 |  43 sub_31ee    ok++
1035 |  **************************************************************************/
1036 | void swapHLDE() {
1037 |     operand_t pi;
1038 | 
1039 |     pi                          = regValues[REG_HL];
1040 |     regValues[REG_HL]           = regValues[REG_DE];
1041 |     regValues[REG_DE]           = pi;
1042 | 
1043 |     pi                          = regValues[REG_H];
1044 |     regValues[REG_H]            = regValues[REG_D];
1045 |     regValues[REG_D]            = pi;
1046 | 
1047 |     pi                          = regValues[REG_L];
1048 |     regValues[REG_L]            = regValues[REG_E];
1049 |     regValues[REG_E]            = pi;
1050 |     regValues[REG_TRACKER].type = T_INVALID;
1051 |     ;
1052 | };
1053 | 
1054 | /**************************************************************************
1055 |  44 pr_psect    sub_328a    ok++
1056 |  **************************************************************************/
1057 | void pr_psect(int psect) {
1058 | 
1059 |     if (psect == cur_psect) {
1060 |         return;
1061 |     }
1062 |     printf("psect\t%s\n", psectNames[psect]);
1063 |     cur_psect = psect;
1064 | }
1065 | 
1066 | /**************************************************************************
1067 |  45 num_psect   sub_32bf    ok++
1068 |  **************************************************************************/
1069 | int num_psect(char const *fmt) {
1070 |     int l1;
1071 | 
1072 |     for (l1 = 0; l1 < 4; ++l1) {
1073 |         if (strcmp(fmt, psectNames[l1]) == 0) {
1074 |             return l1;
1075 |         }
1076 |     }
1077 |     pr_error("Unknown psect");
1078 | }
1079 | 
1080 | /**************************************************************************
1081 |  46	evalExpr	sub_3313  ok++   (PMO) apart from optimiser changes
1082 |  1) one code optimisation to remove jp, putting condition code on call
1083 |  2) code block moved with optimisation on shared code
1084 |  3) two further code block group moves
1085 |  Note the other code is identical and overall the logic is the same
1086 |  **************************************************************************/
1087 | typedef struct {
1088 |     int type; /* 01 s->str */
1089 |     int prec; /* 23 s->i_2 */
1090 | } op_t;
1091 | 
1092 | term_t *evalExpr() {
1093 |     char expectOp;
1094 |     op_t *pOp;
1095 |     term_t *pTerm;
1096 |     term_t termStack[30];
1097 |     op_t opStack[30];
1098 |     static term_t exprResult; /* so pointer to term can be returned */
1099 | 
1100 |     pTerm     = &termStack[30];
1101 |     pOp       = &opStack[29];
1102 |     pOp->type = T_MARKER;
1103 |     pOp->prec = 0;
1104 |     expectOp  = false;
1105 |     do {                                 /* REDUCE loop */
1106 |         for (;; tokType = get_token()) { /* SHIFT loop */
1107 |             if (tokType == T_STRING) {   /* in expressions "A" is treated as ascii value of A */
1108 |                 if (strlen(yylval.pChar) != 1) {
1109 |                     pr_warning("Bad character const");
1110 |                 }
1111 |                 yylval.i = *yylval.pChar;
1112 |                 tokType  = T_CONST;
1113 |             }
1114 |             if (T_FWD <= tokType && tokType <= T_CONST) { /* get the term, note two terms together is an error */
1115 |                 if (expectOp) {
1116 |                     exp_err();
1117 |                 }
1118 |                 expectOp = true; /* flag as expect operator next */
1119 |                 --pTerm;         /* where to push the term */
1120 |                 switch (tokType) {
1121 |                     case T_SYMBOL: /* its reocatable */
1122 |                         pTerm->tPSym = yylval.pSym;
1123 |                         pTerm->val   = 0;
1124 |                         break;
1125 |                     case T_CONST: /* its a constant */
1126 |                         pTerm->val   = yylval.i;
1127 |                         pTerm->tPSym = NULL;
1128 |                         break;
1129 |                 }
1130 |                 continue;
1131 |             } else if (T_UPLUS <= tokType && tokType <= T_LASTOP) {           /* get the operator */
1132 |                 if (!expectOp && (tokType == T_PLUS || tokType == T_MINUS)) { /* map unary +/- */
1133 |                     tokType  = tokType - 7;
1134 |                     yylval.i = 8; /* set its precedence */
1135 |                 }
1136 |                 if (tokType <= T_MARKER) {
1137 |                     if (expectOp) {
1138 |                         exp_err();
1139 |                     }
1140 |                 } else {
1141 |                     if (!expectOp && tokType != T_OPAR) { /* binary op only when expecting op*/
1142 |                         exp_err();
1143 |                     }
1144 |                     if (pOp->prec >= yylval.i) { /* pick up precedence */
1145 |                         break;
1146 |                     }
1147 |                 }
1148 |                 if (tokType != T_CPAR) { /* not a closing ) */
1149 |                     --pOp;
1150 |                     pOp->type = tokType;   /* push its type */
1151 |                     if (tokType == T_OPAR) { /* if it was a ( then set prec to 1 */
1152 |                         yylval.i = 1;
1153 |                     } else {                                 /* OPTIMISER[2]: code moved to here */
1154 |                         expectOp = false;    /* now expecting a term */
1155 |                     }
1156 |                     pOp->prec = yylval.i; /* set the prec */ /* OPTIMISER[3] code block moved / shared */
1157 |                 } else if (pOp->type ==
1158 |                            T_MARKER) /* ) with nothing on stack */ { /* OPTIMISER[4]: test code block moved */
1159 |                     break;
1160 |                 }
1161 |             } else {
1162 |                 break;
1163 |             }
1164 |         }
1165 | 
1166 |         /* REDUCE phase */
1167 |         if (pOp->type == T_OPAR) { 	/* check for matching () */
1168 |             if (tokType != T_CPAR) {
1169 |                 exp_err();    		/* ")" */
1170 |             }
1171 |             tokType  = get_token(); 	/* prime for next part */
1172 |             expectOp = 1;           	/* assuming its a term */
1173 |         } else if (T_MARKER >= pOp->type) {
1174 |             uconv(pOp->type, pTerm);    /* calculate unary operator */
1175 |         } else {
1176 |             bconv(pOp->type, pTerm + 1, pTerm); /* calculate binary operator*/
1177 |             ++pTerm;
1178 |         }
1179 |     } while (++pOp != &opStack[30]); 	/* loop till end of operator stack */
1180 | 
1181 |     exprResult = *pTerm;
1182 |     if (&termStack[29] != pTerm) { 	/* oops outstanding term */
1183 |         exp_err();
1184 |     }
1185 |     return &exprResult;
1186 | }
1187 | 
1188 | /**************************************************************************
1189 |  47 exp_err     sub_32bf    ok++ (PMO)
1190 |  **************************************************************************/
1191 | void exp_err() {
1192 | 
1193 |     pr_error("Expression error");
1194 | }
1195 | 
1196 | /**************************************************************************
1197 |  48 sub_359e    ok++ (PMO)
1198 |  *
1199 |  *  Unary operators
1200 |  **************************************************************************/
1201 | void uconv(int op, term_t *lhs) {
1202 | 
1203 |     switch (op) {
1204 |         case T_UMINUS:
1205 |             lhs->val = -lhs->val;
1206 |             break;
1207 |         case T_NOT:
1208 |             lhs->val = ~lhs->val;
1209 |             break;
1210 |         case T_HI:
1211 |             lhs->val = (lhs->val >> 8) & 0xff;
1212 |             break;
1213 |         case T_LOW:
1214 |             lhs->val &= 0xff;
1215 |             break;
1216 |         case T_UPLUS:
1217 |             return;
1218 |         case T_MARKER:
1219 |             return;
1220 |         default:
1221 |             pr_error("uconv - bad op");
1222 |     }
1223 |     if (lhs->tPSym) {
1224 |         rel_err();
1225 |     }
1226 |     return;
1227 | }
1228 | 
1229 | /**************************************************************************
1230 |  49 sub_3630    ok++ (PMO)
1231 |  *
1232 |  *  Binary operators
1233 |  **************************************************************************/
1234 | void bconv(int op, term_t *lhs, term_t const *rhs) {
1235 | 
1236 |     switch (op) {
1237 |         case T_PLUS:
1238 |             if (lhs->tPSym && rhs->tPSym) {
1239 |                 rel_err();
1240 |             }
1241 |             lhs->val += rhs->val;
1242 |             if (!lhs->tPSym) {
1243 |                 lhs->tPSym = rhs->tPSym;
1244 |             }
1245 |             return;
1246 |         case T_MINUS:
1247 |             if (rhs->tPSym) {
1248 |                 rel_err();
1249 |             }
1250 |             lhs->val -= rhs->val;
1251 |             return;
1252 |         case T_MUL:
1253 |             lhs->val *= rhs->val;
1254 |             break;
1255 |         case T_DIV:
1256 |             lhs->val /= rhs->val;
1257 |             break;
1258 |         case T_MOD:
1259 |             lhs->val %= rhs->val;
1260 |             break;
1261 |         case T_SHR:
1262 |             lhs->val >>= rhs->val;
1263 |             break;
1264 |         case T_SHL:
1265 |             lhs->val <<= rhs->val;
1266 |             break;
1267 |         case T_AND:
1268 |             lhs->val &= rhs->val;
1269 |             break;
1270 |         case T_OR:
1271 |             lhs->val |= rhs->val;
1272 |             break;
1273 |         case T_XOR:
1274 |             lhs->val ^= rhs->val;
1275 |             break;
1276 |         case T_EQ:
1277 |             lhs->val = lhs->val == rhs->val;
1278 |             break;
1279 |         case T_LE:
1280 |             lhs->val = rhs->val < lhs->val;
1281 |             break;
1282 |         case T_GE:
1283 |             lhs->val = lhs->val < rhs->val;
1284 |             break;
1285 |         case T_ULE:
1286 |             lhs->val = (uint16_t)rhs->val < (uint16_t)lhs->val;
1287 |             break;
1288 |         case T_UGE:
1289 |             lhs->val = (uint16_t)lhs->val < (uint16_t)rhs->val;
1290 |             break;
1291 |         default:
1292 |             pr_error("Bconv - bad op");
1293 |             break;
1294 |     }
1295 | 
1296 |     if (lhs->tPSym || rhs->tPSym) {
1297 |         rel_err();
1298 |     }
1299 | }
1300 | 
--------------------------------------------------------------------------------
/part31.c:
--------------------------------------------------------------------------------
   1 | /*
   2 |  * File part31.c created 14.08.2021, last modified 11.11.2021.
   3 |  *
   4 |  * The part31.c file is part of the restored optimization program
   5 |  * from the Hi-Tech C compiler v3.09 package.
   6 |  *
   7 |  *	Andrey Nikitin & Mark Ogden 11.11.2021
   8 |  */
   9 | 
  10 | #include 
  11 | #include 
  12 | #include 
  13 | #include 
  14 | #include "optim1.h"
  15 | 
  16 | int regTestMasks[] = {
  17 |     0x01,                              		/* 6cb2 REG_B   */
  18 |     0x02,                              		/* 6cb4 REG_C   */
  19 |     0x04,                              		/* 6cb6 REG_D   */
  20 |     0x08,                              		/* 6cb8 REG_E   */
  21 |     0x10,                              		/* 6cba REG_H   */
  22 |     0x20,                              		/* 6cbc REG_L   */
  23 |     0x40,                              		/* 6cbe REG_F   */
  24 |     0x80,                              		/* 6cc0 REG_A   */
  25 |     0x00,                              		/* 6cc2 REG_I   */
  26 |     0x00,                              		/* 6cc4 REG_R   */
  27 |     0x03,                              		/* 6cc6 REG_BC  */
  28 |     0x0C,                              		/* 6cc8 REG_DE  */
  29 |     0x30,                              		/* 6cca REG_HL  */
  30 |     0x00,                              		/* 6ccc REG_SP  */
  31 |     0xC0,                              		/* 6cce REG_AF  */
  32 |     0x00,                              		/* 6cd0 REG_AF1 */
  33 |     0x100,                             		/* 6cd2 REG_IX  */
  34 |     0x200,                             		/* 6cd4 REG_IY  */
  35 | };
  36 | 
  37 | /**************************************************************************
  38 |  50 rel_err     ok++
  39 |  **************************************************************************/
  40 | void rel_err() {
  41 | 
  42 |     pr_warning("Relocation error");
  43 | }
  44 | 
  45 | /**************************************************************************
  46 |  51 sub_3856    ok++ (PMO) except for one jp z, that is optimised to jr z,
  47 |  **************************************************************************/
  48 | operand_t *evalOperand() {
  49 |     register operand_t *oper;
  50 | 
  51 |     oper = allocOperand();
  52 | 
  53 |     switch (tokType) {
  54 |         case T_EOL:
  55 |             oper->type = T_INVALID;
  56 |             break;
  57 | 
  58 |         case T_REG:
  59 |             if (expectCond && yylval.i == REG_C) { /* check if C is used in jp c context */
  60 |                 tokType  = T_COND;                 /* convert to condition */
  61 |                 yylval.i = COND_LLT;
  62 |             }
  63 |         /* fall through */
  64 |         case T_COND:
  65 |             oper->type = tokType; /* save type, value and prep for next token */
  66 |             oper->aux  = (uint8_t)yylval.i;
  67 |             tokType    = get_token();
  68 |             break;
  69 | 
  70 |         case T_OPAR:
  71 |             if ((tokType = get_token()) == T_REG) {
  72 |                 if (yylval.i != REG_C && yylval.i < REG_BC) { /* only (C) and (BC) onwards are valid */
  73 |                     oper_err();
  74 |                 }
  75 |                 oper->type = T_REGREF;
  76 |                 oper->aux  = (uint8_t)yylval.i;          /* save reg id */
  77 |                 if ((tokType = get_token()) == T_CPAR) { /* simple (reg) so prep for next token */
  78 |                     tokType = get_token();
  79 |                     break;
  80 |                 }
  81 |                 if (oper->aux < REG_IX) { /* only IX & IY are allowed expressions */
  82 |                     oper_err();
  83 |                 }
  84 |                 oper->type = T_INDEXED; /* is IX/IY +/- d operand */
  85 |             } else {
  86 |                 oper->type = T_ADDRREF;    /* is a (addr) operand */
  87 |             }
  88 | 
  89 |             oper->term = *evalExpr(); /* get the expression */
  90 | 
  91 |             if (tokType != T_CPAR) { /* should now be the closing ) */
  92 |                 oper_err();
  93 |             }
  94 |             tokType = get_token(); /* prep for next token */
  95 |             /* IX & IY are only allowed displacements -128 to 127 */
  96 |             if (oper->type == T_INDEXED && (oper->oVal < -128 || oper->oVal >= 128)) {
  97 |                 pr_warning("Index offset too large");
  98 |             }
  99 |             break;
 100 |         /*
 101 |             the operands below are only valid as the last operand on a line
 102 |             so there is no preping for the next token
 103 |         */
 104 |         case T_FWD:
 105 |         case T_BWD:
 106 |             oper->type = tokType;
 107 |             oper->oVal = yylval.i; /* save the label reference number */
 108 |             break;
 109 |         default:
 110 |             oper->type = T_CONST;
 111 |             oper->term = *evalExpr(); /* allow for more complex expression */
 112 |     }
 113 |     return oper;
 114 | }
 115 | 
 116 | /**************************************************************************
 117 |  52 oper_err    ok++ (PMO) but note jmpbuf not set
 118 |  **************************************************************************/
 119 | void oper_err() {
 120 | 
 121 |     pr_warning("Operand error");
 122 |     longjmp(jmpbuf, 1); /* BUG: jmpbuf not set */
 123 | }
 124 | 
 125 | /**************************************************************************
 126 |  53 sub_39a3    ok++ (PMO)
 127 |  **************************************************************************/
 128 | void getOperands(register inst_t *pi) {
 129 | 
 130 |     tokType    = get_token();
 131 |     cntOperand = 0;
 132 |     pi->iLhs   = NULL;
 133 |     pi->iRhs   = NULL;
 134 |     if (tokType == T_COMM) {
 135 |         oper_err();			/* cannot start with a comma */
 136 |     }
 137 |     if (tokType != T_EOL) {		/* no operands */
 138 |         pi->iLhs = evalOperand();
 139 |         if (tokType == T_COMM) {	/* if comma then 2nd operand */
 140 |             tokType  = get_token();
 141 |             pi->iRhs = evalOperand();
 142 |             ++cntOperand;
 143 |         }
 144 |         ++cntOperand;
 145 |     }
 146 |     clr_len_inbuf();
 147 | }
 148 | 
 149 | /**************************************************************************
 150 |  54 sub_3a15    ok++ (PMO)
 151 |  **************************************************************************/
 152 | void loadFunction() {
 153 |     sym_t  *ps;
 154 |     inst_t *l2;
 155 |     inst_t *l3;
 156 |     int     fpBase;
 157 |     register inst_t *pi;
 158 | 
 159 |     pi = root = (inst_t *)alloc_mem(sizeof(inst_t));
 160 |     pi->pNext = (inst_t *)alloc_mem(sizeof(inst_t));
 161 |     HEAP(pi->pNext);
 162 |     pi->pNext->pAlt = pi;
 163 |     pi              = pi->pNext;
 164 |     l2 = switchVectors = word_6fee = (inst_t *)alloc_mem(sizeof(inst_t));
 165 | 
 166 |     for (;; HEAP(pi->iRhs)) {
 167 |         tokType = get_token();
 168 |         HEAP(pi->iRhs);
 169 |         for (;; HEAP(pi->pNext)) {
 170 |             if (tokType == T_EOL) {
 171 |                 clr_len_inbuf();
 172 |                 break;
 173 |             }
 174 | 
 175 |             if (pi->type != T_INVALID) {
 176 |                 pi = allocInst(pi);    /* m3: */
 177 |             }
 178 |             if (tokType == -1) {    /* m4: */
 179 |                 word_6ffc = pi;
 180 |                 word_6fee = l2;
 181 |                 return;
 182 |             }
 183 |             pi->type = tokType; /* m5: */
 184 |             if (psect == SWDATA) {
 185 |                 if (tokType == T_DEFW) { /* collect the switch table */
 186 |                     pi->opCode = yytext;
 187 |                     getOperands(pi);
 188 |                     l2->pNext       = pi;
 189 |                     pi              = pi->pAlt;
 190 |                     pi->pNext       = NULL;
 191 |                     l2->pNext->pAlt = l2;
 192 |                     l2              = l2->pNext;
 193 |                     break;
 194 |                 }
 195 |                 psect = DATA; /* revert to normal data handling */
 196 |             }
 197 |             switch (pi->type = tokType) { /* m7: */
 198 |                 case T_CONST:
 199 |                     if ((psect == DATA) || (psect == BSS)) {
 200 |                         pi->type = T_INVALID;
 201 |                         pr_psect(psect);
 202 |                         printf("%d:\n", yylval.i);
 203 |                     } else {
 204 |                         pi->aux = yylval.i; /* m10: */
 205 |                         l3      = pi->pAlt;
 206 |                         if (pi->pAlt->type == T_JP && l3->iLhs->type == T_FWD && l3->iLhs->oVal == pi->aux) {
 207 |                             removeInstruction(l3);
 208 |                         }
 209 |                     }
 210 |                     tokType = get_token(); /* m11: */
 211 |                     if (tokType != T_COLN) {
 212 |                         pr_error("Bad temp label");
 213 |                     }
 214 |                     break;
 215 | 
 216 |                 case T_SYMBOL:
 217 |                     ps      = yylval.pSym;
 218 |                     pi->aux = 0;
 219 |                     tokType = get_token();
 220 |                     if (tokType == T_EQU) {
 221 |                         if (ps->label[0] != 'f') { /* compiler generated equ names begin with f */
 222 |                             pr_error("Unknown EQU");
 223 |                         }
 224 | 
 225 |                         pi->type = T_INVALID;
 226 |                         tokType  = get_token();
 227 |                         pi->iLhs = evalOperand();
 228 |                         /* check is constant with no unresolved symbol ref */
 229 |                         if (pi->iLhs->type != T_CONST || pi->iLhs->oPSym) {
 230 |                             pr_error("Bad arg to EQU");
 231 |                         }
 232 | 
 233 |                         fpBase    = pi->iLhs->oVal; /* the frame pointer offset to lowest local (will be 0 or -ve) */
 234 | 
 235 |                         word_6ffc = pi;
 236 |                         word_6fee = l2;
 237 |                         pi        = root;
 238 | 
 239 |                         do { /* update any references to the frame size */
 240 |                             if (pi->iRhs && pi->iRhs->type == T_CONST && pi->iRhs->oPSym == ps) {
 241 |                                 pi->iRhs->oVal += fpBase;
 242 |                                 pi->iRhs->oPSym = NULL;
 243 |                             }
 244 |                             if (pi->iLhs && pi->iLhs->type == T_CONST && pi->iLhs->oPSym == ps) {
 245 |                                 pi->iLhs->oVal += fpBase;
 246 |                                 pi->iLhs->oPSym = NULL;
 247 |                             }
 248 |                         } while (pi = pi->pNext);
 249 |                         return;
 250 |                     }
 251 |                     pi->iPSym   = ps;
 252 | 
 253 |                     ps->p.pInst = pi;
 254 | 
 255 |                     pi->aux     = INT_MAX;
 256 |                     if (psect == DATA && ps->label[0] == 'S') { /* compiler generated switch tables start with S */
 257 |                         psect           = SWDATA;
 258 |                         l2->pNext       = pi;
 259 |                         pi              = pi->pAlt;
 260 |                         pi->pNext       = NULL;
 261 |                         l2->pNext->pAlt = l2;
 262 |                         l2              = l2->pNext;
 263 |                     }
 264 |                     if (psect == DATA || psect == BSS) {
 265 |                         pi->type    = T_INVALID;
 266 |                         pi->iLhs    = NULL;
 267 |                         ps->p.pInst = NULL;
 268 |                         pr_psect(psect);
 269 |                         printf("%s:\n", ps->label);
 270 |                     } else if (ps->label[0] == '_') { /* external name */
 271 |                         name_fun = ps->label;
 272 |                     }
 273 | 
 274 |                     if (tokType == T_COLN) {
 275 |                         break;
 276 |                     }
 277 |                     continue; /* inner loop */
 278 | 
 279 |                 case 255: /* -1 */
 280 |                     pi->type  = T_INVALID;
 281 |                     word_6ffc = pi;
 282 |                     return;
 283 | 
 284 |                 case T_DEFW:
 285 |                 case T_DEFB:
 286 |                     if (psect == TEXT) {
 287 |                         goto case_default;
 288 |                     }
 289 |                 case T_DEFM:
 290 |                 case T_DEFS:
 291 |                 case T_DEFF:
 292 |                     if (psect == TEXT) {
 293 |                         pr_error("DEF[BMSF] in text psect");
 294 |                     }
 295 |                     pr_psect(psect);
 296 |                 /* fall through */
 297 |                 case T_GLB:
 298 |                     printf("%s\t%s\n", yytext, ptr_token());
 299 |                     pi->type = T_INVALID;
 300 |                     break;
 301 | 
 302 |                 case T_PSCT:
 303 |                     psect    = num_psect(ptr_token()); /* m30: */
 304 |                     pi->type = T_INVALID;
 305 |                     break;
 306 | 
 307 |                 case T_JR:
 308 |                     pi->type = T_JP; /* convert to jp so it is safe to move code */
 309 |                     yytext   = "jp";
 310 |                 /* fall through */
 311 |                 default:
 312 | case_default:
 313 |                     pi->opCode = yytext;
 314 |                     pi->aux    = yylval.i;
 315 |                     if (tokType == T_JP || tokType == T_CALL) { /* set if can have conditional */
 316 |                         expectCond = true;
 317 |                     } else {
 318 |                         expectCond = false;
 319 |                     }
 320 |                     getOperands(pi);
 321 |                     if ((pi->type == T_JP) || (pi->type == T_CALL)) {
 322 |                         if (pi->iLhs->type == T_COND) { /* if cond then hoist condition and remove lhs */
 323 |                             pi->aux  = pi->iLhs->aux;
 324 |                             pi->iLhs = pi->iRhs;
 325 |                             pi->iRhs = NULL;
 326 |                         }
 327 |                     }
 328 |                     if (pi->type == T_JP && pi->aux == 0 && pi->iLhs->type != T_REGREF &&
 329 |                             (l3 = pi->pAlt)->type == T_CONST && l3->pAlt->type == T_JP && l3->pAlt->aux == 0) {
 330 | 
 331 |                         while (l3 = l3->pAlt) {
 332 |                             if (l3->type == T_JP && l3->iLhs->type == T_FWD && l3->iLhs->oVal == pi->pAlt->aux) {
 333 |                                 *l3->iLhs = *pi->iLhs;
 334 |                             } else if (l3->type == T_CONST && l3->aux == pi->pAlt->aux) {
 335 |                                 break;
 336 |                             }
 337 |                         }
 338 |                         removeInstruction(pi->pAlt);
 339 |                         freeOperand(pi->iLhs);
 340 |                         pi->type   = T_INVALID;
 341 |                         pi->iLhs   = NULL;
 342 |                         pi->opCode = NULL;
 343 |                     }
 344 |                     break;
 345 |             }
 346 |             break; /* to outer loop */
 347 |         }
 348 |     }
 349 | }
 350 | 
 351 | /**************************************************************************
 352 |  55 sub_4000    ok++ (PMO)
 353 |  **************************************************************************/
 354 | bool sub_4000(register inst_t const *pi) {
 355 | 
 356 |     return pi->type == T_JP && pi->iLhs->oPSym && strcmp(pi->iLhs->oPSym->label, "cret") == 0;
 357 | }
 358 | 
 359 | /**************************************************************************
 360 |  56 sub_404d    ok++ (PMO)  Used in: optimise
 361 |  **************************************************************************/
 362 | void sub_404d() {
 363 | 
 364 |     register inst_t *pi;
 365 | 
 366 |     if (root->pNext) {
 367 |         pr_psect(TEXT);
 368 |         for (pi = root->pNext; pi; pi = pi->pNext) {
 369 |             if (pi->type == T_CALL && strcmp(pi->iLhs->oPSym->label, "ncsv") == 0) {
 370 |                 pi = pi->pNext;
 371 |                 if (pi->type != T_DEFW) { /* "defw" */
 372 |                     pr_error("Expecting defw after call ncsv");
 373 |                 }
 374 |                 if (pi->iLhs->oVal == 0) {
 375 |                     if (usesIXorIY) {
 376 |                         printf("global csv\ncall csv\n");
 377 |                     }
 378 |                 } else {
 379 |                     usesIXorIY = true;
 380 |                     if (pi->iLhs->oVal >= -4) {
 381 |                         printf("global csv\ncall csv\npush hl\n");
 382 |                         if (pi->iLhs->oVal < -2) {
 383 |                             printf("push hl\n");
 384 |                         }
 385 |                     } else {
 386 |                         printf("call ncsv\ndefw %d\n", pi->iLhs->oVal);
 387 |                     }
 388 |                 }
 389 |             } else if (!usesIXorIY && sub_4000(pi)) {
 390 |                 pi->type   = T_RET;
 391 |                 pi->opCode = NULL;
 392 |                 pr_instruction(pi);
 393 |             } else if (!usesIXorIY && pi->type == T_CALL && pi->aux == 0 && pi->pNext->aux == 0 &&
 394 |                        sub_4000(pi->pNext) && pi->iLhs->oPSym->label[0] == '_') {
 395 |                 pi->type   = T_JP; /* "jp" */
 396 |                 pi->opCode = NULL;
 397 |                 pr_instruction(pi);
 398 |                 pi = pi->pNext;
 399 |             } else {
 400 |                 pr_instruction(pi);
 401 |             }
 402 |         }
 403 |     }
 404 |     if (switchVectors->pNext) {
 405 |         pr_psect(DATA);
 406 |         for (pi = switchVectors->pNext; pi; pi = pi->pNext) {
 407 |             pr_instruction(pi);
 408 |         }
 409 |     }
 410 | }
 411 | 
 412 | /**************************************************************************
 413 |  57 pr_instruction	sub_420a    ok++ (PMO)
 414 |  *
 415 |  * benign differences
 416 |  *   1) printf call/return code is shared
 417 |  *   2) fputc('\n', stdout) is located differently
 418 |  **************************************************************************/
 419 | void pr_instruction(register inst_t *pi) {
 420 | 
 421 |     if (pi->type == T_INVALID)
 422 |         ;
 423 |     else if (pi->type == T_SYMBOL) {
 424 |         if ((pi->iPSym->label[0])) {
 425 |             printf("%s:\n", pi->iPSym->label);
 426 |         } else {
 427 |             printf("L%d:\n", pi->iSymId);
 428 |         }
 429 |     } else if (pi->type == T_CONST) {		/* m4: */
 430 |         printf("%d:\n", pi->aux);     /* OPTIMISER[1]: shares printf call with above*/
 431 |     } else if (key_f && pi->type == T_CALL && strcmp(pi->iLhs->oPSym->label, "csv") == 0) {
 432 |         printf("push\tiy\npush\tix\nld\tix,0\nadd\tix,sp\n");
 433 |     } else {
 434 |         if (key_n) {
 435 |             fputc('\t', stdout);		/* m7: */
 436 |         }
 437 | 
 438 |         pr_token(pi);
 439 | 
 440 |         if (pi->type == T_JP || pi->type == T_CALL || pi->type == T_RET) {
 441 |             fputc('\t', stdout);
 442 |             if (pi->aux != 0) {
 443 |                 printf("%s", conditions[pi->aux]);
 444 |             }
 445 |             if (pi->type != T_RET) {
 446 |                 if (pi->aux != 0) {
 447 |                     fputc(',', stdout);
 448 |                 }
 449 |                 sub_436e(pi->iLhs);		/* m11: */
 450 |             }
 451 |         } else if (pi->iLhs) {			/* m14: */
 452 |             fputc('\t', stdout);
 453 |             sub_436e(pi->iLhs);
 454 |             if (pi->iRhs) {
 455 |                 fputc(',', stdout);
 456 |                 sub_436e(pi->iRhs);
 457 |             }
 458 |         }
 459 |         fputc('\n', stdout); /* OPTIMISER: minor movement in where this is located also optimises return */
 460 |     }
 461 | }
 462 | 
 463 | /**************************************************************************
 464 |  58 sub_436e    ok++ (PMO)
 465 |  Same except optimiser misses the optimisation of fputc(')', stdout)
 466 |  **************************************************************************/
 467 | void sub_436e(register operand_t const *pi) {
 468 | 
 469 |     HEAP(pi);
 470 |     switch (pi->type) {
 471 |         case T_INDEXED:
 472 |         case T_ADDRREF:
 473 |             fputc('(', stdout);
 474 |             if (pi->type == T_INDEXED) {
 475 |                 if (pi->aux == REG_IX) {
 476 |                     printf("ix");
 477 |                 } else {
 478 |                     printf("iy");
 479 |                 }
 480 |                 fputc('+', stdout);
 481 |             }
 482 |         case T_CONST:
 483 |             if (pi->oPSym) {
 484 |                 if (pi->oPSym->label[0]) {
 485 |                     printf("%s", pi->oPSym->label);
 486 |                 } else {
 487 |                     printf("L%d", pi->oPSym->p.pInst->iSymId);
 488 |                 }
 489 |                 if (0 < pi->oVal) {
 490 |                     fputc('+', stdout);
 491 |                 }
 492 |             }
 493 |             if (pi->oVal != 0 || !pi->oPSym) {
 494 |                 printf("%d", pi->oVal);
 495 |             }
 496 |             if (pi->type != T_CONST) {
 497 |                 fputc(')', stdout);
 498 |             }
 499 |             break;
 500 |         case T_REGREF:
 501 |             fputc('(', stdout);
 502 |         case T_REG:
 503 |             printf("%s", regs[pi->aux]);
 504 |             if (pi->type == T_REGREF) {
 505 |                 fputc(')', stdout);    /* OPTIMISER[1]: misses optimising htis with same fputc above */
 506 |             }
 507 |             break;
 508 |         case T_FWD:
 509 |             printf("%df", pi->oVal);
 510 |             break;
 511 |         default:
 512 |             pr_error("Bad operand");
 513 |             break;
 514 |     }
 515 |     HEAP(pi);
 516 | }
 517 | 
 518 | /**************************************************************************
 519 |  59 sub_44b2    ok++ (PMO)
 520 |  Optimiser saves some code with minor changes to code for regValues[18]
 521 | 
 522 |  original                   replacement
 523 |  ld a,(regValues + 6ch)     ld  hl,regvalues + 6ch  ; test regValues[18].type
 524 |  or a                       ld  a,(hl)
 525 |  jp z,cret                  or  a
 526 |  push   iy                  jp  z,cret
 527 |  ld hl,regVales + 6ch       push    iy
 528 |  push   hl                  push    hl              ; ®Values[18]
 529 | 
 530 |  The replacement code is slightly short
 531 |  **************************************************************************/
 532 | void sub_44b2(register operand_t const *po) {
 533 |     int n;
 534 | 
 535 |     while ((n = sub_46b1(po, REG_B)) != -1) {
 536 |         sub_4544(n);
 537 |     }
 538 |     while ((n = sub_46b1(po, REG_BC)) != -1) {
 539 |         sub_4544(n);
 540 |     }
 541 | 
 542 |     if (regValues[17].type && operandsSame(po, ®Values[17])) {
 543 |         sub_4544(17);
 544 |     }
 545 | 
 546 |     if (regValues[REG_TRACKER].type && operandsSame(®Values[REG_TRACKER], po)) {
 547 |         regValues[REG_TRACKER].type = T_INVALID;
 548 |     }
 549 | }
 550 | 
 551 | /**************************************************************************
 552 |  60 sub_4544    ok++ (PMO)
 553 |  *
 554 |  * Optimiser generates marginally less efficient code for regValues[18]
 555 |  * access it chooses to use hl and (hl) rather than the load directly
 556 |  * to/from a code functionally is the same
 557 |  **************************************************************************/
 558 | void sub_4544(int reg) {
 559 |     register operand_t *pi;
 560 | 
 561 |     regValues[reg].type = T_INVALID;
 562 |     if (regTestMasks[REG_HL] & regTestMasks[reg]) {
 563 |         hlDelta                     = 0;
 564 |         regValues[REG_TRACKER].type = T_INVALID;
 565 |     }
 566 |     if (pi = regHiLoValMap[reg].pHiRegVal) {
 567 |         pi->type = T_INVALID;
 568 |         if (pi = regHiLoValMap[reg].pLoRegVal) {
 569 |             pi->type = T_INVALID;
 570 |         }
 571 |     }
 572 |     if (reg != 17) {
 573 |         return;
 574 |     }
 575 |     for (pi = regValues; pi < ®Values[REG_TRACKER]; ++pi)
 576 |         if (pi->type == T_INDEXED && pi->aux == REG_IY) {
 577 |             pi->type = T_INVALID;
 578 |         }
 579 | 
 580 |     if (regValues[REG_TRACKER].type == T_INDEXED && regValues[REG_TRACKER].aux == REG_IY) {
 581 |         regValues[REG_TRACKER].type = T_INVALID;
 582 |     }
 583 | }
 584 | 
 585 | /**************************************************************************
 586 |  61 sub_4601    ok+
 587 |  *
 588 |  *  Generates correct code, but different from original
 589 |  **************************************************************************/
 590 | void sub_4601() {
 591 |     register operand_t *po;
 592 | 
 593 |     for (po = regValues; po < ®Values[REG_TRACKER]; ++po) {
 594 |         po->type = T_INVALID;
 595 |     }
 596 |     regValues[REG_TRACKER].type = T_INVALID;
 597 | }
 598 | 
 599 | /**************************************************************************
 600 |  62 sub_4625    ok+
 601 |  *
 602 |  *  Generates correct code, but in a sequence different from original
 603 |  **************************************************************************/
 604 | bool sub_4625(register inst_t const *pi) {
 605 | 
 606 |     switch (pi->type) {
 607 |         case T_LD:
 608 |         case T_STK:
 609 |             return true;
 610 |         case T_INCDEC:
 611 |             return pi->iLhs->type == T_REG && pi->iLhs->aux >= REG_BC;
 612 |         case T_EX:
 613 |             return pi->iLhs->aux != REG_AF;
 614 |     }
 615 |     return false;
 616 | }
 617 | 
 618 | /**************************************************************************
 619 |  63 sub_4682    ok++
 620 |  **************************************************************************/
 621 | bool sub_4682(register operand_t const *pi) {
 622 | 
 623 |     return pi->type == T_CONST && !pi->oPSym && pi->oVal == 0;
 624 | }
 625 | 
 626 | /**************************************************************************
 627 |  64 sub_46b1    ok++
 628 |  **************************************************************************/
 629 | int sub_46b1(register operand_t const *opr, int reg) {
 630 |     operand_t *po;
 631 |     int        i;
 632 | 
 633 |     po = reg < REG_BC ? ®Values[REG_B] : ®Values[REG_BC];
 634 |     do {
 635 |         if (po->type) {
 636 |             if (operandsSame(po, opr)) {
 637 |                 i = (int)(po - regValues);
 638 |                 if (i >= REG_BC && reg < REG_BC) {
 639 |                     return regHiLoMap[i].loReg;
 640 |                 }
 641 |                 return i;
 642 |             }
 643 |         }
 644 |     } while (++po < ®Values[REG_SP]);
 645 |     return -1;
 646 | }
 647 | 
 648 | /**************************************************************************
 649 |  65 sub_475c    ok++
 650 |  **************************************************************************/
 651 | int sub_475c(register operand_t const *po, int p2) {
 652 | 
 653 |     if (!po) {
 654 |         return false;
 655 |     }
 656 |     if (po->type != T_REG && po->type != T_INDEXED && po->type != T_REGREF) {
 657 |         return false;
 658 |     }
 659 |     if (p2 & regTestMasks[po->aux]) {
 660 |         return true;
 661 |     }
 662 |     return false;
 663 | }
 664 | 
 665 | /**************************************************************************
 666 |  66 sub_47a2    ok++
 667 |  **************************************************************************/
 668 | int sub_47a2(register operand_t const *po, int p2) {
 669 | 
 670 |     if (!po) {
 671 |         return false;
 672 |     }
 673 |     if (po->type != T_REG) {
 674 |         return false;
 675 |     }
 676 |     if (p2 & regTestMasks[po->aux]) {
 677 |         return true;
 678 |     }
 679 |     return false;
 680 | }
 681 | 
 682 | /**************************************************************************
 683 |  67 sub_47e0    ok++ (PMO)
 684 |  *
 685 |  *  Optimiser differences
 686 |  * 1) The code for case 0 is detected as the same as the code in case T_JP
 687 |  *    and reused
 688 |  * 2) There are two instances where the test cases are reversed along with
 689 |  *    the associated jumps. Leaving the logic the same
 690 |  **************************************************************************/
 691 | bool sub_47e0(int reg, register inst_t const *pi1, inst_t const *pi2) {
 692 |     uint16_t msk;
 693 |     sym_t   *ps;
 694 |     inst_t  *l3;
 695 |     int      n; /* number of iterations */
 696 | 
 697 |     if (reg == REG_SP || reg == REG_IX) {
 698 |         return true;
 699 |     }
 700 | 
 701 |     if (REG_BC <= reg && reg <= REG_HL) {
 702 |         if (sub_47e0(regHiLoMap[reg].hiReg, pi1, pi2)) {
 703 |             return true;
 704 |         }
 705 |         reg = regHiLoMap[reg].loReg;
 706 |     }
 707 |     if (reg >= sizeof(regTestMasks) / sizeof(regTestMasks[0])) {
 708 |         fprintf(stderr, "%d\n", reg);
 709 |     }
 710 |     /* #pragma warning(suppress : 6385) /* reg has limited values */
 711 |     msk = regTestMasks[reg]; /* m3: */
 712 |     n   = 40;
 713 | 
 714 |     do {
 715 |         switch (pi1->type) {
 716 | 
 717 |             case T_CALL:
 718 |                 if (pi1->aux != 0 && (msk & 0x40)) {
 719 |                     return true;
 720 |                 }
 721 | 
 722 |                 if (reg == REG_IY) {
 723 |                     break;
 724 |                 }
 725 |                 if (!pi1->iLhs->oPSym || pi1->iLhs->oPSym->label[0] == '_') {
 726 |                     return false;
 727 |                 }
 728 | 
 729 |                 if (!(msk & 0xBF)) {
 730 |                     return false;
 731 |                 } else {
 732 |                     return true;
 733 |                 }
 734 | 
 735 |             case T_JP:
 736 |                 if (pi1->aux != 0 || pi1->iLhs->type == T_REGREF || !(ps = pi1->iLhs->oPSym)) {
 737 |                     return true;
 738 |                 }
 739 |                 if (!(l3 = ps->p.pInst))
 740 |                     if (strcmp(ps->label, "cret") != 0) {
 741 |                         return true;
 742 |                     } else if (msk & 0x3C) { /* code reused */
 743 |                         return true;
 744 |                     } else {
 745 |                         return false;
 746 |                     }
 747 |                 pi1 = l3;
 748 |                 break;
 749 | 
 750 |             case T_SIMPLE:
 751 |                 switch (pi1->aux) { /* m14: */
 752 |                     case 0:             /* "nop" */
 753 |                     case I_CPL:
 754 |                     case I_SCF:
 755 |                     case I_CCF:
 756 |                     case I_NEG:
 757 |                     case I_HALT:
 758 |                     case I_DI:
 759 |                     case I_EI:
 760 |                         break;
 761 |                     case I_EXX:
 762 |                         while ((pi1 = pi1->pNext) && (pi1->type != T_SIMPLE || pi1->aux != I_EXX))
 763 |                             if (pi1->type != T_LD && pi1->type != T_STK && pi1->type != T_CADD) {
 764 |                                 return false;
 765 |                             }
 766 |                         if (!pi1) {
 767 |                             return false;
 768 |                         }
 769 |                         break;
 770 |                     default:
 771 |                         if (msk & 0x80) {
 772 |                             return true;
 773 |                         }
 774 |                         break;
 775 |                 }
 776 |                 break;
 777 |             case T_TWOBYTE:
 778 |                 if (reg != 17) {
 779 |                     return true;
 780 |                 }
 781 |                 break;
 782 | 
 783 |             case T_3:
 784 |                 if (pi1->aux == I_XOR) /* m22: */
 785 |                     if (pi1->iLhs->type == T_REG && pi1->iLhs->aux == REG_A && reg == REG_A) {
 786 |                         return false;
 787 |                     }
 788 |                 if (msk & 0x80) {
 789 |                     return true;    /* m23: */
 790 |                 }
 791 |                 if (msk & 0x40) {
 792 |                     return false;
 793 |                 }
 794 |                 if (sub_475c(pi1->iLhs, msk)) { /* OPTIMISER[1]: see below */
 795 |                     return true;
 796 |                 }
 797 |                 break;
 798 | 
 799 |             case T_SHIFT:
 800 |                 if ((pi1->aux & 0xFFE7) != 0x20 && (msk & 0x40)) {
 801 |                     return true;
 802 |                 }
 803 | 
 804 |             case T_INCDEC:
 805 |                 if ((msk & 0x40) && (pi1->iLhs->type != T_REG || pi1->iLhs->aux < REG_BC)) {
 806 |                     return false;
 807 |                 }
 808 |                 if (pi1->iLhs->type == T_REG || sub_475c(pi1->iLhs, msk)) {
 809 |                     return true;
 810 |                 }
 811 |                 break;
 812 | 
 813 |             case T_BIT: /* "set", "res", "bit" */
 814 |                 if (pi1->aux == 0x40 && (msk & 0x40)) {
 815 |                     return false;
 816 |                 }
 817 | 
 818 |             case T_0xF: /* 0xF */
 819 |                 if (sub_475c(pi1->iRhs, msk) || sub_475c(pi1->iLhs, msk)) {
 820 |                     return true;
 821 |                 }
 822 |                 break;
 823 | 
 824 |             case T_5:
 825 |                 break;
 826 | 
 827 |             case T_DJNZ:
 828 |                 if (msk & 1) {
 829 |                     return true;
 830 |                 }
 831 |                 break;
 832 | 
 833 |             case T_0xE:
 834 |                 if (sub_475c(pi1->iRhs, msk)) {
 835 |                     return true;
 836 |                 }
 837 |                 if (sub_47a2(pi1->iLhs, msk)) {
 838 |                     return false;
 839 |                 }
 840 |                 break;
 841 | 
 842 |             case T_STK:
 843 |                 if (pi1->aux == I_PUSH && (msk & regTestMasks[pi1->iLhs->aux])) {
 844 |                     return true;
 845 |                 }
 846 |                 if (msk & regTestMasks[pi1->iLhs->aux]) {
 847 |                     return false;
 848 |                 }
 849 |                 break;
 850 | 
 851 |             case T_EX:
 852 |                 if (pi1->iLhs->type == T_REGREF && (msk & regTestMasks[pi1->iRhs->aux])) {
 853 |                     return true;
 854 |                 }
 855 |                 if (msk & 0x3C) {
 856 |                     return true;
 857 |                 }
 858 |                 break;
 859 | 
 860 |             case T_CADD:
 861 |                 if (msk & 0x40) {
 862 |                     return false;
 863 |                 }
 864 | 
 865 |             case T_CARR: /* Add, sub with Carry */
 866 |                 if ((regTestMasks[pi1->iLhs->aux] | 0x40) & msk) {
 867 |                     return true;
 868 |                 }
 869 |                 if (sub_475c(pi1->iRhs, msk)) {
 870 |                     return true;
 871 |                 }
 872 |                 break;
 873 |             case T_LD:
 874 |                 if (!operandsSame(pi1->iLhs, pi1->iRhs))
 875 |                     if (sub_475c(pi1->iRhs, msk)) {
 876 |                         return true;
 877 |                     } else if (sub_47a2(pi1->iLhs, msk)) {
 878 |                         return false;
 879 |                     } else if (sub_475c(pi1->iLhs, msk)) {
 880 |                         return true;
 881 |                     }
 882 |                 break;
 883 | 
 884 |             case 0: /* OPTIMISER[2]: optimised to reuse code in T_JP */
 885 |                 if (msk & 0x3C) {
 886 |                     return true;
 887 |                 } else {
 888 |                     return false;
 889 |                 }
 890 |             case T_JR:
 891 |             case T_RET:
 892 |             case T_RST:
 893 |                 break;
 894 |         }
 895 |         pi1 = pi1->pNext;
 896 |         if (pi2 == pi1) {
 897 |             return false;
 898 |         }
 899 |     } while (n-- != 0);
 900 |     return true;
 901 | }
 902 | 
 903 | /**************************************************************************
 904 |  68 sub_4c33    ok++ (PMO)  Used in: sub_4cf0, sub_4da7
 905 |  **************************************************************************/
 906 | sym_t *allocItem() {
 907 |     register sym_t *ps;
 908 | 
 909 |     ps = (sym_t *)freeItemList; /* check the free list*/
 910 |     if (ps) {                   /* if there is an entry release it*/
 911 |         freeItemList = ((list_t *)ps)->pNext;
 912 |         ps->label    = NULL;
 913 |         ps->p.pInst  = NULL;
 914 |         return ps;
 915 |     }
 916 |     return (sym_t *)alloc_mem(sizeof(sym_t)); /* else allocate a new one */
 917 | }
 918 | 
 919 | /**************************************************************************
 920 |  69 sub_4c6b    ok+
 921 |  **************************************************************************/
 922 | void freeSymbol(register sym_t *ps) {
 923 | 
 924 |     if (strlen(ps->label) >= sizeof(sym_t)) { /* if string could be reused as a symbol at it to the free list*/
 925 |         ((list_t *)(ps->label))->pNext = freeItemList;
 926 |         freeItemList                   = (list_t *)(ps->label);
 927 |     }
 928 |     ((list_t *)ps)->pNext = freeItemList; /* add the symbol to the free list */
 929 |     freeItemList          = (list_t *)ps;
 930 | }
 931 | 
 932 | /**************************************************************************
 933 |  70 hash_index  sub_4cab    ok++    Used in: sub_4cf0
 934 |  **************************************************************************/
 935 | int hash_index(register char const *s, int size) {
 936 |     uint16_t hash;
 937 | 
 938 |     for (hash = 0; *s != 0; ++s) {
 939 |         hash += *(uint8_t *)s + hash;
 940 |     }
 941 |     return hash % size;
 942 | }
 943 | 
 944 | /**************************************************************************
 945 |  71 sub_4cf0    ok++ (PMO)          Used in: get_token
 946 |  **************************************************************************/
 947 | sym_t *lookupSym(register char const *s) {
 948 |     sym_t **pps;
 949 |     sym_t *ps;
 950 | 
 951 |     pps = &hashtab[hash_index(s, HASHSIZE)];
 952 |     while (*pps && strcmp((*pps)->label, s))
 953 |         if (++pps == &hashtab[HASHSIZE]) {
 954 |             pps = hashtab;
 955 |         }
 956 |     if (ps = *pps) {
 957 |         return ps;
 958 |     }
 959 |     *pps = ps = allocItem();
 960 |     ps->label = alloc_mem((int)strlen(s) + 1);
 961 |     strcpy(ps->label, s);
 962 |     return ps;
 963 | }
 964 | 
 965 | /**************************************************************************
 966 |  72 sub_4da7    ok++
 967 |  **************************************************************************/
 968 | sym_t *allocBlankSym() {
 969 |     register sym_t *ps;
 970 | 
 971 |     ps        = allocItem();
 972 |     ps->label = "";
 973 |     return ps;
 974 | }
 975 | 
 976 | /**************************************************************************
 977 |  73 sub_4dbf    ok++            Used in: optimise
 978 |  **************************************************************************/
 979 | void resetHeap() {
 980 |     int *p;
 981 | 
 982 |     if (programBreak == 0) {
 983 |         programBreak = sbrk(0);    /* current base of heap */
 984 |     } else {
 985 |         brk(programBreak);         /* reset the heap */
 986 |     }
 987 |     alloct = allocs = programBreak;
 988 | 
 989 |     for (p = (int *)hashtab; p < (int *)&hashtab[HASHSIZE];) {
 990 |         *p++ = 0;
 991 |     }
 992 |     freeItemList = NULL;
 993 | }
 994 | 
 995 | /**************************************************************************
 996 |  74 sub_4e20    ok++            Used in: optimise
 997 |  **************************************************************************/
 998 | void freeHashtab() {
 999 | 
1000 |     allocs = (char *)&hashtab;
1001 |     alloct = (char *)&hashtab[HASHSIZE];
1002 | }
1003 | 
1004 | /**************************************************************************
1005 |  75 alloc_mem   sub_4e2d    ok++ (PMO)
1006 |  Optimiser differences.
1007 |  1) res instruction is used to clear lsb rather than and 0xfe
1008 |  2) de is loaded before the size calculation. As it is not used before
1009 |     the code does the same thing
1010 |  **************************************************************************/
1011 | void *alloc_mem(int size) {
1012 |     char *p;
1013 |     register char *pi;
1014 | 
1015 |     if ((size = (size + 1) & ~1) + allocs > alloct) {
1016 |         if ((allocs = sbrk(512)) == (char *) -1) {
1017 |             pr_error("Out of memory in %s", name_fun);
1018 |         }
1019 |         alloct = sbrk(0);
1020 |     }
1021 | 
1022 |     pi = allocs;
1023 |     allocs += size;
1024 |     for (p = pi; size-- != 0;) {
1025 |         *p++ = 0;    /* Clearing allocated memory area */
1026 |     }
1027 |     return pi;
1028 | }
1029 | 
1030 | /*
1031 |  * Simple sbrk & brk implementations
1032 |  */
1033 | #ifndef CPM
1034 | 
1035 | //#define MAXHEAP 0xff00
1036 | //static char *heapBase;
1037 | //static char *heapTop;
1038 | 
1039 | void *sbrk(int size) {
1040 | 
1041 |     if (!heapBase && !(heapTop = heapBase = malloc(MAXHEAP))) {
1042 |         fprintf(stderr, "can't allocate heap!!\n");
1043 |     }
1044 |     if (heapTop + size >= heapBase + MAXHEAP) {
1045 |         return (void *) -1;
1046 |     }
1047 |     heapTop += size;
1048 |     return heapTop - size;
1049 | }
1050 | 
1051 | int brk(void *p) {
1052 | 
1053 |     if (heapBase <= (char *)p && (char *)p < heapBase + MAXHEAP) {
1054 |         heapTop = p;
1055 |         return 0;
1056 |     }
1057 |     return -1;
1058 | };
1059 | 
1060 | #endif
1061 | 
1062 | #ifdef _DEBUG
1063 | void heapchk(void const *p) {
1064 | 
1065 |     if (p && (p < (void *)heapBase || p >= (void *)heapTop) &&
1066 |             (p < (void *)hashtab || p >= (void *)&hashtab[HASHSIZE])) {
1067 |         fprintf(stderr, "out of range heap item\n");
1068 |     }
1069 | }
1070 | #endif
1071 | 
1072 | /**************************************************************************
1073 | 
1074 | #######                     ####### ######  #######   ###   #     #
1075 | #        #    #  #####      #     # #     #    #       #    ##   ##
1076 | #        ##   #  #    #     #     # #     #    #       #    # # # #
1077 | #####    # #  #  #    #     #     # ######     #       #    #  #  #
1078 | #        #  # #  #    #     #     # #          #       #    #     #
1079 | #        #   ##  #    #     #     # #          #       #    #     #
1080 | #######  #    #  #####      ####### #          #      ###   #     #
1081 | 
1082 | */
1083 | 
--------------------------------------------------------------------------------