aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2014-05-08 07:04:00 -0700
committerH. Peter Anvin <hpa@zytor.com>2014-05-08 07:04:00 -0700
commitd40c2b25e9ebb5ca6c608025b1880a6278af7d66 (patch)
tree8d4611e688ebe5c3c38e9a0b9aed2e8aa4cb39e4
parentb9e993537698f75deb043eef58880b8f9d8bb9a0 (diff)
downloadabc80-d40c2b25e9ebb5ca6c608025b1880a6278af7d66.tar.gz
abc80-d40c2b25e9ebb5ca6c608025b1880a6278af7d66.tar.xz
abc80-d40c2b25e9ebb5ca6c608025b1880a6278af7d66.zip
z80asm: Upgrade to a new upstream version
Unfortunate the upstream version doesn't handle "-l filename" correctly (needs "-lfilename"). Fix a bug in keyboard.asm the old assembler handled. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--data/Makefile2
-rw-r--r--data/keyboard.asm2
-rw-r--r--tools/z80asm/BUGS3
-rw-r--r--tools/z80asm/COPYING17
-rw-r--r--tools/z80asm/ChangeLog47
-rw-r--r--tools/z80asm/GPL2341
-rw-r--r--tools/z80asm/GPL3674
-rw-r--r--tools/z80asm/Makefile64
-rw-r--r--tools/z80asm/NEWS4
-rw-r--r--tools/z80asm/README100
-rw-r--r--tools/z80asm/VERSION1
-rw-r--r--tools/z80asm/expressions.c755
-rw-r--r--tools/z80asm/gnulib/getopt.c16
-rw-r--r--tools/z80asm/gnulib/getopt.h8
-rw-r--r--tools/z80asm/gnulib/getopt1.c4
-rw-r--r--tools/z80asm/gnulib/gettext.h4
-rw-r--r--tools/z80asm/z80asm.1316
-rw-r--r--tools/z80asm/z80asm.c1494
-rw-r--r--tools/z80asm/z80asm.h247
19 files changed, 2477 insertions, 1622 deletions
diff --git a/data/Makefile b/data/Makefile
index 1631799..aee528d 100644
--- a/data/Makefile
+++ b/data/Makefile
@@ -5,7 +5,7 @@ Z80ASM = ../tools/z80asm/z80asm
.SUFFIXES: .bdf .asm .obj .bin .mif .bas .rom .pl .inc
.asm.bin:
- $(Z80ASM) -o $@ -l $*.lst $<
+ $(Z80ASM) -o$@ -l$*.lst $<
all : keyboard.mif abc80rom.bin basic80.mif \
mmu.mif chargen.mif videoram.mif fgcol.mif sddrom.mif \
diff --git a/data/keyboard.asm b/data/keyboard.asm
index 511e6a4..b2ed356 100644
--- a/data/keyboard.asm
+++ b/data/keyboard.asm
@@ -341,7 +341,7 @@ ktas_strobeok:
ktas_break:
cp (iy+5) ; down_key
- jp nz,(main_loop_clear)
+ jp nz,main_loop_clear
ld a,b ; status_byte
and 0x7F ; strobe
ld (status_byte),a
diff --git a/tools/z80asm/BUGS b/tools/z80asm/BUGS
deleted file mode 100644
index a748101..0000000
--- a/tools/z80asm/BUGS
+++ /dev/null
@@ -1,3 +0,0 @@
-known BUGS in shevek's Z80 assembler:
-- out (c),0
-- shift/rotate (i[xy]+d),[bcdehla]
diff --git a/tools/z80asm/COPYING b/tools/z80asm/COPYING
index be85328..8efd4fb 100644
--- a/tools/z80asm/COPYING
+++ b/tools/z80asm/COPYING
@@ -1,18 +1,19 @@
COPYING - Copyright information for z80asm, the assembler for the z80 by
Bas Wijnen.
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
+This file is part of z80asm.
-This program is distributed in the hope that it will be useful,
+Z80asm is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3 of the License, or
+(at your option) any later version.
+
+Z80asm is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+along with this program. If not, see <http://www.gnu.org/licenses/>.
-Version 2 of the GPL is included in the distribution in a file named GPL2.
+Version 3 of the GPL is included in the distribution in a file named GPL3.
diff --git a/tools/z80asm/ChangeLog b/tools/z80asm/ChangeLog
index 04ea7c1..2e03f96 100644
--- a/tools/z80asm/ChangeLog
+++ b/tools/z80asm/ChangeLog
@@ -1,3 +1,50 @@
+2009-04-11 Bas Wijnen <wijnen@debian.org>
+
+ * z80asm.c: Fixed bug that defw/dw didn't accept more than one
+ argument.
+
+2009-01-18 Bas Wijnen <wijnen@debian.org>
+
+ * expressions.c: Fix incorrect valid declaration of expressions when
+ only the last label is valid. Thanks to Tomaž Šolc for reporting.
+
+2007-09-09 Bas Wijnen <shevek@fmf.nl>
+
+ * z80asm.c: Wrap program counter consistently.
+ * z80asm.c, z80asm.h: Fix error reporting in references.
+ * all files: Update license to GPL version 3 or later.
+ * Makefile: Improve make dist, and make it work with git.
+
+2007-06-14 Bas Wijnen <shevek@fmf.nl>
+
+ * VERSION: Updated to 1.5
+ * z80asm.c, z80asm.h: Fix handling of $ in stored expressions (thanks
+ to Tomaz Solc for reporting and analysing this.
+ * Makefile: Remove executable if tests fail.
+ * tests/pass.asm, tests/pass.correct-bin: Add some tests.
+ * z80asm.c: Make unresolvable references a normal error (instead of an
+ internal assembler problem).
+
+2007-06-05 Bas Wijnen <shevek@fmf.nl>
+
+ * VERSION: Updated to 1.4
+ * z80asm.c: Fix bit/set/res instructions.
+
+2007-05-24 Bas Wijnen <wijnen@debian.org>
+
+ * VERSION: Updated to 1.3.
+ * tests, tests/pass.asm, tests/pass.correct-bin,
+ tests/pass.correct-err, tests/Makefile: Add test suite to spot
+ regressions.
+ * expressions.c, z80asm.h: New files, split from z80asm.c.
+ * Makefile: Updated.
+ * expressions.c, z80asm.c: Warn for value truncation, warn for
+ expressions fully in parenthesis, improve skipword so it doesn't break
+ on comments with parentheses, improve expression parsing so
+ "ld a, (1) + 1" doesn't result in an error.
+ * examples/macro.asm: Fixed to make it usable as a rom.
+ * z80asm.1: Updated.
+
2005-11-30 Jan Wilmans <jw@dds.nl>
* z80asm.c: Added unoffical syntax of ADD A,r as ADD r
diff --git a/tools/z80asm/GPL2 b/tools/z80asm/GPL2
deleted file mode 100644
index a52b16e..0000000
--- a/tools/z80asm/GPL2
+++ /dev/null
@@ -1,341 +0,0 @@
-
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) 19yy <name of author>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) 19yy name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Library General
-Public License instead of this License.
diff --git a/tools/z80asm/GPL3 b/tools/z80asm/GPL3
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/tools/z80asm/GPL3
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/tools/z80asm/Makefile b/tools/z80asm/Makefile
index b022c61..0e01daa 100644
--- a/tools/z80asm/Makefile
+++ b/tools/z80asm/Makefile
@@ -1,54 +1,50 @@
# Makefile for the Z80 assembler by shevek
-# Copyright (C) 2002-2005 Bas Wijnen
+# Copyright 2002-2007 Bas Wijnen
#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
+# This file is part of z80asm.
#
-# This program is distributed in the hope that it will be useful,
+# Z80asm is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# Z80asm is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
-CC = gcc
-LDFLAGS = -O2 -Wall
-CFLAGS = -O2 -Wall -Wwrite-strings -Wcast-qual -Wcast-align \
- -Wstrict-prototypes -Wmissing-prototypes \
- -Wmissing-declarations -Wredundant-decls -Wnested-externs \
- -Winline -Wshadow -g -W -Ignulib
-VERSION ?= $(shell echo -n `cat VERSION | cut -d. -f1`. ; echo $$[`cat VERSION | cut -d. -f2` + 1])
-ifneq (,$(findstring _NT,$(shell uname -s)))
-O = obj
-X = .exe
-else
-O = o
-X =
-endif
+CC = gcc
+CFLAGS = -O2 -Wall -Wwrite-strings -Wcast-qual -Wcast-align -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -pedantic -ansi -Wshadow -ggdb3 -W -Ignulib
+SHELL = /bin/bash
+VERSION ?= $(shell echo -n `cat VERSION | cut -d. -f1`. ; echo $$[`cat VERSION | cut -d. -f2` + 1])
-all: z80asm$(X)
+all:z80asm
-z80asm$(X): z80asm.c Makefile gnulib/getopt.$(O) gnulib/getopt1.$(O)
- $(CC) $(CFLAGS) $(LDFLAGS) -DVERSION=\"$(shell cat VERSION)\" \
- $< gnulib/getopt.$(O) gnulib/getopt1.$(O) -o $@
+z80asm: z80asm.o expressions.o Makefile gnulib/getopt.o gnulib/getopt1.o
+ $(CC) $(LDFLAGS) $(filter %.o,$^) -o $@
+ $(MAKE) -C tests || rm $@
-gnulib/%.$(O): gnulib/%.c gnulib/getopt.h Makefile
- $(CC) $(CFLAGS) -c $< -o $@
+%.o:%.c z80asm.h gnulib/getopt.h Makefile
+ $(CC) $(CFLAGS) -c $< -o $@ -DVERSION=\"$(shell cat VERSION)\"
clean:
for i in . gnulib examples headers ; do \
- rm -f $$i/core $$i/*~ $$i/\#* $$i/*.$(O) $$i/*.rom ; \
+ rm -f $$i/core $$i/*~ $$i/\#* $$i/*.o $$i/*.rom ; \
done
- rm -f z80asm$(X) z80asm.exe
+ rm -f z80asm z80asm.exe
dist: clean
+ ! git status | grep modified
echo $(VERSION) > VERSION
- rm -rf /tmp/z80asm-$(VERSION) /tmp/z80asm
- tar cf - -C .. z80asm | tar xf - -C /tmp
- find /tmp/z80asm -name CVS | xargs rm -rf
- mv /tmp/z80asm /tmp/z80asm-$(VERSION)
+ git add VERSION
+ -git commit -m "Release version $(VERSION)"
+ rm -rf /tmp/z80asm-$(VERSION)
+ git archive --format=tar --prefix=z80asm-$(VERSION)/ HEAD | tar xf - -C /tmp
tar cvzf ../z80asm-$(VERSION).tar.gz -C /tmp z80asm-$(VERSION)
+ rm -r /tmp/z80asm-$(VERSION)
+ cd .. && gpg -b z80asm-$(VERSION).tar.gz
+ scp ../z80asm-$(VERSION).tar.gz* dl.sv.nongnu.org:/releases/z80asm/
+ git push
diff --git a/tools/z80asm/NEWS b/tools/z80asm/NEWS
deleted file mode 100644
index 2fb5ecf..0000000
--- a/tools/z80asm/NEWS
+++ /dev/null
@@ -1,4 +0,0 @@
-List files now include the output in hex.
-defb/db accepts quoted strings in double quotes.
-
-See README for a (hopefully complete) list of features
diff --git a/tools/z80asm/README b/tools/z80asm/README
deleted file mode 100644
index d1570e5..0000000
--- a/tools/z80asm/README
+++ /dev/null
@@ -1,100 +0,0 @@
-README for shevek's Z80 assembler
-
-See INSTALL for installation instructions
-
-The assembler works like gcc. You need an external editor to create your
-source file. Then you assemble it to a z80 binary with this assembler.
-
-By default, the assembler uses stdin as its only input file and stdout as
-its output file. Any arguments with no flags are taken as input files.
-If more than one input file is specified, the files are concatenated.
-The following flags are supported:
-
--h --help give a help text
-
--V --version give version information
-
--v --verbose be verbose. specify more than once to be more verbose.
- If you want verbosity about parsing the commandline,
- then this should be the the first argument.
-
--l --list file specify file to write out the input, with lines on
- which files are read and every source line prefixed
- with the address. (list file)
-
--L --label file specify file to write all labels to, in assembler
- readable format (human readable as well). Every line is
- of the form:
- label: equ value
- so it can be included in source.
-
--i --input file specify an input file.
-
--o --output file specify the output file.
-
-Some notes on the assembler directives and mnemonics:
-All text is case insensitive, except when quoted.
-Undocumented opcodes are as much as possible supported. There are some errors
-in the implementation, that are being worked on (see BUGS). Names for
-undocumented opcodes are:
-sll and sli are equal and can both be used.
-ixh, ixl, iyh and iyl can be used.
-
-Assembler directives are:
-defb and db arg,arg,arg,...
-defw and dw arg,arg,arg,...
-defs and ds count,value=0
-org address
-if expression
-else
-else
-...
-endif
-include 'file'
- Note: the quotes around the file for include are
- mandatory, but you can choose the quotes yourself.
- eg, you may use % or even a letter as a quote.
- The filename does not undergo any expansion, so
- \, ~, $, etc are passed as written (which means ~
- will not be your home directory.)
-
-defb/db can also take strings, when enclosed in double quotes:
-defb "This text should be in a buffer", 0
-
-All expressions can use the following operators, in order of precedence:
-(a, b and c denote subexpressions)
-a?b:c If a is not zero, return b, otherwise c
-a|b bitwise or
-a^b bitwise xor
-a&b bitwise and
-a==b a!=b equality
-a<=b a>=b a<b a>b inequality
-a<<b a>>b shift
-a+b a-b addition and subtraction
-a*b a/b a%b multiplication, division and modulo
-~a +a -a bitwise not, no effect and negation
-(a) parenthesis
-
-Literals in expressions may be written as: (case does not matter)
-14, 14d decimal number
-016, 16o, 16q octal number
-0xE, 0Eh hexadecimal number (first character must be 0-9)
-%1110, 1110b binary number
-@c11 base 13 number (specified by 'c' so c+1 == 10)
-'s' ASCII code of 's'
-$ address of first byte of current command
-
-In all expressions, labels may be used. However, there are some expressions
-where the value must be computable at once, and therefore only previously
-defined labels may be used. This is the case for:
-- The argument of org
-- The argument of equ (eg, a label definition)
-- The first argument of ds
-- The argument of if
-In all other expression, labels which are defined later may be used.
-
-Warning: parts that are not compiled because of an if statement are only
-checked to have a correct command. The argument is not parsed. This means
-that if the file passes through the assembler with no warnings or errors, it
-may still not assemble correctly in a different setting (where the if's
-give different results).
diff --git a/tools/z80asm/VERSION b/tools/z80asm/VERSION
new file mode 100644
index 0000000..6259340
--- /dev/null
+++ b/tools/z80asm/VERSION
@@ -0,0 +1 @@
+1.8
diff --git a/tools/z80asm/expressions.c b/tools/z80asm/expressions.c
new file mode 100644
index 0000000..dbaea1c
--- /dev/null
+++ b/tools/z80asm/expressions.c
@@ -0,0 +1,755 @@
+/* Z80 assembler by shevek
+
+ Copyright (C) 2002-2009 Bas Wijnen <wijnen@debian.org>
+ Copyright (C) 2005 Jan Wilmans <jw@dds.nl>
+
+ This file is part of z80asm.
+
+ Z80asm is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ Z80asm is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "z80asm.h"
+
+/* reading expressions. The following operators are supported
+ * in order of precedence, with function name:
+ * expr?expr:expr do_rd_expr
+ * | rd_expr_or
+ * ^ rd_expr_xor
+ * & rd_expr_and
+ * == != rd_expr_equal
+ * >= <= > < rd_expr_unequal
+ * << >> rd_expr_shift
+ * + - (binary) rd_term
+ * * / % rd_factor
+ * ~ + - (unary) rd_factor
+ */
+
+static int do_rd_expr (const char **p, char delimiter, int *valid, int level,
+ int *check, int print_errors);
+
+static int
+rd_number (const char **p, const char **endp, int base)
+{
+ int result = 0, i;
+ char *c, num[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+ if (verbose >= 6)
+ fprintf (stderr, "%5d (0x%04x): Starting to read number of base %d"
+ "(string=%s).\n", stack[sp].line, addr, base, *p);
+ num[base] = '\0';
+ *p = delspc (*p);
+ while (**p && (c = strchr (num, tolower (**p))))
+ {
+ i = c - num;
+ if (verbose >= 7)
+ fprintf (stderr, "%5d (0x%04x): Digit found:%1x.\n", stack[sp].line,
+ addr, i);
+ result = result * base + i;
+ (*p)++;
+ }
+ if (endp)
+ *endp = *p;
+ *p = delspc (*p);
+ if (verbose >= 7)
+ fprintf (stderr, "%5d (0x%04x): rd_number returned %d (%04x).\n",
+ stack[sp].line, addr, result, result);
+ return result;
+}
+
+static int
+rd_otherbasenumber (const char **p, int *valid, int print_errors)
+{
+ char c;
+ if (verbose >= 6)
+ fprintf (stderr,
+ "%5d (0x%04x): Starting to read basenumber (string=%s).\n",
+ stack[sp].line, addr, *p);
+ (*p)++;
+ if (!**p)
+ {
+ if (valid)
+ *valid = 0;
+ else if (print_errors)
+ printerr (1, "unexpected end of line after `@'\n");
+ return 0;
+ }
+ if (**p == '0' || !isalnum (**p))
+ {
+ if (valid)
+ *valid = 0;
+ else if (print_errors)
+ printerr (1, "base must be between 1 and z\n");
+ return 0;
+ }
+ c = **p;
+ (*p)++;
+ if (isalpha (**p))
+ return rd_number (p, NULL, tolower (c) - 'a' + 1);
+ return rd_number (p, NULL, c - '0' + 1);
+}
+
+int
+rd_character (const char **p, int *valid, int print_errors)
+{
+ int i;
+ if (verbose >= 6)
+ fprintf (stderr,
+ "%5d (0x%04x): Starting to read character (string=%s).\n",
+ stack[sp].line, addr, *p);
+ i = **p;
+ if (!i)
+ {
+ if (valid)
+ *valid = 0;
+ else if (print_errors)
+ printerr (1, "unexpected end of line in string constant\n");
+ return 0;
+ }
+ if (i == '\\')
+ {
+ (*p)++;
+ if (**p >= '0' && **p <= '7')
+ {
+ int b, num_digits;
+ i = 0;
+ if ((*p)[1] >= '0' && (*p)[1] <= '7')
+ {
+ if (**p <= '3' && (*p)[2] >= '0' && (*p)[2] <= '7')
+ num_digits = 3;
+ else
+ num_digits = 2;
+ }
+ else
+ num_digits = 1;
+ for (b = 0; b < num_digits; ++b)
+ {
+ int bit = (*p)[num_digits - 1 - b] - '0';
+ i += (1 << (b * 3)) * bit;
+ }
+ *p += num_digits;
+ }
+ else
+ {
+ switch (**p)
+ {
+ case 'n':
+ i = 10;
+ break;
+ case 'r':
+ i = 13;
+ break;
+ case 't':
+ i = 9;
+ break;
+ case 'a':
+ i = 7;
+ break;
+ case '\'':
+ if (valid)
+ *valid = 0;
+ else if (print_errors)
+ printerr (1, "empty literal character\n");
+ return 0;
+ case 0:
+ if (valid)
+ *valid = 0;
+ else if (print_errors)
+ printerr (1, "unexpected end of line after "
+ "backslash in string constant\n");
+ return 0;
+ default:
+ i = **p;
+ }
+ (*p)++;
+ }
+ }
+ else
+ (*p)++;
+ if (verbose >= 7)
+ fprintf (stderr, "%5d (0x%04x): rd_character returned %d (%c).\n",
+ stack[sp].line, addr, i, i);
+ return i;
+}
+
+static int
+check_label (struct label *labels, const char **p, struct label **ret,
+ struct label **previous, int force_skip)
+{
+ struct label *l;
+ const char *c;
+ unsigned s2;
+ *p = delspc (*p);
+ for (c = *p; isalnum (*c) || *c == '_' || *c == '.'; ++c)
+ {
+ }
+ s2 = c - *p;
+ for (l = labels; l; l = l->next)
+ {
+ unsigned s1, s;
+ int cmp;
+ s1 = strlen (l->name);
+ s = s1 < s2 ? s1 : s2;
+ cmp = strncmp (l->name, *p, s);
+ if (cmp > 0 || (cmp == 0 && s1 > s))
+ {
+ if (force_skip)
+ *p = c;
+ return 0;
+ }
+ if (cmp < 0 || s2 > s)
+ {
+ if (previous)
+ *previous = l;
+ continue;
+ }
+ *p = c;
+ /* if label is not valid, compute it */
+ if (l->ref)
+ {
+ compute_ref (l->ref, 1);
+ if (!l->ref->done)
+ {
+ /* label was not valid, and isn't computable. tell the
+ * caller that it doesn't exist, so it will try again later.
+ * Set ret to show actual existence. */
+ if (verbose >= 6)
+ fprintf (stderr,
+ "%5d (0x%04x): returning invalid label %s.\n",
+ stack[sp].line, addr, l->name);
+ *ret = l;
+ return 0;
+ }
+ }
+ *ret = l;
+ return 1;
+ }
+ if (force_skip)
+ *p = c;
+ return 0;
+}
+
+int
+rd_label (const char **p, int *exists, struct label **previous, int level,
+ int print_errors)
+{
+ struct label *l = NULL;
+ int s;
+ if (exists)
+ *exists = 0;
+ if (previous)
+ *previous = NULL;
+ if (verbose >= 6)
+ fprintf (stderr, "%5d (0x%04x): Starting to read label (string=%s).\n",
+ stack[sp].line, addr, *p);
+ for (s = level; s >= 0; --s)
+ {
+ if (check_label (stack[s].labels, p, &l,
+ (**p == '.' && s == sp) ? previous : NULL, 0))
+ break;
+ }
+ if (s < 0)
+ {
+ /* not yet found */
+ const char *old_p = *p;
+ if (!check_label (firstlabel, p, &l, **p != '.' ? previous : NULL, 1))
+ {
+ /* label does not exist, or is invalid. This is an error if there
+ * is no existance check. */
+ if (!exists && print_errors)
+ printerr (1, "using undefined label %.*s\n", *p - old_p, old_p);
+ /* Return a value to discriminate between non-existing and invalid */
+ if (verbose >= 7)
+ fprintf (stderr, "rd_label returns invalid value\n");
+ return l != NULL;
+ }
+ }
+ if (exists)
+ *exists = 1;
+ if (verbose >= 7)
+ fprintf (stderr, "rd_label returns valid value 0x%x\n", l->value);
+ return l->value;
+}
+
+static int
+rd_value (const char **p, int *valid, int level, int *check, int print_errors)
+{
+ int sign = 1, not = 0, base, v;
+ const char *p0, *p1, *p2;
+ if (verbose >= 6)
+ fprintf (stderr, "%5d (0x%04x): Starting to read value (string=%s).\n",
+ stack[sp].line, addr, *p);
+ *p = delspc (*p);
+ while (**p && strchr ("+-~", **p))
+ {
+ if (**p == '-')
+ sign = -sign;
+ else if (**p == '~')
+ not = ~not;
+ (*p)++;
+ *p = delspc (*p);
+ }
+ base = 10; /* Default base for suffixless numbers */
+
+ /* Check for parenthesis around full expression: not if no parenthesis */
+ if (**p != '(')
+ *check = 0;
+
+ switch (**p)
+ {
+ int exist, retval;
+ char quote;
+ int dummy_check;
+ case '(':
+ (*p)++;
+ dummy_check = 0;
+ retval = not ^ (sign * do_rd_expr (p, ')', valid, level, &dummy_check,
+ print_errors));
+ ++*p;
+ return retval;
+ case '0':
+ if ((*p)[1] == 'x')
+ {
+ (*p) += 2;
+ return not ^ (sign * rd_number (p, NULL, 0x10));
+ }
+ base = 8; /* If first digit it 0, assume octal unless suffix */
+ /* fall through */
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ p0 = *p;
+ rd_number (p, &p1, 36); /* Advance to end of numeric string */
+ p1--; /* Last character in numeric string */
+ switch (*p1)
+ {
+ case 'h':
+ case 'H':
+ base = 16;
+ break;
+ case 'b':
+ case 'B':
+ base = 2;
+ break;
+ case 'o':
+ case 'O':
+ case 'q':
+ case 'Q':
+ base = 8;
+ break;
+ case 'd':
+ case 'D':
+ base = 10;
+ break;
+ default: /* No suffix */
+ p1++;
+ break;
+ }
+ v = rd_number (&p0, &p2, base);
+ if (p1 != p2)
+ {
+ if (valid)
+ *valid = 0;
+ else if (print_errors)
+ printerr (1, "invalid character in number: \'%c\'\n", *p2);
+ }
+ return not ^ (sign * v);
+ case '$':
+ ++*p;
+ *p = delspc (*p);
+ p0 = *p;
+ v = rd_number (&p0, &p2, 0x10);
+ if (p2 == *p)
+ {
+ v = baseaddr;
+ }
+ else
+ *p = p2;
+ return not ^ (sign * v);
+ case '%':
+ (*p)++;
+ return not ^ (sign * rd_number (p, NULL, 2));
+ case '\'':
+ case '"':
+ quote = **p;
+ ++*p;
+ retval = not ^ (sign * rd_character (p, valid, print_errors));
+ if (**p != quote)
+ {
+ if (valid)
+ *valid = 0;
+ else if (print_errors)
+ printerr (1, "missing closing quote (%c)\n", quote);
+ return 0;
+ }
+ ++*p;
+ return retval;
+ case '@':
+ return not ^ (sign * rd_otherbasenumber (p, valid, print_errors));
+ case '?':
+ rd_label (p, &exist, NULL, level, 0);
+ return not ^ (sign * exist);
+ case '&':
+ {
+ ++*p;
+ switch (**p)
+ {
+ case 'h':
+ case 'H':
+ base = 0x10;
+ break;
+ case 'o':
+ case 'O':
+ base = 010;
+ break;
+ case 'b':
+ case 'B':
+ base = 2;
+ break;
+ default:
+ if (valid)
+ *valid = 0;
+ else if (print_errors)
+ printerr (1, "invalid literal starting with &%c\n", **p);
+ return 0;
+ }
+ ++*p;
+ return not ^ (sign * rd_number (p, NULL, base));
+ }
+ default:
+ {
+ int value;
+ exist = 1;
+ value = rd_label (p, valid ? &exist : NULL, NULL, level, print_errors);
+ if (!exist)
+ *valid = 0;
+ return not ^ (sign * value);
+ }
+ }
+}
+
+static int
+rd_factor (const char **p, int *valid, int level, int *check, int print_errors)
+{
+ /* read a factor of an expression */
+ int result;
+ if (verbose >= 6)
+ fprintf (stderr, "%5d (0x%04x): Starting to read factor (string=%s).\n",
+ stack[sp].line, addr, *p);
+ result = rd_value (p, valid, level, check, print_errors);
+ *p = delspc (*p);
+ while (**p == '*' || **p == '/')
+ {
+ *check = 0;
+ if (**p == '*')
+ {
+ (*p)++;
+ result *= rd_value (p, valid, level, check, print_errors);
+ }
+ else if (**p == '/')
+ {
+ (*p)++;
+ result /= rd_value (p, valid, level, check, print_errors);
+ }
+ *p = delspc (*p);
+ }
+ if (verbose >= 7)
+ fprintf (stderr, "%5d (0x%04x): rd_factor returned %d (%04x).\n",
+ stack[sp].line, addr, result, result);
+ return result;
+}
+
+static int
+rd_term (const char **p, int *valid, int level, int *check, int print_errors)
+{
+ /* read a term of an expression */
+ int result;
+ if (verbose >= 6)
+ fprintf (stderr, "%5d (0x%04x): Starting to read term (string=%s).\n",
+ stack[sp].line, addr, *p);
+ result = rd_factor (p, valid, level, check, print_errors);
+ *p = delspc (*p);
+ while (**p == '+' || **p == '-')
+ {
+ *check = 0;
+ if (**p == '+')
+ {
+ (*p)++;
+ result += rd_factor (p, valid, level, check, print_errors);
+ }
+ else if (**p == '-')
+ {
+ (*p)++;
+ result -= rd_factor (p, valid, level, check, print_errors);
+ }
+ *p = delspc (*p);
+ }
+ if (verbose >= 7)
+ fprintf (stderr, "%5d (0x%04x): rd_term returned %d (%04x).\n",
+ stack[sp].line, addr, result, result);
+ return result;
+}
+
+static int
+rd_expr_shift (const char **p, int *valid, int level, int *check,
+ int print_errors)
+{
+ int result;
+ if (verbose >= 6)
+ fprintf (stderr, "%5d (0x%04x): Starting to read shift expression "
+ "(string=%s).\n", stack[sp].line, addr, *p);
+ result = rd_term (p, valid, level, check, print_errors);
+ *p = delspc (*p);
+ while ((**p == '<' || **p == '>') && (*p)[1] == **p)
+ {
+ *check = 0;
+ if (**p == '<')
+ {
+ (*p) += 2;
+ result <<= rd_term (p, valid, level, check, print_errors);
+ }
+ else if (**p == '>')
+ {
+ (*p) += 2;
+ result >>= rd_term (p, valid, level, check, print_errors);
+ }
+ *p = delspc (*p);
+ }
+ if (verbose >= 7)
+ fprintf (stderr, "%5d (0x%04x): rd_shift returned %d (%04x).\n",
+ stack[sp].line, addr, result, result);
+ return result;
+}
+
+static int
+rd_expr_unequal (const char **p, int *valid, int level, int *check,
+ int print_errors)
+{
+ int result;
+ if (verbose >= 6)
+ fprintf (stderr, "%5d (0x%04x): Starting to read "
+ "unequality expression (string=%s).\n", stack[sp].line, addr,
+ *p);
+ result = rd_expr_shift (p, valid, level, check, print_errors);
+ *p = delspc (*p);
+ if (**p == '<' && (*p)[1] == '=')
+ {
+ *check = 0;
+ (*p) += 2;
+ return result <= rd_expr_unequal (p, valid, level, check, print_errors);
+ }
+ else if (**p == '>' && (*p)[1] == '=')
+ {
+ *check = 0;
+ (*p) += 2;
+ return result >= rd_expr_unequal (p, valid, level, check, print_errors);
+ }
+ if (**p == '<' && (*p)[1] != '<')
+ {
+ *check = 0;
+ (*p)++;
+ return result < rd_expr_unequal (p, valid, level, check, print_errors);
+ }
+ else if (**p == '>' && (*p)[1] != '>')
+ {
+ *check = 0;
+ (*p)++;
+ return result > rd_expr_unequal (p, valid, level, check, print_errors);
+ }
+ if (verbose >= 7)
+ fprintf (stderr, "%5d (0x%04x): rd_shift returned %d (%04x).\n",
+ stack[sp].line, addr, result, result);
+ return result;
+}
+
+static int
+rd_expr_equal (const char **p, int *valid, int level, int *check,
+ int print_errors)
+{
+ int result;
+ if (verbose >= 6)
+ fprintf (stderr, "%5d (0x%04x): Starting to read equality epression "
+ "(string=%s).\n", stack[sp].line, addr, *p);
+ result = rd_expr_unequal (p, valid, level, check, print_errors);
+ *p = delspc (*p);
+ if (**p == '=')
+ {
+ *check = 0;
+ ++*p;
+ if (**p == '=')
+ ++ * p;
+ return result == rd_expr_equal (p, valid, level, check, print_errors);
+ }
+ else if (**p == '!' && (*p)[1] == '=')
+ {
+ *check = 0;
+ (*p) += 2;
+ return result != rd_expr_equal (p, valid, level, check, print_errors);
+ }
+ if (verbose >= 7)
+ fprintf (stderr, "%5d (0x%04x): rd_equal returned %d (%04x).\n",
+ stack[sp].line, addr, result, result);
+ return result;
+}
+
+static int
+rd_expr_and (const char **p, int *valid, int level, int *check,
+ int print_errors)
+{
+ int result;
+ if (verbose >= 6)
+ fprintf (stderr, "%5d (0x%04x): Starting to read and expression "
+ "(string=%s).\n", stack[sp].line, addr, *p);
+ result = rd_expr_equal (p, valid, level, check, print_errors);
+ *p = delspc (*p);
+ if (**p == '&')
+ {
+ *check = 0;
+ (*p)++;
+ result &= rd_expr_and (p, valid, level, check, print_errors);
+ }
+ if (verbose >= 7)
+ fprintf (stderr, "%5d (0x%04x): rd_expr_and returned %d (%04x).\n",
+ stack[sp].line, addr, result, result);
+ return result;
+}
+
+static int
+rd_expr_xor (const char **p, int *valid, int level, int *check,
+ int print_errors)
+{
+ int result;
+ if (verbose >= 6)
+ fprintf (stderr, "%5d (0x%04x): Starting to read xor expression "
+ "(string=%s).\n", stack[sp].line, addr, *p);
+ result = rd_expr_and (p, valid, level, check, print_errors);
+ if (verbose >= 7)
+ fprintf (stderr, "%5d (0x%04x): rd_expr_xor: rd_expr_and returned %d "
+ "(%04x).\n", stack[sp].line, addr, result, result);
+ *p = delspc (*p);
+ if (**p == '^')
+ {
+ *check = 0;
+ (*p)++;
+ result ^= rd_expr_xor (p, valid, level, check, print_errors);
+ }
+ if (verbose >= 7)
+ fprintf (stderr, "%5d (0x%04x): rd_expr_xor returned %d (%04x).\n",
+ stack[sp].line, addr, result, result);
+ return result;
+}
+
+static int
+rd_expr_or (const char **p, int *valid, int level, int *check,
+ int print_errors)
+{
+ int result;
+ if (verbose >= 6)
+ fprintf (stderr, "%5d (0x%04x): Starting to read or expression "
+ "(string=%s).\n", stack[sp].line, addr, *p);
+ result = rd_expr_xor (p, valid, level, check, print_errors);
+ if (verbose >= 7)
+ fprintf (stderr, "%5d (0x%04x): rd_expr_or: rd_expr_xor returned %d "
+ "(%04x).\n", stack[sp].line, addr, result, result);
+ *p = delspc (*p);
+ if (**p == '|')
+ {
+ *check = 0;
+ (*p)++;
+ result |= rd_expr_or (p, valid, level, check, print_errors);
+ }
+ if (verbose >= 7)
+ fprintf (stderr, "%5d (0x%04x): rd_expr_or returned %d (%04x).\n",
+ stack[sp].line, addr, result, result);
+ return result;
+}
+
+static int
+do_rd_expr (const char **p, char delimiter, int *valid, int level, int *check,
+ int print_errors)
+{
+ /* read an expression. delimiter can _not_ be '?' */
+ int result = 0;
+ if (verbose >= 6)
+ fprintf (stderr,
+ "%5d (0x%04x): Starting to read expression "
+ "(string=%s, delimiter=%c).\n", stack[sp].line, addr, *p,
+ delimiter ? delimiter : ' ');
+ *p = delspc (*p);
+ if (!**p || **p == delimiter)
+ {
+ if (valid)
+ *valid = 0;
+ else if (print_errors)
+ printerr (1, "expression expected (not %s)\n", *p);
+ return 0;
+ }
+ result = rd_expr_or (p, valid, level, check, print_errors);
+ *p = delspc (*p);
+ if (**p == '?')
+ {
+ *check = 0;
+ (*p)++;
+ if (result)
+ {
+ result = do_rd_expr (p, ':', valid, level, check, print_errors);
+ if (**p)
+ (*p)++;
+ do_rd_expr (p, delimiter, valid, level, check, print_errors);
+ }
+ else
+ {
+ do_rd_expr (p, ':', valid, level, check, print_errors);
+ if (**p)
+ (*p)++;
+ result = do_rd_expr (p, delimiter, valid, level, check,
+ print_errors);
+ }
+ }
+ *p = delspc (*p);
+ if (**p && **p != delimiter)
+ {
+ if (valid)
+ *valid = 0;
+ else if (print_errors)
+ printerr (1, "junk at end of expression: %s\n", *p);
+ }
+ if (verbose >= 7)
+ {
+ fprintf (stderr, "%5d (0x%04x): rd_expr returned %d (%04x).\n",
+ stack[sp].line, addr, result, result);
+ if (valid && !*valid)
+ fprintf (stderr, "%5d (0x%04x): Returning invalid result.\n",
+ stack[sp].line, addr);
+ }
+ return result;
+}
+
+int
+rd_expr (const char **p, char delimiter, int *valid, int level,
+ int print_errors)
+{
+ int check = 1;
+ int result;
+ if (valid)
+ *valid = 1;
+ result = do_rd_expr (p, delimiter, valid, level, &check, print_errors);
+ if (print_errors && (!valid || *valid) && check)
+ printerr (0, "expression fully enclosed in parenthesis\n");
+ return result;
+}
diff --git a/tools/z80asm/gnulib/getopt.c b/tools/z80asm/gnulib/getopt.c
index 1347f14..a229b4d 100644
--- a/tools/z80asm/gnulib/getopt.c
+++ b/tools/z80asm/gnulib/getopt.c
@@ -20,8 +20,8 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
Ditto for AIX 3.2 and <stdlib.h>. */
@@ -34,7 +34,6 @@
#endif
#include <stdio.h>
-#include <stdlib.h>
/* Comment out all this code if we are using the GNU C Library, and are not
actually compiling the library itself. This code is part of the GNU C
@@ -188,6 +187,17 @@ static enum
/* Value of POSIXLY_CORRECT environment variable. */
static char *posixly_correct;
+#ifndef __GNU_LIBRARY__
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+#ifndef getenv
+extern char *getenv ();
+#endif
+
+#endif /* not __GNU_LIBRARY__ */
+
/* Handle permutation of arguments. */
/* Describe the part of ARGV that contains non-options that have
diff --git a/tools/z80asm/gnulib/getopt.h b/tools/z80asm/gnulib/getopt.h
index d75535b..7f5eaba 100644
--- a/tools/z80asm/gnulib/getopt.h
+++ b/tools/z80asm/gnulib/getopt.h
@@ -16,8 +16,8 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
#ifndef _GETOPT_H
@@ -135,10 +135,14 @@ struct option
arguments to the option '\0'. This behavior is specific to the GNU
`getopt'. */
+#ifdef __GNU_LIBRARY__
/* Many other libraries have conflicting prototypes for getopt, with
differences in the consts, in stdlib.h. To avoid compilation
errors, only prototype getopt for the GNU C library. */
extern int getopt (int ___argc, char *const *___argv, const char *__shortopts);
+#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+#endif /* __GNU_LIBRARY__ */
#ifndef __need_getopt
extern int getopt_long (int ___argc, char *const *___argv,
diff --git a/tools/z80asm/gnulib/getopt1.c b/tools/z80asm/gnulib/getopt1.c
index 3288c72..b488a1a 100644
--- a/tools/z80asm/gnulib/getopt1.c
+++ b/tools/z80asm/gnulib/getopt1.c
@@ -16,8 +16,8 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
#ifdef HAVE_CONFIG_H
#include <config.h>
diff --git a/tools/z80asm/gnulib/gettext.h b/tools/z80asm/gnulib/gettext.h
index 835732e..6130961 100644
--- a/tools/z80asm/gnulib/gettext.h
+++ b/tools/z80asm/gnulib/gettext.h
@@ -12,8 +12,8 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
#ifndef _LIBGETTEXT_H
#define _LIBGETTEXT_H 1
diff --git a/tools/z80asm/z80asm.1 b/tools/z80asm/z80asm.1
new file mode 100644
index 0000000..c87ccc4
--- /dev/null
+++ b/tools/z80asm/z80asm.1
@@ -0,0 +1,316 @@
+.\" Hey, EMACS: -*- nroff -*-
+.\" z80asm.1 - manual page
+.\" Copyright 2005-2007 Bas Wijnen <wijnen@debian.org>
+.\" This file is part of z80asm.
+.\"
+.\" Z80asm is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 3 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" Z80asm is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+.\" First parameter, NAME, should be all caps
+.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
+.\" other parameters are allowed: see man(7), man(1)
+.TH Z80ASM 1 "May 10, 2005"
+.\" Please adjust this date whenever revising the manpage.
+.\"
+.\" Some roff macros, for reference:
+.\" .nh disable hyphenation
+.\" .hy enable hyphenation
+.\" .ad l left justify
+.\" .ad b justify to both left and right margins
+.\" .nf disable filling
+.\" .fi enable filling
+.\" .br insert line break
+.\" .sp <n> insert n+1 empty lines
+.\" for manpage-specific macros, see man(7)
+.SH NAME
+z80asm \- assembler for the Z80 microprocessor
+.SH SYNOPSIS
+.B z80asm
+.RI [ options ] " " [ "files..." ]
+.SH DESCRIPTION
+Z80asm is an assembler for Z80 assembly.
+If no input files are specified, stdin is used. If no output file is
+specified, "a.bin" is used. If "-" is specified as output file, stdout is
+used. This makes it possible to use the assembler in a pipeline.
+.PP
+When multiple input files are specified, the assembler first uses all files
+which were specified with \-i or \-\-input, in the order given. After that, all
+files which were specified as non\-option arguments are assembled, also in the
+order given.
+.SH OPTIONS
+.TP
+.B \-h, \-\-help
+Show summary of options and exit.
+.TP
+.B \-V, \-\-version
+Display version information and exit.
+.TP
+.B \-v, \-\-verbose
+Be verbose. Specify multiple times to be more verbose. Messages are sent to
+standard error.
+.TP
+.BR "\-l, \-\-list" [=filename]
+Write a list file. No filename or '-' means stderr.
+.TP
+.BR "\-L, \-\-label" [=filename]
+Write a label file. No filename or '-' means stderr.
+.TP
+.BR "\-p, \-\-label\-prefix" =prefix
+prefix all labels with this prefix.
+.TP
+.BR "\-i, \-\-input" =filename
+Specify an input file (\-i may be omitted). '-' means stdin.
+.TP
+.BR "\-o, \-\-output" =filename
+Specify the output file. '-' or completely omitting the option means stdout.
+.TP
+.BR "\-I, \-\-includepath" =dirname
+Add a directory to the include path. The order in which the directories are
+tried is from back to front: the last directory specified has the highest
+priority. "/usr/share/z80asm" is always in the include path (with lowest
+priority), you don't have to specify it.
+.TP
+.B \-f, \-\-force
+Produce output even in case of errors. Normally the output, list and label
+files are removed when assembly is unsuccesful.
+
+.SH ASSEMBLER DIRECTIVES
+All mnemonics and registers are case insensitive. All other text (in
+particular, labels and macros) are not.
+Undocumented opcodes are as much as possible supported:
+.TP
+sll and sli are equal and can both be used.
+.TP
+ixh, ixl, iyh and iyl can be used.
+.PP
+Assembler directives are:
+.TP
+.BR incbin " 'filename'"
+Include a binary file into the resulting assembled file. This can be used to
+include text files, or images, sound files, etc. The filename is searched for
+in the current directory, and then in the include path, just like for include.
+Also like for include, the quotes can be any character (but must match) and
+no substitution is performed (so ~ is not your home directory).
+.TP
+.BR defb " or " db " arg, arg, arg, ..."
+Define bytes.
+.TP
+.BR defm " or " dm " " "" """String""" "" ", 'String'"
+Define message. Each character in the string is stored as one byte. Backslash
+escapes are allowed, as in characters in expressions. Unlike the argument for
+include, the quotes must really be quotes (but they can be single or double
+quotes. The closing quote must match the opening quote.)
+.PP
+defb/db and defm/dm are really aliases; either can take both
+quoted strings and numbers:
+.br
+defb "This text should be in a buffer\\r\\n", 0
+.TP
+.BR defs " or " ds " count [, value]"
+Define space. count bytes are reserved. Each of them is initialised to the
+specified value, or 0 if no value is specified.
+.TP
+.BR defw " or " dw " arg, arg, arg, ..."
+Define words. Each argument is stored as two bytes, the low order byte first.
+.TP
+.B end
+End assembly of this source file. Any remaining lines are copied into the list
+file (if present), but not assembled.
+.TP
+.RB "label: " equ " expression"
+Define label to have value expression.
+.PP
+.BR if " expression"
+.br
+code block 1
+.br
+.B else
+.br
+code block 2
+.br
+.B else
+.br
+code block 3
+.br
+.B ...
+.br
+code block n
+.br
+.B endif
+.RS
+Conditionally assemble code. If expression is not 0, all odd code blocks are
+assembled, if expression is 0, all even blocks are assembled. Usually only
+one or two code blocks are present.
+.RE
+.TP
+.BR include " 'file'"
+Include file into the source. The quotes around the file for include are
+mandatory, but you can choose the quotes yourself. eg, you may use % or even
+a letter as a quote. The filename does not undergo any expansion, so \\, ~,
+$, etc are passed as written (which means ~ will not be your home directory.)
+The filename is used as specified, and then prefixed with each directory in the include path, until it can be opened.
+.PP
+.RB "label: " macro " arg1, arg2, ..."
+.br
+code block
+.br
+.B endif
+.RS
+Define a macro. The macro can be used where an opcode is expected. The code
+block is then substituted, with the given values for the arguments. This is
+a textual substitution, so the following example is valid:
+.RE
+makelabel name
+.br
+label_name:
+.br
+endm
+.RS
+This will generate a label with a constructed name (it's not a very useful
+example, but it shows the possiblities).
+.RE
+.TP
+.BR org " address"
+Set the "program counter" to address. This does not add any bytes to the
+resulting binary, it only determines how the rest of the code is interpreted
+(in particular, the value of labels and
+.BR $ ).
+.TP
+.BR seek " offset"
+Seek to position offset in the output file. This can be used for overwiting
+previously assembled code, for example for patching a binary which was included
+using
+.BR incbin .
+
+.SH EXPRESSIONS
+All expressions can use the following operators, in order of precedence:
+.RB ( a ", " b " and " c " denote subexpressions)"
+.TP
+.B a ? b : c
+If a is not zero, return b, otherwise c
+.TP
+.B a | b
+bitwise or
+.TP
+.B a ^ b
+bitwise xor
+.TP
+.B a & b
+bitwise and
+.TP
+.B a == b, a = b, a != b
+equality
+.TP
+.B a <= b, a >= b, a < b, a > b
+inequality
+.TP
+.B a << b, a >> b
+bit shift
+.TP
+.B a + b, a \- b
+addition and subtraction
+.TP
+.B a * b, a / b, a % b
+multiplication, division and modulo
+.TP
+.B ~a, +a, \-a
+bitwise not, no effect and negation
+.TP
+.BR ? label
+1 if label exists, 0 if it does not. This does not generate an error if label
+does not exist. Note that this is usually evaluated immediately (if the rest
+of the expression permits), and it does not check if the label is defined
+later. This means it can be used as the argument of
+.B if
+, to get the functionality of #ifdef in C.
+.TP
+.B (a)
+parenthesis
+.PP
+
+Literals in expressions may be written as: (case does not matter)
+.TP
+.B @c11
+arbitrary base number (specified by 'c' so c+1 == 10: here base is 13)
+.TP
+.B 14, 14d, @914
+decimal number
+.TP
+.B 016, 16o, 16q, &o16, @716
+octal number
+.TP
+.B 0Eh, 0xE, &hE, $E, @FE
+hexadecimal number (for the first notations, the first character must be 0\-9)
+.TP
+.B %1110, 1110b, &b1110, @11110
+binary number
+.TP
+.B 's'
+ASCII code of 's'
+.TP
+.B '\\\\n', '\\\\r', '\\\\a', '\\\\t'
+Newline, carriage return, alert, tab
+.TP
+.B '\\\\nnn'
+Octal ASCII code
+.TP
+.B $
+address of first byte of current command
+
+.SH LABELS
+In all expressions, labels may be used. However, there are some expressions
+where the value must be computable at once, and therefore only previously
+defined labels may be used. This is the case for:
+.TP
+\- The argument of org
+.TP
+\- The argument of seek
+.TP
+\- The argument of equ (eg, a label definition)
+.TP
+\- The first argument of ds
+.TP
+\- The argument of if
+.PP
+In all other expressions, labels which are defined later may be used.
+.PP
+Labels must consist of letters, digits, underscores and periods, and must not
+start with a digit. Labels are case sensitive.
+.PP
+Labels starting with a period (.) are
+.B local
+, which means their scope is only the current include file or macro definition
+(and files included/macros called from it). This is particularly useful for
+macros, to prevent duplicate definitions when using a macro more than once.
+
+.SH EXIT STATUS
+If assembly was successful, no output is produced (except the result, and
+messages triggered by --verbose) and 0 is returned. At any error, there is
+output on the standard error and 1 is returned.
+
+.SH NOTES
+Parts that are not assembled because of an if statement and macros which are
+defined but never used are only checked to have a correct command. The
+argument is not parsed. This means that if the file passes through the
+assembler with no warnings or errors, it may still not assemble correctly in
+a different setting (where the if's give different results).
+
+.SH BUGS
+If you find a bug, or want to send comments, please use the web interface at
+http://savannah.nongnu.org/projects/z80asm/ or send an e\-mail to
+wijnen@debian.org.
+
+.SH AUTHOR
+Z80asm was written by Bas Wijnen <wijnen@debian.org>.
+Some patches were provided by Jan Wilmans <jw@dds.nl>
diff --git a/tools/z80asm/z80asm.c b/tools/z80asm/z80asm.c
index a681aac..2a326df 100644
--- a/tools/z80asm/z80asm.c
+++ b/tools/z80asm/z80asm.c
@@ -1,161 +1,25 @@
/* Z80 assembler by shevek
- Copyright (C) 2002-2005 Bas Wijnen <shevek@fmf.nl>
+ Copyright (C) 2002-2009 Bas Wijnen <wijnen@debian.org>
Copyright (C) 2005 Jan Wilmans <jw@dds.nl>
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
+ This file is part of z80asm.
- This program is distributed in the hope that it will be useful,
+ Z80asm is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ Z80asm is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <stdio.h>
-#include <string.h>
-#include <strings.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <ctype.h>
-#include <stdarg.h>
-#include <getopt.h>
-#include <unistd.h>
-
-/* defines which are not function-specific */
-#ifndef BUFLEN
-#define BUFLEN 300 /* size of readbuffer for file i/o */
-#endif
-
-#ifndef MAX_INCLUDE
-#define MAX_INCLUDE 200 /* stack size for include command and macros */
-#endif
-
-/* types */
-/* mnemonics. THESE MUST BE IN THE SAME ORDER AS const char *mnemonic[]! */
-enum mnemonic
-{
- CALL, CPDR, CPIR, DJNZ, HALT, INDR, INIR, LDDR, LDIR, OTDR, OTIR, OUTD,
- OUTI, PUSH, RETI, RETN, RLCA, RRCA, DEFB, DEFW, DEFS, DEFM,
- ADC, ADD, AND, BIT, CCF, CPD, CPI, CPL, DAA, DEC, EQU, EXX, INC, IND, INI,
- LDD, LDI, NEG, NOP, OUT, POP, RES, RET, RLA, RLC, RLD, RRA, RRC, RRD, RST,
- SBC, SCF, SET, SLA, SLL, SLI, SRA, SRL, SUB, XOR, ORG,
- CP, DI, EI, EX, IM, IN, JP, JR, LD, OR, RL, RR, DB, DW, DS, DM,
- INCLUDE, INCBIN, IF, ELSE, ENDIF, END, MACRO, ENDM, SEEK
-};
-
-/* types of reference */
-enum reftype
-{
- TYPE_BSR, /* bit value (0-7) for bit, set and res */
- TYPE_DS, /* ds reference (byte count and value) */
- TYPE_RST, /* rst reference: val & 0x38 == val */
- TYPE_ABSW, /* absolute word (2 bytes) */
- TYPE_ABSB, /* absolute byte */
- TYPE_RELB, /* relative byte */
- TYPE_LABEL /* equ expression */
-};
-
-/* filetypes that can appear on the input. object files are on the todo list */
-enum filetype
-{
- FILETYPE_ASM
-};
-
-/* labels (will be malloced) */
-struct label
-{
- struct label *next, *prev; /* linked list */
- int value; /* value */
- int valid; /* if it is valid, or not yet computed */
- int busy; /* if it is currently being computed */
- struct reference *ref; /* mallocced memory to value for computation */
- char name[1]; /* space with name in it */
-};
-
-/* files that were given on the commandline */
-struct infile
-{
- const char *name;
- enum filetype type;
-};
-
-/* filenames must be remembered for references */
-struct name
-{
- struct name *next, *prev;
- char name[1];
-};
-
-/* the include path */
-struct includedir
-{
- struct includedir *next;
- char name[1];
-};
-
-/* macro stuff */
-struct macro_arg
-{
- struct macro_arg *next;
- unsigned pos;
- unsigned which;
-};
-
-struct macro_line
-{
- struct macro_line *next;
- char *line;
- struct macro_arg *args;
-};
-
-struct macro
-{
- struct macro *next;
- char *name;
- unsigned numargs;
- char **args;
- struct macro_line *lines;
-};
-
-/* elements on the context stack */
-struct stack
-{
- const char *name; /* filename (for errors). may be malloced */
- struct includedir *dir; /* directory where it comes from, if any */
- FILE *file; /* the handle */
- int line; /* the current line number (for errors) */
- int shouldclose; /* if this file should be closed when done */
- struct label *labels; /* local labels for this stack level */
- /* if file is NULL, this is a macro entry */
- struct macro *macro;
- struct macro_line *macro_line;
- char **macro_args; /* arguments given to the macro */
-};
-
-/* these structs will be malloced for each reference */
-struct reference
-{
- struct reference *next, *prev;
- enum reftype type; /* type of reference */
- long oseekpos; /* position in outfile for data */
- long lseekpos; /* position in listfile for data */
- char delimiter; /* delimiter for parser */
- int addr, line; /* address and line of reference */
- int comma; /* comma when reference was set */
- int count; /* only for ds: number of items */
- int infile; /* index in infile[], current infile */
- int done; /* if this reference has been computed */
- int computed_value; /* value (only valid if done = true) */
- int level; /* maximum stack level of labels to use */
- char input[1]; /* variable size buffer containing formula */
-};
+#include "z80asm.h"
/* global variables */
/* mnemonics, used as argument to indx() in assemble */
@@ -174,83 +38,89 @@ const char *mnemonics[] = {
};
/* linked lists */
-static struct reference *firstreference = NULL;
-static struct label *firstlabel = NULL, *lastlabel = NULL;
-static struct name *firstname = NULL;
-static struct includedir *firstincludedir = NULL;
-static struct macro *firstmacro = NULL;
+struct reference *firstreference = NULL;
+struct label *firstlabel = NULL, *lastlabel = NULL;
+struct name *firstname = NULL;
+struct includedir *firstincludedir = NULL;
+struct macro *firstmacro = NULL;
/* files */
-static FILE *realoutputfile, *outfile, *reallistfile, *listfile, *labelfile;
-static const char *realoutputfilename;
-static const char *labelfilename;
-static struct infile *infile;
+FILE *realoutputfile, *outfile, *reallistfile, *listfile, *labelfile;
+const char *realoutputfilename;
+const char *labelfilename;
+struct infile *infile;
/* prefix for labels in labelfile */
-static const char *labelprefix = "";
+const char *labelprefix = "";
/* bools to see if files are opened */
-static int havelist = 0, label = 0;
+int havelist = 0, label = 0;
/* number of infiles in array */
-static int infilecount;
+int infilecount;
/* number of errors seen so far */
-static int errors = 0;
+int errors = 0;
/* current line, address and file */
-static int addr = 0, file;
+int addr = 0, file;
/* current number of characters in list file, for indentation */
-static int listdepth;
+int listdepth;
/* use readbyte instead of (hl) if writebyte is true */
-static int writebyte;
-static const char *readbyte;
+int writebyte;
+const char *readbyte;
/* variables which are filled by rd_* functions and used later,
* like readbyte */
-static const char *readword, *indexjmp, *bitsetres;
+const char *readword, *indexjmp, *bitsetres;
/* 0, 0xdd or 0xfd depening on which index prefix should be given */
-static int indexed;
+int indexed;
/* increased for every -v option on the command line */
-static int verbose = 0;
+int verbose = 0;
/* read commas after indx() if comma > 1. increase for every call */
-static int comma;
+int comma;
/* address at start of line (for references) */
-static int baseaddr;
+int baseaddr;
/* set by readword and readbyte, used for new_reference */
-static char mem_delimiter;
+char mem_delimiter;
/* line currently being parsed */
-static char *buffer = NULL;
+char *buffer = NULL;
/* if a macro is currently being defined */
-static int define_macro = 0;
+int define_macro = 0;
/* file (and macro) stack */
-static int sp;
-static struct stack stack[MAX_INCLUDE]; /* maximum level of includes */
+int sp;
+struct stack stack[MAX_INCLUDE]; /* maximum level of includes */
/* Produce output even with errors. */
-static int use_force = 0;
+int use_force = 0;
/* print an error message, including current line and file */
-static void
-printerr (const char *fmt, ...)
+void
+printerr (int error, const char *fmt, ...)
{
- int msp = (sp < 0) ? 0 : sp;
va_list l;
va_start (l, fmt);
- fprintf (stderr, "%s%s:%d: ", stack[msp].dir ? stack[msp].dir->name : "",
- stack[msp].name, stack[msp].line);
+ if ((sp < 0) || (stack[sp].name == 0))
+ {
+ fprintf (stderr, "internal assembler error, sp == %i\n", sp);
+ vfprintf (stderr, fmt, l);
+ exit (2);
+ }
+ fprintf (stderr, "%s%s:%d: %s: ", stack[sp].dir ? stack[sp].dir->name : "",
+ stack[sp].name, stack[sp].line, error ? "error" : "warning");
vfprintf (stderr, fmt, l);
va_end (l);
- errors++;
+ if (error)
+ errors++;
}
/* skip over spaces in string */
-static const char *
+const char *
delspc (const char *ptr)
{
while (*ptr && isspace (*ptr))
@@ -267,7 +137,7 @@ rd_comma (const char **p)
*p = delspc (*p);
if (**p != ',')
{
- printerr ("`,' expected. Remainder of line: %s\n", *p);
+ printerr (1, "`,' expected. Remainder of line: %s\n", *p);
return;
}
*p = delspc ((*p) + 1);
@@ -287,37 +157,11 @@ has_argument (const char **p)
static void
skipword (const char **pos, char delimiter)
{
- int depth = 0;
- char c;
- while (1)
- {
- switch (c = (*((*pos)++)))
- {
- case '\0':
- if (depth > 0)
- {
- printerr ("unexpected end of line\n");
- }
- (*pos)--;
- return;
- case '(':
- depth++;
- break;
- case ')':
- if (--depth < 0)
- {
- if (delimiter == ')')
- return;
- printerr ("unexpected `)'\n");
- }
- break;
- default:
- if (delimiter == c && depth == 0)
- {
- return;
- }
- }
- }
+ /* rd_expr will happily read the expression, and possibly return
+ * an invalid result. It will update pos, which is what we need. */
+ /* Pass valid to allow using undefined labels without errors. */
+ int valid;
+ rd_expr (pos, delimiter, &valid, sp, 0);
}
/* callback function for argument parser, used to open output files. */
@@ -373,7 +217,7 @@ open_include_file (const char *name, struct includedir **dir,
char *tmp = malloc (strlen (i->name) + strlen (name) + 1);
if (!tmp)
{
- printerr ("not enough memory trying to open include file\n");
+ printerr (1, "not enough memory trying to open include file\n");
return NULL;
}
strcpy (tmp, i->name);
@@ -498,7 +342,7 @@ parse_commandline (int argc, char **argv)
{"force", no_argument, NULL, 'f'},
{NULL, 0, NULL, 0}
};
- const char *short_opts = "hVvl:L:i:o:p:I:f";
+ const char *short_opts = "hVvl::L::i:o:p:I:f";
int done = 0, i, out = 0;
infile = NULL;
while (!done)
@@ -525,7 +369,7 @@ parse_commandline (int argc, char **argv)
exit (0);
case 'V':
printf ("Z80 assembler version " VERSION "\n"
- "Copyright (C) 2002-2005 Bas Wijnen "
+ "Copyright (C) 2002-2007 Bas Wijnen "
"<shevek@fmf.nl>.\n"
"Copyright (C) 2005 Jan Wilmans "
"<jw@dds.nl>.\n"
@@ -534,8 +378,8 @@ parse_commandline (int argc, char **argv)
"of the GNU General Public License as published by\n"
"the Free Software Foundation; either version 2 of the\n"
"License, or (at your option) any later version.\n\n"
- "For more information about these matters, see the file\n"
- "named COPYING.\n");
+ "The complete text of the GPL can be found in\n"
+ "/usr/share/common-licenses/GPL.\n");
exit (0);
case 'v':
verbose++;
@@ -594,7 +438,7 @@ parse_commandline (int argc, char **argv)
/* find any of the list[] entries as the start of ptr and return index */
static int
-indx (const char **ptr, const char **list, int error)
+indx (const char **ptr, const char **list, int error, const char **expr)
{
int i, l;
*ptr = delspc (*ptr);
@@ -602,7 +446,7 @@ indx (const char **ptr, const char **list, int error)
{
if (error)
{
- printerr ("unexpected end of line\n");
+ printerr (1, "unexpected end of line\n");
return 0;
}
else
@@ -612,24 +456,63 @@ indx (const char **ptr, const char **list, int error)
rd_comma (ptr);
for (i = 0; list[i]; i++)
{
+ const char *input = *ptr;
+ const char *check = list[i];
+ int had_expr = 0;
+ if (!list[i][0])
+ continue;
l = strlen (list[i]);
- if (list[i][0] && !strncasecmp (*ptr, list[i], l)
- && (!isalnum ((*ptr)[l]) || !isalnum (list[i][l - 1])))
+ while (*check)
+ {
+ if (*check == ' ')
+ {
+ input = delspc (input);
+ }
+ else if (*check == '*')
+ {
+ *expr = input;
+ mem_delimiter = check[1];
+ rd_expr (&input, mem_delimiter, NULL, sp, 0);
+ had_expr = 1;
+ }
+ else if (*check == '+')
+ {
+ if (*input == '+' || *input == '-')
+ {
+ *expr = input;
+ mem_delimiter = check[1];
+ rd_expr (&input, mem_delimiter, NULL, sp, 0);
+ }
+ }
+ else if (*check == *input || (*check >= 'a' && *check <= 'z'
+ && *check - 'a' + 'A' == *input))
+ ++input;
+ else
+ break;
+
+ ++check;
+ }
+ if (*check || (isalnum (check[-1]) && isalnum (input[0])))
+ continue;
+ if (had_expr)
{
- (*ptr) += l;
- if (verbose >= 4)
- fprintf (stderr, "%5d (0x%04x): Piece of code found:%s\n",
- stack[sp].line, addr, list[i]);
- if (verbose >= 6)
- fprintf (stderr, "%5d (0x%04x): Remainder of line=%s.\n",
- stack[sp].line, addr, *ptr);
- comma++;
- return i + 1;
+ input = delspc (input);
+ if (*input && *input != ',')
+ continue;
}
+ *ptr = input;
+ if (verbose >= 4)
+ fprintf (stderr, "%5d (0x%04x): Piece of code found:%s\n",
+ stack[sp].line, addr, list[i]);
+ if (verbose >= 6)
+ fprintf (stderr, "%5d (0x%04x): Remainder of line=%s.\n",
+ stack[sp].line, addr, *ptr);
+ comma++;
+ return i + 1;
}
if (error)
{
- printerr ("parse error. Remainder of line=%s\n", *ptr);
+ printerr (1, "parse error. Remainder of line=%s\n", *ptr);
if (verbose >= 3)
{
fprintf (stderr, "When looking for any of:\n");
@@ -645,12 +528,9 @@ indx (const char **ptr, const char **list, int error)
static int
readcommand (const char **p)
{
- return indx (p, mnemonics, 0);
+ return indx (p, mnemonics, 0, NULL);
}
-static int rd_label (const char **p, int *exists, struct label **previous,
- int level);
-
/* try to read a label and optionally store it in the list */
static void
readlabel (const char **p, int store)
@@ -669,7 +549,7 @@ readlabel (const char **p, int store)
return;
if (pos == *p)
{
- printerr ("`:' found without a label");
+ printerr (1, "`:' found without a label");
return;
}
if (!store)
@@ -679,16 +559,16 @@ readlabel (const char **p, int store)
}
c = pos + 1;
dummy = *p;
- j = rd_label (&dummy, &i, &previous, sp);
+ j = rd_label (&dummy, &i, &previous, sp, 0);
if (i || j)
{
- printerr ("duplicate definition of label %s\n", *p);
+ printerr (1, "duplicate definition of label %s\n", *p);
*p = c;
return;
}
if (NULL == (buf = malloc (sizeof (struct label) + c - *p)))
{
- printerr ("not enough memory to store label %s\n", *p);
+ printerr (1, "not enough memory to store label %s\n", *p);
*p = c;
return;
}
@@ -739,6 +619,7 @@ write_one_byte (int b, int list)
listdepth += 3;
}
addr++;
+ addr &= 0xffff;
}
/* write byte to outfile and possibly some index things as well */
@@ -793,161 +674,19 @@ wrtb (int b)
}
}
-/* reading expressions. The following operators are supported
- * in order of precedence, with function name:
- * expr?expr:expr rd_expr
- * | rd_expr_or
- * ^ rd_expr_xor
- * & rd_expr_and
- * == != rd_expr_equal
- * >= <= > < rd_expr_unequal
- * << >> rd_expr_shift
- * + - (binary) rd_term
- * * / % rd_factor
- * ~ + - (unary) rd_factor
- */
-
-static int
-rd_number (const char **p, const char **endp, int base)
-{
- int result = 0, i;
- char *c, num[] = "0123456789abcdefghijklmnopqrstuvwxyz";
- if (verbose >= 6)
- fprintf (stderr, "%5d (0x%04x): Starting to read number of base %d"
- "(string=%s).\n", stack[sp].line, addr, base, *p);
- num[base] = '\0';
- *p = delspc (*p);
- while (**p && (c = strchr (num, tolower (**p))))
- {
- i = c - num;
- if (verbose >= 7)
- fprintf (stderr, "%5d (0x%04x): Digit found:%1x.\n", stack[sp].line,
- addr, i);
- result = result * base + i;
- (*p)++;
- }
- if (endp)
- *endp = *p;
- *p = delspc (*p);
- if (verbose >= 7)
- fprintf (stderr, "%5d (0x%04x): rd_number returned %d (%04x).\n",
- stack[sp].line, addr, result, result);
- return result;
-}
-
-static int
-rd_otherbasenumber (const char **p)
-{
- char c;
- if (verbose >= 6)
- fprintf (stderr,
- "%5d (0x%04x): Starting to read basenumber (string=%s).\n",
- stack[sp].line, addr, *p);
- (*p)++;
- if (!**p)
- {
- printerr ("unexpected end of line after `@'\n");
- return 0;
- }
- if (**p == '0' || !isalnum (**p))
- {
- printerr ("base must be between 1 and z\n");
- return 0;
- }
- c = **p;
- (*p)++;
- if (isalpha (**p))
- return rd_number (p, NULL, tolower (c) - 'a' + 1);
- return rd_number (p, NULL, c - '0' + 1);
-}
-
-static int
-rd_character (const char **p)
-{
- int i;
- if (verbose >= 6)
- fprintf (stderr,
- "%5d (0x%04x): Starting to read character (string=%s).\n",
- stack[sp].line, addr, *p);
- i = **p;
- if (!i)
- {
- printerr ("unexpected end of line in string constant\n");
- return 0;
- }
- if (i == '\\')
- {
- (*p)++;
- if (**p >= '0' && **p <= '7')
- {
- int b, num_digits;
- i = 0;
- if ((*p)[1] >= '0' && (*p)[1] <= '7')
- {
- if (**p <= '3' && (*p)[2] >= '0' && (*p)[2] <= '7')
- num_digits = 3;
- else
- num_digits = 2;
- }
- else
- num_digits = 1;
- for (b = 0; b < num_digits; ++b)
- {
- int bit = (*p)[num_digits - 1 - b] - '0';
- i += (1 << (b * 3)) * bit;
- }
- *p += num_digits;
- }
- else
- {
- switch (**p)
- {
- case 'n':
- i = 10;
- break;
- case 'r':
- i = 13;
- break;
- case 't':
- i = 9;
- break;
- case 'a':
- i = 7;
- break;
- case '\'':
- printerr ("empty literal character\n");
- return 0;
- case 0:
- printerr ("unexpected end of line after "
- "backslash in string constant\n");
- return 0;
- default:
- i = **p;
- }
- (*p)++;
- }
- }
- else
- (*p)++;
- if (verbose >= 7)
- fprintf (stderr, "%5d (0x%04x): rd_character returned %d (%c).\n",
- stack[sp].line, addr, i, i);
- return i;
-}
-
-static int rd_expr (const char **p, char delimiter, int *valid, int level);
-
-static int
+int
compute_ref (struct reference *ref, int allow_invalid)
{
const char *ptr;
int valid = 0;
int backup_addr = addr;
+ int backup_baseaddr = baseaddr;
int backup_comma = comma;
int backup_file = file;
int backup_sp = sp;
sp = ref->level;
addr = ref->addr;
+ baseaddr = ref->baseaddr;
comma = ref->comma;
file = ref->infile;
if (verbose >= 3)
@@ -960,7 +699,7 @@ compute_ref (struct reference *ref, int allow_invalid)
{
ref->computed_value = rd_expr (&ptr, ref->delimiter,
allow_invalid ? &valid : NULL,
- ref->level);
+ ref->level, 1);
if (valid)
ref->done = 1;
}
@@ -969,519 +708,12 @@ compute_ref (struct reference *ref, int allow_invalid)
stack[sp].line, addr, ref->computed_value, ref->computed_value);
sp = backup_sp;
addr = backup_addr;
+ baseaddr = backup_baseaddr;
comma = backup_comma;
file = backup_file;
return ref->computed_value;
}
-static int
-check_label (struct label *labels, const char **p, struct label **ret,
- struct label **previous, int force_skip)
-{
- struct label *l;
- const char *c;
- unsigned s2;
- *p = delspc (*p);
- for (c = *p; isalnum (*c) || *c == '_' || *c == '.'; ++c)
- {
- }
- s2 = c - *p;
- for (l = labels; l; l = l->next)
- {
- unsigned s1, s;
- int cmp;
- s1 = strlen (l->name);
- s = s1 < s2 ? s1 : s2;
- cmp = strncmp (l->name, *p, s);
- if (cmp > 0 || (cmp == 0 && s1 > s))
- {
- if (force_skip)
- *p = c;
- return 0;
- }
- if (cmp < 0 || s2 > s)
- {
- if (previous)
- *previous = l;
- continue;
- }
- *p = c;
- /* if label is not valid, compute it */
- if (l->ref)
- {
- compute_ref (l->ref, 1);
- if (!l->ref->done)
- {
- /* label was not valid, and isn't computable. tell the
- * caller that it doesn't exist, so it will try again later.
- * Set ret to show actual existence. */
- if (verbose >= 6)
- fprintf (stderr,
- "%5d (0x%04x): returning invalid label %s.\n",
- stack[sp].line, addr, l->name);
- *ret = l;
- return 0;
- }
- }
- *ret = l;
- return 1;
- }
- if (force_skip)
- *p = c;
- return 0;
-}
-
-static int
-rd_label (const char **p, int *exists, struct label **previous, int level)
-{
- struct label *l = NULL;
- int s;
- if (exists)
- *exists = 0;
- if (previous)
- *previous = NULL;
- if (verbose >= 6)
- fprintf (stderr, "%5d (0x%04x): Starting to read label (string=%s).\n",
- stack[sp].line, addr, *p);
- for (s = level; s >= 0; --s)
- {
- if (check_label (stack[s].labels, p, &l,
- (**p == '.' && s == sp) ? previous : NULL, 0))
- break;
- }
- if (s < 0)
- {
- /* not yet found */
- const char *old_p = *p;
- if (!check_label (firstlabel, p, &l, **p != '.' ? previous : NULL, 1))
- {
- /* label does not exist, or is invalid. This is an error if there
- * is no existance check. */
- if (!exists)
- printerr ("using undefined label %.*s\n", *p - old_p, old_p);
- /* Return a value to discriminate between non-existing and invalid */
- if (verbose >= 7)
- fprintf (stderr, "rd_label returns invalid value\n");
- return l != NULL;
- }
- }
- if (exists)
- *exists = 1;
- if (verbose >= 7)
- fprintf (stderr, "rd_label returns valid value 0x%x\n", l->value);
- return l->value;
-}
-
-static int
-rd_value (const char **p, int *valid, int level)
-{
- int sign = 1, not = 0, base, v;
- const char *p0, *p1, *p2;
- if (verbose >= 6)
- fprintf (stderr, "%5d (0x%04x): Starting to read value (string=%s).\n",
- stack[sp].line, addr, *p);
- *p = delspc (*p);
- while (**p && strchr ("+-~", **p))
- {
- if (**p == '-')
- sign = -sign;
- else if (**p == '~')
- not = ~not;
- (*p)++;
- *p = delspc (*p);
- }
- base = 10; /* Default base for suffixless numbers */
- switch (**p)
- {
- int exist, retval;
- char quote;
- case '(':
- (*p)++;
- retval = not ^ (sign * rd_expr (p, ')', valid, level));
- ++*p;
- return retval;
- case '0':
- if ((*p)[1] == 'x')
- {
- (*p) += 2;
- return not ^ (sign * rd_number (p, NULL, 0x10));
- }
- base = 8; /* If first digit it 0, assume octal unless suffix */
- /* fall through */
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- p0 = *p;
- rd_number (p, &p1, 36); /* Advance to end of numeric string */
- p1--; /* Last character in numeric string */
- switch (*p1)
- {
- case 'h':
- case 'H':
- base = 16;
- break;
- case 'b':
- case 'B':
- base = 2;
- break;
- case 'o':
- case 'O':
- case 'q':
- case 'Q':
- base = 8;
- break;
- case 'd':
- case 'D':
- base = 10;
- break;
- default: /* No suffix */
- p1++;
- break;
- }
- v = rd_number (&p0, &p2, base);
- if (p1 != p2)
- {
- printerr ("invalid character in number: \'%c\'\n", *p2);
- }
- return not ^ (sign * v);
- case '$':
- ++*p;
- *p = delspc (*p);
- p0 = *p;
- v = rd_number (&p0, &p2, 0x10);
- if (p2 == *p)
- {
- v = baseaddr;
- }
- else
- *p = p2;
- return not ^ (sign * v);
- case '%':
- (*p)++;
- return not ^ (sign * rd_number (p, NULL, 2));
- case '\'':
- case '"':
- quote = **p;
- ++*p;
- retval = not ^ (sign * rd_character (p));
- if (**p != quote)
- {
- printerr ("missing closing quote (%c)\n", quote);
- return 0;
- }
- ++*p;
- return retval;
- case '@':
- return not ^ (sign * rd_otherbasenumber (p));
- case '?':
- rd_label (p, &exist, NULL, level);
- return not ^ (sign * exist);
- case '&':
- {
- ++*p;
- switch (**p)
- {
- case 'h':
- case 'H':
- base = 0x10;
- break;
- case 'o':
- case 'O':
- base = 010;
- break;
- case 'b':
- case 'B':
- base = 2;
- break;
- default:
- printerr ("invalid literal starting with &%c\n", **p);
- return 0;
- }
- ++*p;
- return not ^ (sign * rd_number (p, NULL, base));
- }
- default:
- return not ^ (sign * rd_label (p, valid, NULL, level));
- }
-}
-
-static int
-rd_factor (const char **p, int *valid, int level)
-{
- /* read a factor of an expression */
- int result;
- if (verbose >= 6)
- fprintf (stderr, "%5d (0x%04x): Starting to read factor (string=%s).\n",
- stack[sp].line, addr, *p);
- result = rd_value (p, valid, level);
- *p = delspc (*p);
- while (**p == '*' || **p == '/')
- {
- if (**p == '*')
- {
- (*p)++;
- result *= rd_value (p, valid, level);
- }
- else if (**p == '/')
- {
- (*p)++;
- result /= rd_value (p, valid, level);
- }
- *p = delspc (*p);
- }
- if (verbose >= 7)
- fprintf (stderr, "%5d (0x%04x): rd_factor returned %d (%04x).\n",
- stack[sp].line, addr, result, result);
- return result;
-}
-
-static int
-rd_term (const char **p, int *valid, int level)
-{
- /* read a term of an expression */
- int result;
- if (verbose >= 6)
- fprintf (stderr, "%5d (0x%04x): Starting to read term (string=%s).\n",
- stack[sp].line, addr, *p);
- result = rd_factor (p, valid, level);
- *p = delspc (*p);
- while (**p == '+' || **p == '-')
- {
- if (**p == '+')
- {
- (*p)++;
- result += rd_factor (p, valid, level);
- }
- else if (**p == '-')
- {
- (*p)++;
- result -= rd_factor (p, valid, level);
- }
- *p = delspc (*p);
- }
- if (verbose >= 7)
- fprintf (stderr, "%5d (0x%04x): rd_term returned %d (%04x).\n",
- stack[sp].line, addr, result, result);
- return result;
-}
-
-static int
-rd_expr_shift (const char **p, int *valid, int level)
-{
- int result;
- if (verbose >= 6)
- fprintf (stderr, "%5d (0x%04x): Starting to read shift expression "
- "(string=%s).\n", stack[sp].line, addr, *p);
- result = rd_term (p, valid, level);
- *p = delspc (*p);
- while ((**p == '<' || **p == '>') && (*p)[1] == **p)
- {
- if (**p == '<')
- {
- (*p) += 2;
- result <<= rd_term (p, valid, level);
- }
- else if (**p == '>')
- {
- (*p) += 2;
- result >>= rd_term (p, valid, level);
- }
- *p = delspc (*p);
- }
- if (verbose >= 7)
- fprintf (stderr, "%5d (0x%04x): rd_shift returned %d (%04x).\n",
- stack[sp].line, addr, result, result);
- return result;
-}
-
-static int
-rd_expr_unequal (const char **p, int *valid, int level)
-{
- int result;
- if (verbose >= 6)
- fprintf (stderr, "%5d (0x%04x): Starting to read "
- "unequality expression (string=%s).\n", stack[sp].line, addr,
- *p);
- result = rd_expr_shift (p, valid, level);
- *p = delspc (*p);
- if (**p == '<' && (*p)[1] == '=')
- {
- (*p) += 2;
- return result <= rd_expr_unequal (p, valid, level);
- }
- else if (**p == '>' && (*p)[1] == '=')
- {
- (*p) += 2;
- return result >= rd_expr_unequal (p, valid, level);
- }
- if (**p == '<' && (*p)[1] != '<')
- {
- (*p)++;
- return result < rd_expr_unequal (p, valid, level);
- }
- else if (**p == '>' && (*p)[1] != '>')
- {
- (*p)++;
- return result > rd_expr_unequal (p, valid, level);
- }
- if (verbose >= 7)
- fprintf (stderr, "%5d (0x%04x): rd_shift returned %d (%04x).\n",
- stack[sp].line, addr, result, result);
- return result;
-}
-
-static int
-rd_expr_equal (const char **p, int *valid, int level)
-{
- int result;
- if (verbose >= 6)
- fprintf (stderr, "%5d (0x%04x): Starting to read equality epression "
- "(string=%s).\n", stack[sp].line, addr, *p);
- result = rd_expr_unequal (p, valid, level);
- *p = delspc (*p);
- if (**p == '=')
- {
- ++*p;
- if (**p == '=')
- ++ * p;
- return result == rd_expr_equal (p, valid, level);
- }
- else if (**p == '!' && (*p)[1] == '=')
- {
- (*p) += 2;
- return result != rd_expr_equal (p, valid, level);
- }
- if (verbose >= 7)
- fprintf (stderr, "%5d (0x%04x): rd_equal returned %d (%04x).\n",
- stack[sp].line, addr, result, result);
- return result;
-}
-
-static int
-rd_expr_and (const char **p, int *valid, int level)
-{
- int result;
- if (verbose >= 6)
- fprintf (stderr, "%5d (0x%04x): Starting to read and expression "
- "(string=%s).\n", stack[sp].line, addr, *p);
- result = rd_expr_equal (p, valid, level);
- *p = delspc (*p);
- if (**p == '&')
- {
- (*p)++;
- result &= rd_expr_and (p, valid, level);
- }
- if (verbose >= 7)
- fprintf (stderr, "%5d (0x%04x): rd_expr_and returned %d (%04x).\n",
- stack[sp].line, addr, result, result);
- return result;
-}
-
-static int
-rd_expr_xor (const char **p, int *valid, int level)
-{
- int result;
- if (verbose >= 6)
- fprintf (stderr, "%5d (0x%04x): Starting to read xor expression "
- "(string=%s).\n", stack[sp].line, addr, *p);
- result = rd_expr_and (p, valid, level);
- if (verbose >= 7)
- fprintf (stderr, "%5d (0x%04x): rd_expr_xor: rd_expr_and returned %d "
- "(%04x).\n", stack[sp].line, addr, result, result);
- *p = delspc (*p);
- if (**p == '^')
- {
- (*p)++;
- result ^= rd_expr_xor (p, valid, level);
- }
- if (verbose >= 7)
- fprintf (stderr, "%5d (0x%04x): rd_expr_xor returned %d (%04x).\n",
- stack[sp].line, addr, result, result);
- return result;
-}
-
-static int
-rd_expr_or (const char **p, int *valid, int level)
-{
- int result;
- if (verbose >= 6)
- fprintf (stderr, "%5d (0x%04x): Starting to read or expression "
- "(string=%s).\n", stack[sp].line, addr, *p);
- result = rd_expr_xor (p, valid, level);
- if (verbose >= 7)
- fprintf (stderr, "%5d (0x%04x): rd_expr_or: rd_expr_xor returned %d "
- "(%04x).\n", stack[sp].line, addr, result, result);
- *p = delspc (*p);
- if (**p == '|')
- {
- (*p)++;
- result |= rd_expr_or (p, valid, level);
- }
- if (verbose >= 7)
- fprintf (stderr, "%5d (0x%04x): rd_expr_or returned %d (%04x).\n",
- stack[sp].line, addr, result, result);
- return result;
-}
-
-static int
-rd_expr (const char **p, char delimiter, int *valid, int level)
-{
- /* read an expression. delimiter can _not_ be '?' */
- int result = 0;
- if (verbose >= 6)
- fprintf (stderr,
- "%5d (0x%04x): Starting to read expression (string=%s).\n",
- stack[sp].line, addr, *p);
- if (valid)
- *valid = 1;
- *p = delspc (*p);
- if (!**p || **p == delimiter)
- {
- printerr ("expression expected (not %s)\n", *p);
- return 0;
- }
- result = rd_expr_or (p, valid, level);
- *p = delspc (*p);
- if (**p == '?')
- {
- (*p)++;
- if (result)
- {
- result = rd_expr (p, ':', valid, level);
- if (**p)
- (*p)++;
- rd_expr (p, delimiter, valid, level);
- }
- else
- {
- rd_expr (p, ':', valid, level);
- if (**p)
- (*p)++;
- result = rd_expr (p, delimiter, valid, level);
- }
- }
- *p = delspc (*p);
- if (**p && **p != delimiter)
- {
- printerr ("ignoring junk at end of expression: %s\n", *p);
- }
- if (verbose >= 7)
- {
- fprintf (stderr, "%5d (0x%04x): rd_expr returned %d (%04x).\n",
- stack[sp].line, addr, result, result);
- if (valid && !*valid)
- fprintf (stderr, "%5d (0x%04x): Returning invalid result.\n",
- stack[sp].line, addr);
- }
- return result;
-}
-
static void wrt_ref (int val, int type, int count);
/* Create a new reference, to be resolved after assembling (so all labels are
@@ -1494,7 +726,7 @@ new_reference (const char *p, int type, char delimiter, int ds_count)
int valid, value;
const char *c;
c = p;
- value = rd_expr (&c, delimiter, &valid, sp);
+ value = rd_expr (&c, delimiter, &valid, sp, 1);
if (valid)
{
if (verbose >= 5)
@@ -1505,20 +737,45 @@ new_reference (const char *p, int type, char delimiter, int ds_count)
}
else
{
- /* the expression is not valid (yet), we need to make a real reference.
- */
- if (NULL == (tmp = malloc (sizeof (struct reference) + strlen (p))))
+ /* the expression is not valid (yet), we need to make a real reference. */
+ tmp = malloc (sizeof (struct reference) + strlen (p));
+ if (!tmp)
+ {
+ printerr (1, "unable to allocate memory for reference %s\n", p);
+ return;
+ }
+ tmp->file = malloc (strlen (stack[sp].name) + 1);
+ if (!tmp->file)
{
- printerr ("unable to allocate memory for reference %s\n", p);
+ printerr (1, "unable to allocate memory for reference filename\n");
+ free (tmp);
return;
}
+ strcpy (tmp->file, stack[sp].name);
+ if (stack[sp].dir)
+ {
+ tmp->dir = malloc (strlen (stack[sp].dir->name)
+ + sizeof (struct includedir));
+ if (!tmp->dir)
+ {
+ printerr (1, "unable to allocate memory for reference dir\n");
+ free (tmp->file);
+ free (tmp);
+ return;
+ }
+ strcpy (tmp->dir->name, stack[sp].dir->name);
+ }
+ else
+ tmp->dir = NULL;
opos = ftell (outfile);
lpos = havelist ? ftell (listfile) : 0;
if (verbose >= 3)
- fprintf (stderr, "%5d (0x%04x): reference set to %s (delimiter=%c)\n",
- stack[sp].line, addr, p, delimiter);
+ fprintf (stderr, "%5d (0x%04x): reference set to %s (delimiter=%c, "
+ "sp=%d)\n", stack[sp].line, addr, p, delimiter, sp);
strcpy (tmp->input, p);
- tmp->addr = baseaddr;
+ tmp->line = stack[sp].line;
+ tmp->addr = addr;
+ tmp->baseaddr = baseaddr;
tmp->count = ds_count;
tmp->infile = file;
tmp->comma = comma;
@@ -1593,16 +850,6 @@ rd_byte (const char **p, char delimiter)
return 1;
}
-/* read an indexjump byte (for (ix + nn) commands) */
-static void
-rd_index (const char **p)
-{
- rd_byte (p, ')');
- indexjmp = readbyte;
- writebyte = 0;
- return;
-}
-
/* read an address from infile and put it in reference table.
* so that it will be written here afterwards */
static void
@@ -1628,8 +875,8 @@ rd_ex1 (const char **p)
{
#define DE 2
#define AF 3
- const char *list[] = { "(sp)", "de", "af", NULL };
- return indx (p, list, 1);
+ const char *list[] = { "( sp )", "de", "af", NULL };
+ return indx (p, list, 1, NULL);
}
/* read first argument of IN */
@@ -1638,7 +885,7 @@ rd_in (const char **p)
{
#define A 8
const char *list[] = { "b", "c", "d", "e", "h", "l", "f", "a", NULL };
- return indx (p, list, 1);
+ return indx (p, list, 1, NULL);
}
/* read second argument of out (c),x */
@@ -1646,7 +893,7 @@ static int
rd_out (const char **p)
{
const char *list[] = { "b", "c", "d", "e", "h", "l", "0", "a", NULL };
- return indx (p, list, 1);
+ return indx (p, list, 1, NULL);
}
/* read (c) or (nn) */
@@ -1655,34 +902,10 @@ rd_nnc (const char **p)
{
#define C 1
int i;
- const char *list[] = { "(", NULL };
- i = indx (p, list, 1);
- if (!i)
- return 0;
- *p = delspc (*p);
- if (tolower (**p) == 'c')
- {
- *p = delspc ((*p) + 1);
- if (**p != ')')
- {
- printerr ("missing closing parenthesis\n");
- return 0;
- }
- (*p)++;
- return C;
- }
- if (tolower (**p) == 'a')
- {
- *p = delspc ((*p) + 1);
- if (**p != ',')
- {
- printerr ("missing ','\n");
- return 0;
- }
- *p = delspc ((*p) + 1);
- }
- rd_byte (p, ')');
- writebyte = 0;
+ const char *list[] = { "( c )", "(*)", "a , (*)", NULL };
+ i = indx (p, list, 1, &readbyte);
+ if (i < 2)
+ return i;
return 2;
}
@@ -1690,8 +913,8 @@ rd_nnc (const char **p)
static int
rd_c (const char **p)
{
- const char *list[] = { "(c)", "(bc)", NULL };
- return indx (p, list, 1);
+ const char *list[] = { "( c )", "( bc )", NULL };
+ return indx (p, list, 1, NULL);
}
/* read a or hl */
@@ -1700,7 +923,7 @@ rd_a_hl (const char **p)
{
#define HL 2
const char *list[] = { "a", "hl", NULL };
- return indx (p, list, 1);
+ return indx (p, list, 1, NULL);
}
/* read first argument of ld */
@@ -1731,10 +954,11 @@ rd_ld (const char **p)
int i;
const char *list[] = {
"ixh", "ixl", "iyh", "iyl", "bc", "de", "hl", "sp", "ix",
- "iy", "b", "c", "d", "e", "h", "l", "(hl)", "a", "i",
- "r", "(bc)", "(de)", "(ix", "(iy", "(", NULL
+ "iy", "b", "c", "d", "e", "h", "l", "( hl )", "a", "i",
+ "r", "( bc )", "( de )", "( ix +)", "(iy +)", "(*)", NULL
};
- i = indx (p, list, 1);
+ const char *nn;
+ i = indx (p, list, 1, &nn);
if (!i)
return 0;
if (i <= 2)
@@ -1755,12 +979,12 @@ rd_ld (const char **p)
}
if (i == ld_IX || i == ld_IY)
{
- rd_index (p);
+ indexjmp = nn;
indexed = i == ld_IX ? 0xDD : 0xFD;
return ld_HL;
}
if (i == ld_NN)
- rd_word (p, ')');
+ readword = nn;
return i;
}
@@ -1770,10 +994,10 @@ rd_jp (const char **p)
{
int i;
const char *list[] = {
- "nz", "z", "nc", "c", "po", "pe", "p", "m", "(ix)", "(iy)",
+ "nz", "z", "nc", "c", "po", "pe", "p", "m", "( ix )", "( iy )",
"(hl)", NULL
};
- i = indx (p, list, 0);
+ i = indx (p, list, 0, NULL);
if (i < 9)
return i;
if (i == 11)
@@ -1787,7 +1011,7 @@ static int
rd_jr (const char **p)
{
const char *list[] = { "nz", "z", "nc", "c", NULL };
- return indx (p, list, 0);
+ return indx (p, list, 0, NULL);
}
/* read A */
@@ -1795,7 +1019,7 @@ static int
rd_a (const char **p)
{
const char *list[] = { "a", NULL };
- return indx (p, list, 1);
+ return indx (p, list, 1, NULL);
}
/* read bc,de,hl,af */
@@ -1804,20 +1028,21 @@ rd_stack (const char **p)
{
int i;
const char *list[] = { "bc", "de", "hl", "af", "ix", "iy", NULL };
- i = indx (p, list, 1);
+ i = indx (p, list, 1, NULL);
if (i < 5)
return i;
indexed = 0xDD + 0x20 * (i - 5);
return 3;
}
+#if 0
/* read a or hl(2) or i[xy](2) with variables set */
static int
rd_a_hlx (const char **p)
{
int i;
const char *list[] = { "a", "hl", "ix", "iy", NULL };
- i = indx (p, list, 1);
+ i = indx (p, list, 1, NULL);
if (i < 2)
return i;
if (i == 2)
@@ -1825,6 +1050,7 @@ rd_a_hlx (const char **p)
indexed = 0xDD + 0x20 * (i - 3);
return 2;
}
+#endif
/* read b,c,d,e,h,l,(hl),a,(ix+nn),(iy+nn),nn
* but now with extra hl or i[xy](15) for add-instruction
@@ -1836,21 +1062,23 @@ rd_r_add (const char **p)
int i;
const char *list[] = {
"ixl", "ixh", "iyl", "iyh", "b", "c", "d", "e", "h", "l",
- "(hl)", "a", "(ix", "(iy", "hl", "ix", "iy", NULL
+ "( hl )", "a", "( ix +)", "( iy +)", "hl", "ix", "iy", "*", NULL
};
- i = indx (p, list, 0);
- if (!i) // not in list ? assume "nn"
+ const char *nn;
+ i = indx (p, list, 0, &nn);
+ if (i == 18) /* expression */
{
- rd_byte (p, '\0');
+ readbyte = nn;
+ writebyte = 1;
return 7;
}
- if (i > 14) // 15,16,17
+ if (i > 14) /* hl, ix, iy */
{
if (i > 15)
indexed = 0xDD + 0x20 * (i - 16);
return addHL;
}
- if (i <= 4) // 8-bit access of ix/iy
+ if (i <= 4) /* i[xy][hl] */
{
indexed = 0xdd + 0x20 * (i > 2);
return 6 - (i & 1);
@@ -1858,8 +1086,8 @@ rd_r_add (const char **p)
i -= 4;
if (i < 9)
return i;
- indexed = 0xDD + 0x20 * (i - 9); // 16-bit access of ix/iy
- rd_index (p);
+ indexed = 0xDD + 0x20 * (i - 9); /* (i[xy] +) */
+ indexjmp = nn;
return 7;
}
@@ -1868,10 +1096,10 @@ static int
rd_rr_ (const char **p)
{
const char *list[] = { "bc", "de", "hl", "sp", NULL };
- return indx (p, list, 1);
+ return indx (p, list, 1, NULL);
}
-/* read bc,de,hl|ix|iy,sp. hl|ix|iy only if it is already indexed. */
+/* read bc,de,hl|ix|iy,sp. hl|ix|iy only if it is already indexed the same. */
static int
rd_rrxx (const char **p)
{
@@ -1881,11 +1109,11 @@ rd_rrxx (const char **p)
switch (indexed)
{
case 0xDD:
- return indx (p, listx, 1);
+ return indx (p, listx, 1, NULL);
case 0xFD:
- return indx (p, listy, 1);
+ return indx (p, listy, 1, NULL);
default:
- return indx (p, list, 1);
+ return indx (p, list, 1, NULL);
}
}
@@ -1896,13 +1124,15 @@ rd_r (const char **p)
{
int i;
const char *list[] = {
- "ixl", "ixh", "iyl", "iyh", "b", "c", "d", "e", "h", "l", "(hl)",
- "a", "(ix", "(iy", NULL
+ "ixl", "ixh", "iyl", "iyh", "b", "c", "d", "e", "h", "l", "( hl )",
+ "a", "( ix +)", "( iy +)", "*", NULL
};
- i = indx (p, list, 0);
- if (!i)
+ const char *nn;
+ i = indx (p, list, 0, &nn);
+ if (i == 15) /* expression */
{
- rd_byte (p, '\0');
+ readbyte = nn;
+ writebyte = 1;
return 7;
}
if (i <= 4)
@@ -1914,7 +1144,7 @@ rd_r (const char **p)
if (i < 9)
return i;
indexed = 0xDD + 0x20 * (i - 9);
- rd_index (p);
+ indexjmp = nn;
return 7;
}
@@ -1924,13 +1154,12 @@ rd_r_ (const char **p)
{
int i;
const char *list[] = {
- "b", "c", "d", "e", "h", "l", "(hl)", "a", "(ix", "(iy", NULL
+ "b", "c", "d", "e", "h", "l", "( hl )", "a", "( ix +)", "( iy +)", NULL
};
- i = indx (p, list, 1);
+ i = indx (p, list, 1, &indexjmp);
if (i < 9)
return i;
indexed = 0xDD + 0x20 * (i - 9);
- rd_index (p);
return 7;
}
@@ -1939,7 +1168,7 @@ static int
rd_0_7 (const char **p)
{
*p = delspc (*p);
- if (**p == 0 || **p == ';')
+ if (**p == 0)
return 0;
bitsetres = *p;
skipword (p, ',');
@@ -1951,7 +1180,7 @@ static int
rd_cc (const char **p)
{
const char *list[] = { "nz", "z", "nc", "c", "po", "pe", "p", "m", NULL };
- return indx (p, list, 0);
+ return indx (p, list, 0, NULL);
}
/* read long or short register, */
@@ -1961,16 +1190,15 @@ rd_r_rr (const char **p)
int i;
const char *list[] = {
"iy", "ix", "sp", "hl", "de", "bc", "", "b", "c", "d", "e", "h",
- "l", "(hl)", "a", "(ix", "(iy", NULL
+ "l", "( hl )", "a", "( ix +)", "( iy +)", NULL
};
- i = indx (p, list, 1);
+ i = indx (p, list, 1, &indexjmp);
if (!i)
return 0;
if (i < 16 && i > 2)
return 7 - i;
if (i > 15)
{
- rd_index (p);
indexed = 0xDD + (i - 16) * 0x20;
return -7;
}
@@ -1983,7 +1211,7 @@ static int
rd_hl (const char **p)
{
const char *list[] = { "hl", NULL };
- return indx (p, list, 1);
+ return indx (p, list, 1, NULL);
}
/* read hl, ix, or iy */
@@ -1992,17 +1220,11 @@ rd_hlx (const char **p)
{
int i;
const char *list[] = { "hl", "ix", "iy", NULL };
- i = indx (p, list, 1);
- switch (i)
- {
- case 0:
- return 0;
- case 1:
- return 1;
- default:
- indexed = 0xDD + 0x20 * (i - 2);
- return 1;
- }
+ i = indx (p, list, 1, NULL);
+ if (i < 2)
+ return i;
+ indexed = 0xDD + 0x20 * (i - 2);
+ return 1;
}
/* read af' */
@@ -2010,7 +1232,7 @@ static int
rd_af_ (const char **p)
{
const char *list[] = { "af'", NULL };
- return indx (p, list, 1);
+ return indx (p, list, 1, NULL);
}
/* read 0(1), 1(3), or 2(4) */
@@ -2018,7 +1240,7 @@ static int
rd_0_2 (const char **p)
{
const char *list[] = { "0", "", "1", "2", NULL };
- return indx (p, list, 1);
+ return indx (p, list, 1, NULL);
}
/* read argument of ld (hl), */
@@ -2026,11 +1248,11 @@ static int
rd_ld_hl (const char **p)
{
int i;
- const char *list[] = { "b", "c", "d", "e", "h", "l", "", "a", NULL };
- i = indx (p, list, 0);
- if (i)
+ const char *list[] = { "b", "c", "d", "e", "h", "l", "", "a", "*", NULL };
+ i = indx (p, list, 0, &readbyte);
+ if (i < 9)
return i;
- rd_byte (p, '\0');
+ writebyte = 1;
return 7;
}
@@ -2042,7 +1264,7 @@ rd_ld_nn (const char **p)
#define ld_nnA 6
int i;
const char *list[] = { "bc", "de", "", "sp", "hl", "a", "ix", "iy", NULL };
- i = indx (p, list, 1);
+ i = indx (p, list, 1, NULL);
if (i < 7)
return i;
indexed = 0xdd + 0x20 * (i == 8);
@@ -2058,45 +1280,54 @@ rd_lda (const char **p)
#define A_NN 11
int i;
const char *list[] = {
- "(sp)", "(iy", "(de)", "(bc)", "(ix", "b", "c", "d", "e", "h",
- "l", "(hl)", "a", "i", "r", "(", NULL
+ "( sp )", "( iy +)", "( de )", "( bc )", "( ix +)", "b", "c", "d", "e", "h",
+ "l", "( hl )", "a", "i", "r", "(*)", "*", NULL
};
- i = indx (p, list, 0);
+ const char *nn;
+ i = indx (p, list, 0, &nn);
if (i == 2 || i == 5)
{
indexed = (i == 2) ? 0xFD : 0xDD;
- rd_index (p);
+ indexjmp = nn;
return 7;
}
- if (!i)
+ if (i == 17)
{
- rd_byte (p, '\0');
+ readbyte = nn;
+ writebyte = 1;
return 7;
}
if (i == 16)
{
- rd_word (p, ')');
+ readword = nn;
}
return i - 5;
}
-/* read argument of b|c|d|e|h|l */
+/* read argument of ld b|c|d|e|h|l */
static int
rd_ldbcdehla (const char **p)
{
int i;
const char *list[] = {
- "b", "c", "d", "e", "h", "l", "(hl)", "a", "(ix", "(iy", "ixh",
- "ixl", "iyh", "iyl", NULL
+ "b", "c", "d", "e", "h", "l", "( hl )", "a", "( ix +)", "( iy +)", "ixh",
+ "ixl", "iyh", "iyl", "*", NULL
};
- i = indx (p, list, 0);
+ const char *nn;
+ i = indx (p, list, 0, &nn);
+ if (i == 15)
+ {
+ readbyte = nn;
+ writebyte = 1;
+ return 7;
+ }
if (i > 10)
{
int x;
x = 0xdd + 0x20 * (i > 12);
if (indexed && indexed != x)
{
- printerr ("illegal use of index registers\n");
+ printerr (1, "illegal use of index registers\n");
return 0;
}
indexed = x;
@@ -2106,17 +1337,14 @@ rd_ldbcdehla (const char **p)
{
if (indexed)
{
- printerr ("illegal use of index registers\n");
+ printerr (1, "illegal use of index registers\n");
return 0;
}
indexed = 0xDD + 0x20 * (i == 10);
- rd_index (p);
+ indexjmp = nn;
return 7;
}
- if (i)
- return i;
- rd_byte (p, '\0');
- return 7;
+ return i;
}
/* read nnnn, or (nnnn) */
@@ -2124,16 +1352,8 @@ static int
rd_nn_nn (const char **p)
{
#define _NN 1
- int i;
- const char *list[] = { "(", NULL };
- i = indx (p, list, 0);
- if (i)
- {
- rd_word (p, ')');
- return 1;
- }
- rd_word (p, '\0');
- return 0;
+ const char *list[] = { "(*)", "*", NULL };
+ return 2 - indx (p, list, 0, &readword);
}
/* read {HL|IX|IY},nnnn, or (nnnn) */
@@ -2143,20 +1363,16 @@ rd_sp (const char **p)
#define SPNN 0
#define SPHL 1
int i;
- const char *list[] = { "(", "ix", "iy", "hl", NULL };
- i = indx (p, list, 0);
- switch (i)
+ const char *list[] = { "hl", "ix", "iy", "(*)", "*", NULL };
+ const char *nn;
+ i = indx (p, list, 0, &nn);
+ if (i > 3)
{
- case 0:
- rd_word (p, '\0');
- return 0;
- case 1:
- rd_word (p, ')');
- return 2;
+ readword = nn;
+ return i == 4 ? 2 : 0;
}
- if (i == 4)
- return 1;
- indexed = 0xDD + 0x20 * (i - 2);
+ if (i != 1)
+ indexed = 0xDD + 0x20 * (i - 2);
return 1;
}
@@ -2169,19 +1385,25 @@ wrt_ref (int val, int type, int count)
case TYPE_RST:
if ((val & 0x38) != val)
{
- printerr ("incorrect RST value %d (0x%02x)\n", val, val);
+ printerr (1, "incorrect RST value %d (0x%02x)\n", val, val);
return;
}
write_one_byte (val + 0xC7, 1);
return;
case TYPE_ABSW:
+ if (val < -0x8000 || val >= 0x10000)
+ printerr (0, "word value %d (0x%x) truncated\n", val, val);
write_one_byte (val & 0xff, 1);
write_one_byte ((val >> 8) & 0xff, 1);
return;
case TYPE_ABSB:
+ if (val < -0x80 || val >= 0x100)
+ printerr (0, "byte value %d (0x%x) truncated\n", val, val);
write_one_byte (val & 0xff, 1);
return;
case TYPE_DS:
+ if (val < -0x80 || val >= 0x100)
+ printerr (0, "byte value %d (0x%x) truncated\n", val, val);
if (havelist)
{
fprintf (listfile, " 0x%02x...", val & 0xff);
@@ -2195,21 +1417,21 @@ wrt_ref (int val, int type, int count)
case TYPE_BSR:
if (val & ~7)
{
- printerr ("incorrect BIT/SET/RES value %d\n", val);
+ printerr (1, "incorrect BIT/SET/RES value %d\n", val);
return;
}
write_one_byte (0x08 * val + count, 1);
return;
case TYPE_RELB:
val -= count;
- if (val < -128 || val > 127)
+ if (val & 0xff80 && ~val & 0xff80)
{
- printerr ("relative jump out of range (%d)\n", val);
+ printerr (1, "relative jump out of range (%d)\n", val);
}
write_one_byte (val & 0xff, 1);
return;
case TYPE_LABEL:
- printerr ("bug in the assembler: trying to write label reference. "
+ printerr (1, "bug in the assembler: trying to write label reference. "
"Please report.\n");
return;
}
@@ -2225,13 +1447,13 @@ get_include_name (const char **ptr)
name = malloc (strlen (*ptr));
if (!name)
{
- printerr ("unable to allocate memory for filename %.*s\n",
+ printerr (1, "unable to allocate memory for filename %.*s\n",
strlen (*ptr) - 1, *ptr);
return NULL;
}
if (!**ptr)
{
- printerr ("include without filename\n");
+ printerr (1, "include without filename\n");
free (name);
return NULL;
}
@@ -2240,7 +1462,7 @@ get_include_name (const char **ptr)
{
if (!**ptr)
{
- printerr ("filename without closing quote (%c)\n", quote);
+ printerr (1, "filename without closing quote (%c)\n", quote);
free (name);
return NULL;
}
@@ -2274,7 +1496,7 @@ read_line (void)
buffer = malloc (size + 1);
if (!buffer)
{
- printerr ("out of memory reading line\n");
+ printerr (1, "out of memory reading line\n");
return 0;
}
memcpy (buffer, short_buffer, BUFLEN + 1);
@@ -2290,7 +1512,7 @@ read_line (void)
b = realloc (buffer, size + 1);
if (!b)
{
- printerr ("out of memory reading line\n");
+ printerr (1, "out of memory reading line\n");
return 0;
}
buffer = b;
@@ -2311,7 +1533,7 @@ read_line (void)
buffer = malloc (size);
if (!buffer)
{
- printerr ("out of memory\n");
+ printerr (1, "out of memory\n");
return 0;
}
pos = 0;
@@ -2348,14 +1570,14 @@ get_macro_args (const char **ptr, char ***ret_args, int allow_empty)
}
if (*ptr == c && !allow_empty)
{
- printerr ("empty macro argument\n");
+ printerr (1, "empty macro argument\n");
break;
}
++numargs;
args = realloc (*ret_args, sizeof (char *) * numargs);
if (!args)
{
- printerr ("out of memory\n");
+ printerr (1, "out of memory\n");
--numargs;
break;
}
@@ -2363,7 +1585,7 @@ get_macro_args (const char **ptr, char ***ret_args, int allow_empty)
args[numargs - 1] = malloc (*ptr - c + 1);
if (!args[numargs - 1])
{
- printerr ("out of memory\n");
+ printerr (1, "out of memory\n");
--numargs;
break;
}
@@ -2400,7 +1622,7 @@ assemble (void)
stack[sp].file = fopen (infile[file].name, "r");
if (!stack[sp].file)
{
- printerr ("unable to open %s. skipping\n", infile[file].name);
+ printerr (1, "unable to open %s. skipping\n", infile[file].name);
continue;
}
stack[sp].shouldclose = 1;
@@ -2421,7 +1643,7 @@ assemble (void)
ptr = delspc (ptr);
if (*ptr != 0)
{
- printerr ("ignoring junk at end of line: %s\n", ptr);
+ printerr (1, "junk at end of line: %s\n", ptr);
}
if (listdepth < 8)
tabs = 3;
@@ -2447,7 +1669,7 @@ assemble (void)
}
while (!read_line ())
{
- struct reference *ref;
+ struct reference *ref, *nextref;
struct label *next;
if (verbose >= 6)
fprintf (stderr, "finished reading file %s\n",
@@ -2464,11 +1686,25 @@ assemble (void)
/* the top of stack is about to be popped off, throwing all
* local labels out of scope. All references at this level
* which aren't computable are errors. */
- for (ref = firstreference; ref; ref = ref->next)
+ for (ref = firstreference; ref; ref = nextref)
{
+ nextref = ref->next;
compute_ref (ref, 1);
+ if (ref->done)
+ continue;
if (ref->level == sp)
- --ref->level;
+ if (!ref->level--)
+ {
+ printerr (1, "unable to resolve reference: %s\n",
+ ref->input);
+ if (ref->prev)
+ ref->prev->next = ref->next;
+ else
+ firstreference = ref->next;
+ if (ref->next)
+ ref->next->prev = ref->prev;
+ free (ref);
+ }
}
/* Ok, now junk all local labels of the top stack level */
for (l = stack[sp].labels; l; l = next)
@@ -2545,7 +1781,7 @@ assemble (void)
*current_line = malloc (sizeof (struct macro_line));
if (!*current_line)
{
- printerr ("out of memory\n");
+ printerr (1, "out of memory\n");
continue;
}
(*current_line)->next = NULL;
@@ -2553,7 +1789,7 @@ assemble (void)
(*current_line)->line = malloc (strlen (buffer) + 1);
if (!(*current_line)->line)
{
- printerr ("out of memory\n");
+ printerr (1, "out of memory\n");
free (*current_line);
*current_line = NULL;
continue;
@@ -2573,7 +1809,7 @@ assemble (void)
newarg = malloc (sizeof (struct macro_arg));
if (!newarg)
{
- printerr ("out of memory\n");
+ printerr (1, "out of memory\n");
break;
}
newarg->next = NULL;
@@ -2622,22 +1858,22 @@ assemble (void)
{
if (!(r = rd_rrxx (&ptr)))
break;
- wrtb (0x09 + 0x10 * --r); // ADD HL/IX/IY, qq
+ wrtb (0x09 + 0x10 * --r); /* ADD HL/IX/IY, qq */
break;
}
if (has_argument (&ptr))
{
if (r != A)
{
- printerr ("parse error before: %s\n", ptr);
+ printerr (1, "parse error before: %s\n", ptr);
break;
}
if (!(r = rd_r (&ptr)))
break;
- wrtb (0x80 + --r); // ADD A,r
+ wrtb (0x80 + --r); /* ADD A,r */
break;
}
- wrtb (0x80 + --r); // ADD r
+ wrtb (0x80 + --r); /* ADD r */
break;
case AND:
if (!(r = rd_r (&ptr)))
@@ -2647,6 +1883,7 @@ assemble (void)
case BIT:
if (!rd_0_7 (&ptr))
break;
+ rd_comma (&ptr);
if (!(r = rd_r_ (&ptr)))
break;
wrtb (0xCB);
@@ -2717,7 +1954,7 @@ assemble (void)
case EQU:
if (!lastlabel)
{
- printerr ("EQU without label\n");
+ printerr (1, "EQU without label\n");
break;
}
new_reference (ptr, TYPE_LABEL, 0, 0);
@@ -3021,6 +2258,7 @@ assemble (void)
case RES:
if (!rd_0_7 (&ptr))
break;
+ rd_comma (&ptr);
if (!(r = rd_r_ (&ptr)))
break;
wrtb (0xCB);
@@ -3111,6 +2349,7 @@ assemble (void)
case SET:
if (!rd_0_7 (&ptr))
break;
+ rd_comma (&ptr);
if (!(r = rd_r_ (&ptr)))
break;
wrtb (0xCB);
@@ -3143,11 +2382,11 @@ assemble (void)
case SUB:
if (!(r = rd_r (&ptr)))
break;
- if (has_argument (&ptr)) // SUB A,r ?
+ if (has_argument (&ptr)) /* SUB A,r ? */
{
if (r != A)
{
- printerr ("parse error before: %s\n", ptr);
+ printerr (1, "parse error before: %s\n", ptr);
break;
}
if (!(r = rd_r (&ptr)))
@@ -3165,13 +2404,12 @@ assemble (void)
case DEFM:
case DM:
ptr = delspc (ptr);
- have_quote = (*ptr == '"' || *ptr == '\'');
- if (!have_quote && !rd_byte (&ptr, ','))
- break;
- do
+ while (1)
{
+ have_quote = (*ptr == '"' || *ptr == '\'');
if (have_quote)
{
+ /* Read string. */
int quote = *ptr;
if (listfile)
{
@@ -3181,51 +2419,56 @@ assemble (void)
++ptr;
while (*ptr != quote)
{
- write_one_byte (rd_character (&ptr), 0);
+ write_one_byte (rd_character (&ptr, NULL, 1), 0);
if (*ptr == 0)
{
- printerr ("end of line in quoted " "string\n");
+ printerr (1, "end of line in quoted string\n");
break;
}
}
- if (!*ptr)
- break;
++ptr;
- ptr = delspc (ptr);
- if (!*ptr)
- break;
- if (*ptr++ != ',')
- {
- printerr ("expected end of line or ',' (not %c)\n",
- ptr[-1]);
- break;
- }
- ptr = delspc (ptr);
- continue;
}
- new_reference (readbyte, TYPE_ABSB, ',', 1);
+ else
+ {
+ /* Read expression. */
+ new_reference (ptr, TYPE_ABSB, ',', 1);
+ skipword (&ptr, ',');
+ }
ptr = delspc (ptr);
+ if (*ptr == ',')
+ {
+ ++ptr;
+ continue;
+ }
+ if (*ptr != 0)
+ printerr (1, "junk in byte definition: %s\n", ptr);
+ break;
}
- while ((have_quote = (*ptr == '"' || *ptr == '\''))
- || rd_byte (&ptr, ','));
- writebyte = 0;
break;
case DEFW:
case DW:
if (!(r = rd_word (&ptr, ',')))
- break;
- do
+ {
+ printerr (1, "No data for word definition\n");
+ break;
+ }
+ while (1)
{
new_reference (readword, TYPE_ABSW, ',', 1);
+ ptr = delspc (ptr);
+ if (*ptr != ',')
+ break;
+ ++ptr;
+ if (!(r = rd_word (&ptr, ',')))
+ printerr (1, "Missing expression in defw\n");
}
- while ((r = rd_word (&ptr, ',')));
break;
case DEFS:
case DS:
- r = rd_expr (&ptr, ',', NULL, sp);
+ r = rd_expr (&ptr, ',', NULL, sp, 1);
if (r < 0)
{
- printerr ("ds should have its first argument >=0"
+ printerr (1, "ds should have its first argument >=0"
" (not -0x%x)\n", -r);
break;
}
@@ -3253,12 +2496,12 @@ assemble (void)
file_ended = 1;
break;
case ORG:
- addr = rd_expr (&ptr, '\0', NULL, sp);
+ addr = rd_expr (&ptr, '\0', NULL, sp, 1) & 0xffff;
break;
case INCLUDE:
if (sp + 1 >= MAX_INCLUDE)
{
- printerr ("stack overflow (circular include?)");
+ printerr (1, "stack overflow (circular include?)");
if (verbose >= 5)
{
int x;
@@ -3277,7 +2520,7 @@ assemble (void)
name = malloc (sizeof (struct name) + strlen (nm));
if (!name)
{
- printerr ("out of memory while allocating name\n");
+ printerr (1, "out of memory while allocating name\n");
free (nm);
break;
}
@@ -3291,7 +2534,7 @@ assemble (void)
&stack[sp].dir, "r");
if (!stack[sp].file)
{
- printerr ("unable to open file %s\n", name->name);
+ printerr (1, "unable to open file %s\n", name->name);
free (name);
--sp;
break;
@@ -3314,7 +2557,7 @@ assemble (void)
incfile = open_include_file (name, NULL, "rb");
if (!incfile)
{
- printerr ("unable to open binary file %s\n", name);
+ printerr (1, "unable to open binary file %s\n", name);
free (name);
break;
}
@@ -3326,18 +2569,19 @@ assemble (void)
break;
if (num != fwrite (filebuffer, 1, num, outfile))
{
- printerr ("error including binary file %s: %s\n",
+ printerr (1, "error including binary file %s: %s\n",
name, strerror (errno));
break;
}
addr += num;
+ addr &= 0xffff;
}
fclose (incfile);
free (name);
break;
}
case IF:
- if (rd_expr (&ptr, '\0', NULL, sp))
+ if (rd_expr (&ptr, '\0', NULL, sp, 1))
ifcount++;
else
noifcount++;
@@ -3345,7 +2589,7 @@ assemble (void)
case ELSE:
if (ifcount == 0)
{
- printerr ("else without if\n");
+ printerr (1, "else without if\n");
break;
}
noifcount = 1;
@@ -3354,7 +2598,7 @@ assemble (void)
case ENDIF:
if (noifcount == 0 && ifcount == 0)
{
- printerr ("endif without if\n");
+ printerr (1, "endif without if\n");
break;
}
if (noifcount)
@@ -3365,12 +2609,12 @@ assemble (void)
case MACRO:
if (!lastlabel)
{
- printerr ("macro without label\n");
+ printerr (1, "macro without label\n");
break;
}
if (define_macro)
{
- printerr ("nested macro definition\n");
+ printerr (1, "nested macro definition\n");
break;
}
{
@@ -3379,20 +2623,20 @@ assemble (void)
{
if (strcmp (m->name, lastlabel->name) == 0)
{
- printerr ("duplicate macro definition\n");
+ printerr (1, "duplicate macro definition\n");
break;
}
}
m = malloc (sizeof (struct macro));
if (!m)
{
- printerr ("out of memory\n");
+ printerr (1, "out of memory\n");
break;
}
m->name = malloc (strlen (lastlabel->name) + 1);
if (!m->name)
{
- printerr ("out of memory\n");
+ printerr (1, "out of memory\n");
free (m);
break;
}
@@ -3413,11 +2657,11 @@ assemble (void)
break;
case ENDM:
if (stack[sp].file)
- printerr ("endm outside macro definition\n");
+ printerr (1, "endm outside macro definition\n");
break;
case SEEK:
{
- unsigned int seekaddr = rd_expr (&ptr, '\0', NULL, sp);
+ unsigned int seekaddr = rd_expr (&ptr, '\0', NULL, sp, 1);
if (verbose >= 2)
{
fprintf (stderr, "%s%s:%d: ",
@@ -3439,7 +2683,7 @@ assemble (void)
unsigned numargs;
if (sp + 1 >= MAX_INCLUDE)
{
- printerr ("stack overflow (circular include?)\n");
+ printerr (1, "stack overflow (circular include?)\n");
if (verbose >= 5)
{
int x;
@@ -3458,7 +2702,7 @@ assemble (void)
if (numargs != m->numargs)
{
unsigned a;
- printerr ("invalid number of arguments for macro "
+ printerr (1, "invalid number of arguments for macro "
"(is %d, must be %d)\n", numargs,
m->numargs);
for (a = 0; a < numargs; ++a)
@@ -3479,13 +2723,13 @@ assemble (void)
if (m)
break;
}
- printerr ("command or comment expected (was %s)\n", ptr);
+ printerr (1, "command or comment expected (was %s)\n", ptr);
}
}
}
if (ifcount || noifcount)
{
- printerr ("reached EOF at IF level %d\n", ifcount + noifcount);
+ printerr (1, "reached EOF at IF level %d\n", ifcount + noifcount);
}
if (havelist)
{
@@ -3494,6 +2738,8 @@ assemble (void)
{
struct reference *next;
struct reference *tmp;
+ /* Add a stack frame for error reporting. */
+ ++sp;
for (tmp = firstreference; tmp; tmp = next)
{
int ref;
@@ -3501,8 +2747,14 @@ assemble (void)
fseek (outfile, tmp->oseekpos, SEEK_SET);
if (havelist)
fseek (listfile, tmp->lseekpos, SEEK_SET);
+ stack[sp].name = tmp->file;
+ stack[sp].dir = tmp->dir;
+ stack[sp].line = tmp->line;
ref = compute_ref (tmp, 0);
wrt_ref (ref, tmp->type, tmp->count);
+ if (tmp->dir)
+ free (tmp->dir);
+ free (tmp->file);
free (tmp);
}
}
diff --git a/tools/z80asm/z80asm.h b/tools/z80asm/z80asm.h
new file mode 100644
index 0000000..af398ca
--- /dev/null
+++ b/tools/z80asm/z80asm.h
@@ -0,0 +1,247 @@
+/* Z80 assembler by shevek
+
+ Copyright (C) 2002-2007 Bas Wijnen <shevek@fmf.nl>
+ Copyright (C) 2005 Jan Wilmans <jw@dds.nl>
+
+ This file is part of z80asm.
+
+ Z80asm is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ Z80asm is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Z80ASM_H
+#define Z80ASM_H
+
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <getopt.h>
+#include <unistd.h>
+
+/* defines which are not function-specific */
+#ifndef BUFLEN
+#define BUFLEN 300 /* size of readbuffer for file i/o */
+#endif
+
+#ifndef MAX_INCLUDE
+#define MAX_INCLUDE 200 /* stack size for include command and macros */
+#endif
+
+/* types */
+/* mnemonics. THESE MUST BE IN THE SAME ORDER AS const char *mnemonic[]! */
+enum mnemonic
+{
+ CALL, CPDR, CPIR, DJNZ, HALT, INDR, INIR, LDDR, LDIR, OTDR, OTIR, OUTD,
+ OUTI, PUSH, RETI, RETN, RLCA, RRCA, DEFB, DEFW, DEFS, DEFM,
+ ADC, ADD, AND, BIT, CCF, CPD, CPI, CPL, DAA, DEC, EQU, EXX, INC, IND, INI,
+ LDD, LDI, NEG, NOP, OUT, POP, RES, RET, RLA, RLC, RLD, RRA, RRC, RRD, RST,
+ SBC, SCF, SET, SLA, SLL, SLI, SRA, SRL, SUB, XOR, ORG,
+ CP, DI, EI, EX, IM, IN, JP, JR, LD, OR, RL, RR, DB, DW, DS, DM,
+ INCLUDE, INCBIN, IF, ELSE, ENDIF, END, MACRO, ENDM, SEEK
+};
+
+/* types of reference */
+enum reftype
+{
+ TYPE_BSR, /* bit value (0-7) for bit, set and res */
+ TYPE_DS, /* ds reference (byte count and value) */
+ TYPE_RST, /* rst reference: val & 0x38 == val */
+ TYPE_ABSW, /* absolute word (2 bytes) */
+ TYPE_ABSB, /* absolute byte */
+ TYPE_RELB, /* relative byte */
+ TYPE_LABEL /* equ expression */
+};
+
+/* filetypes that can appear on the input. object files are on the todo list */
+enum filetype
+{
+ FILETYPE_ASM
+};
+
+/* labels (will be malloced) */
+struct label
+{
+ struct label *next, *prev; /* linked list */
+ int value; /* value */
+ int valid; /* if it is valid, or not yet computed */
+ int busy; /* if it is currently being computed */
+ struct reference *ref; /* mallocced memory to value for computation */
+ char name[1]; /* space with name in it */
+};
+
+/* files that were given on the commandline */
+struct infile
+{
+ const char *name;
+ enum filetype type;
+};
+
+/* filenames must be remembered for references */
+struct name
+{
+ struct name *next, *prev;
+ char name[1];
+};
+
+/* the include path */
+struct includedir
+{
+ struct includedir *next;
+ char name[1];
+};
+
+/* macro stuff */
+struct macro_arg
+{
+ struct macro_arg *next;
+ unsigned pos;
+ unsigned which;
+};
+
+struct macro_line
+{
+ struct macro_line *next;
+ char *line;
+ struct macro_arg *args;
+};
+
+struct macro
+{
+ struct macro *next;
+ char *name;
+ unsigned numargs;
+ char **args;
+ struct macro_line *lines;
+};
+
+/* elements on the context stack */
+struct stack
+{
+ const char *name; /* filename (for errors). may be malloced */
+ struct includedir *dir; /* directory where it comes from, if any */
+ FILE *file; /* the handle */
+ int line; /* the current line number (for errors) */
+ int shouldclose; /* if this file should be closed when done */
+ struct label *labels; /* local labels for this stack level */
+ /* if file is NULL, this is a macro entry */
+ struct macro *macro;
+ struct macro_line *macro_line;
+ char **macro_args; /* arguments given to the macro */
+};
+
+/* these structs will be malloced for each reference */
+struct reference
+{
+ struct reference *next, *prev;
+ enum reftype type; /* type of reference */
+ long oseekpos; /* position in outfile for data */
+ long lseekpos; /* position in listfile for data */
+ char delimiter; /* delimiter for parser */
+ int addr, line; /* address and line of reference */
+ int baseaddr; /* address at start of line of reference */
+ int comma; /* comma when reference was set */
+ int count; /* only for ds: number of items */
+ int infile; /* index in infile[], current infile */
+ int done; /* if this reference has been computed */
+ int computed_value; /* value (only valid if done = true) */
+ int level; /* maximum stack level of labels to use */
+ struct includedir *dir; /* dirname of file (for error reporting) */
+ char *file; /* filename (for error reporting) */
+ char input[1]; /* variable size buffer containing formula */
+};
+
+/* global variables */
+/* mnemonics, used as argument to indx() in assemble */
+extern const char *mnemonics[];
+
+/* linked lists */
+extern struct reference *firstreference;
+extern struct label *firstlabel, *lastlabel;
+extern struct name *firstname;
+extern struct includedir *firstincludedir;
+extern struct macro *firstmacro;
+
+/* files */
+extern FILE *realoutputfile, *outfile, *reallistfile, *listfile, *labelfile;
+extern const char *realoutputfilename;
+extern const char *labelfilename;
+extern struct infile *infile;
+/* prefix for labels in labelfile */
+extern const char *labelprefix;
+/* bools to see if files are opened */
+extern int havelist, label;
+/* number of infiles in array */
+extern int infilecount;
+
+/* number of errors seen so far */
+extern int errors;
+
+/* current line, address and file */
+extern int addr, file;
+/* current number of characters in list file, for indentation */
+extern int listdepth;
+
+/* use readbyte instead of (hl) if writebyte is true */
+extern int writebyte;
+extern const char *readbyte;
+/* variables which are filled by rd_* functions and used later,
+ * like readbyte */
+extern const char *readword, *indexjmp, *bitsetres;
+
+/* 0, 0xdd or 0xfd depening on which index prefix should be given */
+extern int indexed;
+
+/* increased for every -v option on the command line */
+extern int verbose;
+
+/* read commas after indx() if comma > 1. increase for every call */
+extern int comma;
+
+/* address at start of line (for references) */
+extern int baseaddr;
+
+/* set by readword and readbyte, used for new_reference */
+extern char mem_delimiter;
+
+/* line currently being parsed */
+extern char *buffer;
+
+/* if a macro is currently being defined */
+extern int define_macro;
+
+/* file (and macro) stack */
+extern int sp;
+extern struct stack stack[MAX_INCLUDE]; /* maximum level of includes */
+
+/* Produce output even with errors. */
+extern int use_force;
+
+/* print an error message, including current line and file */
+void printerr (int error, const char *fmt, ...);
+
+/* skip over spaces in string */
+const char *delspc (const char *ptr);
+
+int rd_expr (const char **p, char delimiter, int *valid, int level,
+ int print_errors);
+int rd_label (const char **p, int *exists, struct label **previous, int level,
+ int print_errors);
+int rd_character (const char **p, int *valid, int print_errors);
+
+int compute_ref (struct reference *ref, int allow_invalid);
+
+#endif