]> git.pld-linux.org Git - packages/binutils.git/blame - binutils-gasp.patch
- 2.13.90.0.18
[packages/binutils.git] / binutils-gasp.patch
CommitLineData
2859501d
JB
1diff -Nur binutils-2.13.90.0.18.orig/gas/Makefile.am binutils-2.13.90.0.18/gas/Makefile.am
2--- binutils-2.13.90.0.18.orig/gas/Makefile.am Sun Feb 2 03:21:17 2003
3+++ binutils-2.13.90.0.18/gas/Makefile.am Sun Feb 2 12:25:10 2003
4@@ -197,7 +197,7 @@
5 symbols.c \
6 write.c
7
8-CFILES = $(GAS_CFILES) itbl-ops.c
9+CFILES = $(GAS_CFILES) gasp.c itbl-ops.c
10
11 HFILES = \
12 as.h \
13@@ -452,7 +452,8 @@
14
15 # Note: GASP is now deprecated and has been removed. It is still
16 # available in the CVS archive or older binutils releases if it is needed.
17-noinst_PROGRAMS = as-new
18+# ...and it is needed for few packages in distribution.
19+noinst_PROGRAMS = as-new gasp-new
20 noinst_SCRIPTS = $(GDBINIT)
21 EXTRA_SCRIPTS = .gdbinit
22
23@@ -515,6 +516,10 @@
24 as.h asintl.h bignum.h bit_fix.h config.h emul.h expr.h flonum.h \
25 frags.h hash.h listing.h obj.h read.h symbols.h tc.h write.h
26
27+gasp_new_SOURCES = gasp.c macro.c sb.c hash.c
28+gasp_new_LDADD = ../libiberty/libiberty.a $(INTLLIBS)
29+gasp_new_DEPENDENCIES = ../libiberty/libiberty.a $(INTLDEPS)
30+
31 EXPECT = `if [ -f $${rootme}/../expect/expect ] ; then \
32 echo $${rootme}/../expect/expect ; \
33 else echo expect ; fi`
34@@ -2416,6 +2421,8 @@
35 $(INCDIR)/obstack.h subsegs.h struc-symbol.h
36 write.o: write.c $(INCDIR)/symcat.h subsegs.h $(INCDIR)/obstack.h \
37 output-file.h dwarf2dbg.h
38+gasp.o: gasp.c $(INCDIR)/getopt.h $(INCDIR)/safe-ctype.h \
39+ sb.h macro.h $(INCDIR)/xregex.h $(INCDIR)/xregex2.h
40 itbl-ops.o: itbl-ops.c itbl-ops.h $(INCDIR)/symcat.h
41 e-crisaout.o: $(srcdir)/config/e-crisaout.c $(INCDIR)/symcat.h \
42 emul-target.h
43diff -Nur binutils-2.13.90.0.18.orig/gas/Makefile.in binutils-2.13.90.0.18/gas/Makefile.in
44--- binutils-2.13.90.0.18.orig/gas/Makefile.in Sun Feb 2 03:21:17 2003
45+++ binutils-2.13.90.0.18/gas/Makefile.in Sun Feb 2 12:29:17 2003
46@@ -313,7 +313,7 @@
47 write.c
48
49
50-CFILES = $(GAS_CFILES) itbl-ops.c
51+CFILES = $(GAS_CFILES) gasp.c itbl-ops.c
52
53 HFILES = \
54 as.h \
55@@ -575,7 +575,8 @@
56
57 # Note: GASP is now deprecated and has been removed. It is still
58 # available in the CVS archive or older binutils releases if it is needed.
59-noinst_PROGRAMS = as-new
60+# ...and it is needed for few packages in distribution.
61+noinst_PROGRAMS = as-new gasp-new
62 noinst_SCRIPTS = $(GDBINIT)
63 EXTRA_SCRIPTS = .gdbinit
64
65@@ -624,6 +625,10 @@
66 $(extra_objects) $(GASLIBS) $(INTLDEPS)
67
68
69+gasp_new_SOURCES = gasp.c macro.c sb.c hash.c
70+gasp_new_LDADD = ../libiberty/libiberty.a $(INTLLIBS)
71+gasp_new_DEPENDENCIES = ../libiberty/libiberty.a $(INTLDEPS)
72+
73 EXPECT = `if [ -f $${rootme}/../expect/expect ] ; then \
74 echo $${rootme}/../expect/expect ; \
75 else echo expect ; fi`
76@@ -2431,7 +2436,7 @@
77 mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
78 CONFIG_HEADER = config.h
79 CONFIG_CLEAN_FILES = ${GDBINIT}
80-noinst_PROGRAMS = as-new$(EXEEXT)
81+noinst_PROGRAMS = as-new$(EXEEXT) gasp-new$(EXEEXT)
82 PROGRAMS = $(noinst_PROGRAMS)
83
84
85@@ -2439,6 +2444,9 @@
86 CPPFLAGS = @CPPFLAGS@
87 LDFLAGS = @LDFLAGS@
88 LIBS = @LIBS@
89+gasp_new_OBJECTS = gasp.$(OBJEXT) macro.$(OBJEXT) sb.$(OBJEXT) \
90+hash.$(OBJEXT)
91+gasp_new_LDFLAGS =
92 itbl_test_OBJECTS = itbl-parse.$(OBJEXT) itbl-lex.$(OBJEXT)
93 itbl_test_DEPENDENCIES = itbl-tops.o itbl-test.o \
94 ../libiberty/libiberty.a
95@@ -2472,8 +2480,8 @@
96
97 TAR = tar
98 GZIP_ENV = --best
99-SOURCES = $(itbl_test_SOURCES) $(as_new_SOURCES) $(EXTRA_as_new_SOURCES)
100-OBJECTS = $(itbl_test_OBJECTS) $(as_new_OBJECTS)
101+SOURCES = $(gasp_new_SOURCES) $(itbl_test_SOURCES) $(as_new_SOURCES) $(EXTRA_as_new_SOURCES)
102+OBJECTS = $(gasp_new_OBJECTS) $(itbl_test_OBJECTS) $(as_new_OBJECTS)
103
104 all: all-redirect
105 .SUFFIXES:
106@@ -2576,6 +2584,10 @@
107
108 maintainer-clean-libtool:
109
110+gasp-new$(EXEEXT): $(gasp_new_OBJECTS) $(gasp_new_DEPENDENCIES)
111+ @rm -f gasp-new$(EXEEXT)
112+ $(LINK) $(gasp_new_LDFLAGS) $(gasp_new_OBJECTS) $(gasp_new_LDADD) $(LIBS)
113+
114 itbl-test$(EXEEXT): $(itbl_test_OBJECTS) $(itbl_test_DEPENDENCIES)
115 @rm -f itbl-test$(EXEEXT)
116 $(LINK) $(itbl_test_LDFLAGS) $(itbl_test_OBJECTS) $(itbl_test_LDADD) $(LIBS)
117@@ -3326,6 +3338,8 @@
118 $(INCDIR)/obstack.h subsegs.h struc-symbol.h
119 write.o: write.c $(INCDIR)/symcat.h subsegs.h $(INCDIR)/obstack.h \
120 output-file.h dwarf2dbg.h
121+gasp.o: gasp.c $(INCDIR)/getopt.h $(INCDIR)/safe-ctype.h \
122+ sb.h macro.h $(INCDIR)/xregex.h $(INCDIR)/xregex2.h
123 itbl-ops.o: itbl-ops.c itbl-ops.h $(INCDIR)/symcat.h
124 e-crisaout.o: $(srcdir)/config/e-crisaout.c $(INCDIR)/symcat.h \
125 emul-target.h
126diff -Nur binutils-2.13.90.0.18.orig/gas/doc/Makefile.am binutils-2.13.90.0.18/gas/doc/Makefile.am
127--- binutils-2.13.90.0.18.orig/gas/doc/Makefile.am Sun Feb 2 03:21:17 2003
128+++ binutils-2.13.90.0.18/gas/doc/Makefile.am Sun Feb 2 12:35:43 2003
129@@ -15,7 +15,7 @@
130
131 man_MANS = as.1
132
133-info_TEXINFOS = as.texinfo
134+info_TEXINFOS = as.texinfo gasp.texi
135
136 asconfig.texi: $(CONFIG).texi
137 rm -f asconfig.texi
138diff -Nur binutils-2.13.90.0.18.orig/gas/doc/Makefile.in binutils-2.13.90.0.18/gas/doc/Makefile.in
139--- binutils-2.13.90.0.18.orig/gas/doc/Makefile.in Sun Feb 2 03:21:17 2003
140+++ binutils-2.13.90.0.18/gas/doc/Makefile.in Sun Feb 2 12:36:47 2003
141@@ -133,7 +133,7 @@
142
143 man_MANS = as.1
144
145-info_TEXINFOS = as.texinfo
146+info_TEXINFOS = as.texinfo gasp.texi
147
148 CPU_DOCS = \
149 c-a29k.texi \
150@@ -182,9 +182,9 @@
151 CONFIG_CLEAN_FILES =
152 TEXI2DVI = `if test -f $(top_srcdir)/../texinfo/util/texi2dvi; then echo $(top_srcdir)/../texinfo/util/texi2dvi; else echo texi2dvi; fi`
153 TEXINFO_TEX = $(top_srcdir)/../texinfo/texinfo.tex
154-INFO_DEPS = as.info
155+INFO_DEPS = as.info gasp.info
156 DVIS = as.dvi
157-TEXINFOS = as.texinfo
158+TEXINFOS = as.texinfo gasp.texi
159 man1dir = $(mandir)/man1
160 MANS = $(man_MANS)
161
162diff -Nur binutils-2.13.90.0.18.orig/gas/doc/gasp.texi binutils-2.13.90.0.18/gas/doc/gasp.texi
163--- binutils-2.13.90.0.18.orig/gas/doc/gasp.texi Thu Jan 1 01:00:00 1970
164+++ binutils-2.13.90.0.18/gas/doc/gasp.texi Wed Oct 30 05:09:13 2002
165@@ -0,0 +1,1456 @@
166+\input texinfo @c -*- Texinfo -*-
167+@setfilename gasp.info
168+@c
169+@c This file documents the assembly preprocessor "GASP"
170+@c
171+@c Copyright 1994, 1995, 2000, 2002 Free Software Foundation, Inc.
172+@c
173+@c Permission is granted to copy, distribute and/or modify this document
174+@c under the terms of the GNU Free Documentation License, Version 1.1
175+@c or any later version published by the Free Software Foundation;
176+@c with no Invariant Sections, with no Front-Cover Texts, and with no
177+@c Back-Cover Texts. A copy of the license is included in the
178+@c section entitled "GNU Free Documentation License".
179+
180+@ifinfo
181+@format
182+START-INFO-DIR-ENTRY
183+* gasp: (gasp). The GNU Assembler Preprocessor
184+END-INFO-DIR-ENTRY
185+@end format
186+@end ifinfo
187+
188+@syncodeindex ky cp
189+@syncodeindex fn cp
190+
191+@finalout
192+@setchapternewpage odd
193+@settitle GASP
194+@titlepage
195+@c FIXME boring title
196+@title GASP, an assembly preprocessor
197+@subtitle for GASP version 1
198+@sp 1
199+@subtitle March 1994
200+@author Roland Pesch
201+@page
202+
203+@tex
204+{\parskip=0pt \hfill Cygnus Support\par
205+}
206+@end tex
207+
208+@vskip 0pt plus 1filll
209+Copyright @copyright{} 1994, 1995, 2000, 2002 Free Software Foundation, Inc.
210+
211+ Permission is granted to copy, distribute and/or modify this document
212+ under the terms of the GNU Free Documentation License, Version 1.1
213+ or any later version published by the Free Software Foundation;
214+ with no Invariant Sections, with no Front-Cover Texts, and with no
215+ Back-Cover Texts. A copy of the license is included in the
216+ section entitled "GNU Free Documentation License".
217+
218+@end titlepage
219+
220+@ifinfo
221+Copyright @copyright{} 1994, 1995, 2000, 2002 Free Software Foundation, Inc.
222+
223+@ignore
224+Permission is granted to process this file through TeX and print the
225+results, provided the printed document carries a copying permission
226+notice identical to this one except for the removal of this paragraph
227+(this paragraph not being relevant to the printed manual).
228+@end ignore
229+
230+ Permission is granted to copy, distribute and/or modify this document
231+ under the terms of the GNU Free Documentation License, Version 1.1
232+ or any later version published by the Free Software Foundation;
233+ with no Invariant Sections, with no Front-Cover Texts, and with no
234+ Back-Cover Texts. A copy of the license is included in the
235+ section entitled "GNU Free Documentation License".
236+
237+
238+@node Top
239+@top GASP
240+
241+GASP is a preprocessor for assembly programs.
242+
243+This file describes version 1 of GASP.
244+
245+Steve Chamberlain wrote GASP; Roland Pesch wrote this manual.
246+
247+@menu
248+* Overview:: What is GASP?
249+* Invoking GASP:: Command line options.
250+* Commands:: Preprocessor commands.
251+* GNU Free Documentation License:: GNU Free Documentation License
252+* Index:: Index.
253+@end menu
254+@end ifinfo
255+
256+@node Overview
257+@chapter What is GASP?
258+
259+The primary purpose of the @sc{gnu} assembler is to assemble the output of
260+other programs---notably compilers. When you have to hand-code
261+specialized routines in assembly, that means the @sc{gnu} assembler is
262+an unfriendly processor: it has no directives for macros, conditionals,
263+or many other conveniences that you might expect.
264+
265+In some cases you can simply use the C preprocessor, or a generalized
266+preprocessor like @sc{m4}; but this can be awkward, since none of these
267+things are designed with assembly in mind.
268+
269+@sc{gasp} fills this need. It is expressly designed to provide the
270+facilities you need with hand-coded assembly code. Implementing it as a
271+preprocessor, rather than part of the assembler, allows the maximum
272+flexibility: you can use it with hand-coded assembly, without paying a
273+penalty of added complexity in the assembler you use for compiler
274+output.
275+
276+@emph{Note} The use of @sc{gasp} has now been deprecated. Anything
277+that it could do can now be done by the macro facilities built into
278+@sc{gas} itself. At some point in the future the @sc{gasp} sources will
279+be removed entirely from the binutils distribution.
280+
281+Here is a small example to give the flavor of @sc{gasp}. This input to
282+@sc{gasp}
283+
284+@cartouche
285+@example
286+ .MACRO saveregs from=8 to=14
287+count .ASSIGNA \from
288+ ! save r\from..r\to
289+ .AWHILE \&count LE \to
290+ mov r\&count,@@-sp
291+count .ASSIGNA \&count + 1
292+ .AENDW
293+ .ENDM
294+
295+ saveregs from=12
296+
297+bar: mov #H'dead+10,r0
298+foo .SDATAC "hello"<10>
299+ .END
300+@end example
301+@end cartouche
302+
303+@noindent
304+generates this assembly program:
305+
306+@cartouche
307+@example
308+ ! save r12..r14
309+ mov r12,@@-sp
310+ mov r13,@@-sp
311+ mov r14,@@-sp
312+
313+bar: mov #57005+10,r0
314+foo: .byte 6,104,101,108,108,111,10
315+@end example
316+@end cartouche
317+
318+@node Invoking GASP
319+@chapter Command Line Options
320+
321+@c FIXME! Or is there a simpler way, calling from GAS option?
322+The simplest way to use @sc{gasp} is to run it as a filter and assemble
323+its output. In Unix and its ilk, you can do this, for example:
324+
325+@c FIXME! GASP filename suffix convention?
326+@example
327+$ gasp prog.asm | as -o prog.o
328+@end example
329+
330+Naturally, there are also a few command-line options to allow you to
331+request variations on this basic theme. Here is the full set of
332+possibilities for the @sc{gasp} command line.
333+
334+@example
335+gasp [ -a | --alternate ]
336+ [ -c @var{char} | --commentchar @var{char} ]
337+ [ -d | --debug ] [ -h | --help ] [ -M | --mri ]
338+ [ -o @var{outfile} | --output @var{outfile} ]
339+ [ -p | --print ] [ -s | --copysource ]
340+ [ -u | --unreasonable ] [ -v | --version ]
341+ @var{infile} @dots{}
342+@end example
343+
344+@ftable @code
345+@item @var{infile} @dots{}
346+@c FIXME! Why not stdin as default infile?
347+The input file names. You must specify at least one input file; if you
348+specify more, @sc{gasp} preprocesses them all, concatenating the output
349+in the order you list the @var{infile} arguments.
350+
351+Mark the end of each input file with the preprocessor command
352+@code{.END}. @xref{Other Commands,, Miscellaneous commands}.
353+
354+@item -a
355+@itemx --alternate
356+Use alternative macro syntax. @xref{Alternate,, Alternate macro
357+syntax}, for a discussion of how this syntax differs from the default
358+@sc{gasp} syntax.
359+
360+@cindex comment character, changing
361+@cindex semicolon, as comment
362+@cindex exclamation mark, as comment
363+@cindex shriek, as comment
364+@cindex bang, as comment
365+@cindex @code{!} default comment char
366+@cindex @code{;} as comment char
367+@item -c '@var{char}'
368+@itemx --commentchar '@var{char}'
369+Use @var{char} as the comment character. The default comment character
370+is @samp{!}. For example, to use a semicolon as the comment character,
371+specify @w{@samp{-c ';'}} on the @sc{gasp} command line. Since
372+assembler command characters often have special significance to command
373+shells, it is a good idea to quote or escape @var{char} when you specify
374+a comment character.
375+
376+For the sake of simplicity, all examples in this manual use the default
377+comment character @samp{!}.
378+
379+@item -d
380+@itemx --debug
381+Show debugging statistics. In this version of @sc{gasp}, this option
382+produces statistics about the string buffers that @sc{gasp} allocates
383+internally. For each defined buffersize @var{s}, @sc{gasp} shows the
384+number of strings @var{n} that it allocated, with a line like this:
385+
386+@example
387+strings size @var{s} : @var{n}
388+@end example
389+
390+@noindent
391+@sc{gasp} displays these statistics on the standard error stream, when
392+done preprocessing.
393+
394+@item -h
395+@itemx --help
396+Display a summary of the @sc{gasp} command line options.
397+
398+@item -M
399+@itemx --mri
400+Use MRI compatibility mode. Using this option causes @sc{gasp} to
401+accept the syntax and pseudo-ops used by the Microtec Research
402+@code{ASM68K} assembler.
403+
404+@item -o @var{outfile}
405+@itemx --output @var{outfile}
406+Write the output in a file called @var{outfile}. If you do not use the
407+@samp{-o} option, @sc{gasp} writes its output on the standard output
408+stream.
409+
410+@item -p
411+@itemx --print
412+Print line numbers. @sc{gasp} obeys this option @emph{only} if you also
413+specify @samp{-s} to copy source lines to its output. With @samp{-s
414+-p}, @sc{gasp} displays the line number of each source line copied
415+(immediately after the comment character at the beginning of the line).
416+
417+@item -s
418+@itemx --copysource
419+Copy the source lines to the output file. Use this option
420+to see the effect of each preprocessor line on the @sc{gasp} output.
421+@sc{gasp} places a comment character (@samp{!} by default) at
422+the beginning of each source line it copies, so that you can use this
423+option and still assemble the result.
424+
425+@item -u
426+@itemx --unreasonable
427+Bypass ``unreasonable expansion'' limit. Since you can define @sc{gasp}
428+macros inside other macro definitions, the preprocessor normally
429+includes a sanity check. If your program requires more than 1,000
430+nested expansions, @sc{gasp} normally exits with an error message. Use
431+this option to turn off this check, allowing unlimited nested
432+expansions.
433+
434+@item -v
435+@itemx --version
436+Display the @sc{gasp} version number.
437+@end ftable
438+
439+@node Commands
440+@chapter Preprocessor Commands
441+
442+@sc{gasp} commands have a straightforward syntax that fits in well with
443+assembly conventions. In general, a command extends for a line, and may
444+have up to three fields: an optional label, the command itself, and
445+optional arguments to the command. You can write commands in upper or
446+lower case, though this manual shows them in upper case. @xref{Syntax
447+Details,, Details of the GASP syntax}, for more information.
448+
449+@menu
450+* Conditionals::
451+* Loops::
452+* Variables::
453+* Macros::
454+* Data::
455+* Listings::
456+* Other Commands::
457+* Syntax Details::
458+* Alternate::
459+@end menu
460+
461+@node Conditionals
462+@section Conditional assembly
463+
464+The conditional-assembly directives allow you to include or exclude
465+portions of an assembly depending on how a pair of expressions, or a
466+pair of strings, compare.
467+
468+The overall structure of conditionals is familiar from many other
469+contexts. @code{.AIF} marks the start of a conditional, and precedes
470+assembly for the case when the condition is true. An optional
471+@code{.AELSE} precedes assembly for the converse case, and an
472+@code{.AENDI} marks the end of the condition.
473+
474+@c FIXME! Why doesn't -u turn off this check?
475+You may nest conditionals up to a depth of 100; @sc{gasp} rejects
476+nesting beyond that, because it may indicate a bug in your macro
477+structure.
478+
479+@c FIXME! Why isn't there something like cpp's -D option? Conditionals
480+@c would be much more useful if there were.
481+Conditionals are primarily useful inside macro definitions, where you
482+often need different effects depending on argument values.
483+@xref{Macros,, Defining your own directives}, for details about defining
484+macros.
485+
486+@ftable @code
487+@item .AIF @var{expra} @var{cmp} @var{exprb}
488+@itemx .AIF "@var{stra}" @var{cmp} "@var{strb}"
489+
490+The governing condition goes on the same line as the @code{.AIF}
491+preprocessor command. You may compare either two strings, or two
492+expressions.
493+
494+When you compare strings, only two conditional @var{cmp} comparison
495+operators are available: @samp{EQ} (true if @var{stra} and @var{strb}
496+are identical), and @samp{NE} (the opposite).
497+
498+When you compare two expressions, @emph{both expressions must be
499+absolute} (@pxref{Expressions,, Arithmetic expressions in GASP}). You
500+can use these @var{cmp} comparison operators with expressions:
501+
502+@ftable @code
503+@item EQ
504+Are @var{expra} and @var{exprb} equal? (For strings, are @var{stra} and
505+@var{strb} identical?)
506+
507+@item NE
508+Are @var{expra} and @var{exprb} different? (For strings, are @var{stra}
509+and @var{strb} different?
510+
511+@item LT
512+Is @var{expra} less than @var{exprb}? (Not allowed for strings.)
513+
514+@item LE
515+Is @var{expra} less than or equal to @var{exprb}? (Not allowed for strings.)
516+
517+@item GT
518+Is @var{expra} greater than @var{exprb}? (Not allowed for strings.)
519+
520+@item GE
521+Is @var{expra} greater than or equal to @var{exprb}? (Not allowed for
522+strings.)
523+@end ftable
524+
525+@item .AELSE
526+Marks the start of assembly code to be included if the condition fails.
527+Optional, and only allowed within a conditional (between @code{.AIF} and
528+@code{.AENDI}).
529+
530+@item .AENDI
531+Marks the end of a conditional assembly.
532+@end ftable
533+
534+@node Loops
535+@section Repetitive sections of assembly
536+
537+Two preprocessor directives allow you to repeatedly issue copies of the
538+same block of assembly code.
539+
540+@ftable @code
541+@item .AREPEAT @var{aexp}
542+@itemx .AENDR
543+If you simply need to repeat the same block of assembly over and over a
544+fixed number of times, sandwich one instance of the repeated block
545+between @code{.AREPEAT} and @code{.AENDR}. Specify the number of
546+copies as @var{aexp} (which must be an absolute expression). For
547+example, this repeats two assembly statements three times in succession:
548+
549+@cartouche
550+@example
551+ .AREPEAT 3
552+ rotcl r2
553+ div1 r0,r1
554+ .AENDR
555+@end example
556+@end cartouche
557+
558+@item .AWHILE @var{expra} @var{cmp} @var{exprb}
559+@itemx .AENDW
560+@itemx .AWHILE @var{stra} @var{cmp} @var{strb}
561+@itemx .AENDW
562+To repeat a block of assembly depending on a conditional test, rather
563+than repeating it for a specific number of times, use @code{.AWHILE}.
564+@code{.AENDW} marks the end of the repeated block. The conditional
565+comparison works exactly the same way as for @code{.AIF}, with the same
566+comparison operators (@pxref{Conditionals,, Conditional assembly}).
567+
568+Since the terms of the comparison must be absolute expression,
569+@code{.AWHILE} is primarily useful within macros. @xref{Macros,,
570+Defining your own directives}.
571+@end ftable
572+
573+@cindex loops, breaking out of
574+@cindex breaking out of loops
575+You can use the @code{.EXITM} preprocessor directive to break out of
576+loops early (as well as to break out of macros). @xref{Macros,,
577+Defining your own directives}.
578+
579+@node Variables
580+@section Preprocessor variables
581+
582+You can use variables in @sc{gasp} to represent strings, registers, or
583+the results of expressions.
584+
585+You must distinguish two kinds of variables:
586+@enumerate
587+@item
588+Variables defined with @code{.EQU} or @code{.ASSIGN}. To evaluate this
589+kind of variable in your assembly output, simply mention its name. For
590+example, these two lines define and use a variable @samp{eg}:
591+
592+@cartouche
593+@example
594+eg .EQU FLIP-64
595+ @dots{}
596+ mov.l eg,r0
597+@end example
598+@end cartouche
599+
600+@emph{Do not use} this kind of variable in conditional expressions or
601+while loops; @sc{gasp} only evaluates these variables when writing
602+assembly output.
603+
604+@item
605+Variables for use during preprocessing. You can define these
606+with @code{.ASSIGNC} or @code{.ASSIGNA}. To evaluate this
607+kind of variable, write @samp{\&} before the variable name; for example,
608+
609+@cartouche
610+@example
611+opcit .ASSIGNA 47
612+ @dots{}
613+ .AWHILE \&opcit GT 0
614+ @dots{}
615+ .AENDW
616+@end example
617+@end cartouche
618+
619+@sc{gasp} treats macro arguments almost the same way, but to evaluate
620+them you use the prefix @samp{\} rather than @samp{\&}.
621+@xref{Macros,, Defining your own directives}.
622+@end enumerate
623+
624+@ftable @code
625+@item @var{pvar} .EQU @var{expr}
626+@c FIXME! Anything to beware of re GAS directive of same name?
627+Assign preprocessor variable @var{pvar} the value of the expression
628+@var{expr}. There are no restrictions on redefinition; use @samp{.EQU}
629+with the same @var{pvar} as often as you find it convenient.
630+
631+@item @var{pvar} .ASSIGN @var{expr}
632+Almost the same as @code{.EQU}, save that you may not redefine
633+@var{pvar} using @code{.ASSIGN} once it has a value.
634+@c FIXME!! Supposed to work this way, apparently, but on 9feb94 works
635+@c just like .EQU
636+
637+@item @var{pvar} .ASSIGNA @var{aexpr}
638+Define a variable with a numeric value, for use during preprocessing.
639+@var{aexpr} must be an absolute expression. You can redefine variables
640+with @code{.ASSIGNA} at any time.
641+
642+@item @var{pvar} .ASSIGNC "@var{str}"
643+Define a variable with a string value, for use during preprocessing.
644+You can redefine variables with @code{.ASSIGNC} at any time.
645+
646+@item @var{pvar} .REG (@var{register})
647+Use @code{.REG} to define a variable that represents a register. In
648+particular, @var{register} is @emph{not evaluated} as an expression.
649+You may use @code{.REG} at will to redefine register variables.
650+@end ftable
651+
652+All these directives accept the variable name in the ``label'' position,
653+that is at the left margin. You may specify a colon after the variable
654+name if you wish; the first example above could have started @samp{eg:}
655+with the same effect.
656+
657+@c pagebreak makes for better aesthetics---ensures macro and expansion together
658+@page
659+@node Macros
660+@section Defining your own directives
661+
662+The commands @code{.MACRO} and @code{.ENDM} allow you to define macros
663+that generate assembly output. You can use these macros with a syntax
664+similar to built-in @sc{gasp} or assembler directives. For example,
665+this definition specifies a macro @code{SUM} that adds together a range of
666+consecutive registers:
667+
668+@cartouche
669+@example
670+ .MACRO SUM FROM=0, TO=9
671+ ! \FROM \TO
672+ mov r\FROM,r10
673+COUNT .ASSIGNA \FROM+1
674+ .AWHILE \&COUNT LE \TO
675+ add r\&COUNT,r10
676+COUNT .ASSIGNA \&COUNT+1
677+ .AENDW
678+ .ENDM
679+@end example
680+@end cartouche
681+
682+@noindent
683+With that definition, @samp{SUM 0,5} generates this assembly output:
684+
685+@cartouche
686+@example
687+ ! 0 5
688+ mov r0,r10
689+ add r1,r10
690+ add r2,r10
691+ add r3,r10
692+ add r4,r10
693+ add r5,r10
694+@end example
695+@end cartouche
696+
697+@ftable @code
698+@item .MACRO @var{macname}
699+@itemx .MACRO @var{macname} @var{macargs} @dots{}
700+Begin the definition of a macro called @var{macname}. If your macro
701+definition requires arguments, specify their names after the macro name,
702+separated by commas or spaces. You can supply a default value for any
703+macro argument by following the name with @samp{=@var{deflt}}. For
704+example, these are all valid @code{.MACRO} statements:
705+
706+@table @code
707+@item .MACRO COMM
708+Begin the definition of a macro called @code{COMM}, which takes no
709+arguments.
710+
711+@item .MACRO PLUS1 P, P1
712+@itemx .MACRO PLUS1 P P1
713+Either statement begins the definition of a macro called @code{PLUS1},
714+which takes two arguments; within the macro definition, write
715+@samp{\P} or @samp{\P1} to evaluate the arguments.
716+
717+@item .MACRO RESERVE_STR P1=0 P2
718+Begin the definition of a macro called @code{RESERVE_STR}, with two
719+arguments. The first argument has a default value, but not the second.
720+After the definition is complete, you can call the macro either as
721+@samp{RESERVE_STR @var{a},@var{b}} (with @samp{\P1} evaluating to
722+@var{a} and @samp{\P2} evaluating to @var{b}), or as @samp{RESERVE_STR
723+,@var{b}} (with @samp{\P1} evaluating as the default, in this case
724+@samp{0}, and @samp{\P2} evaluating to @var{b}).
725+@end table
726+
727+When you call a macro, you can specify the argument values either by
728+position, or by keyword. For example, @samp{SUM 9,17} is equivalent to
729+@samp{SUM TO=17, FROM=9}. Macro arguments are preprocessor variables
730+similar to the variables you define with @samp{.ASSIGNA} or
731+@samp{.ASSIGNC}; in particular, you can use them in conditionals or for
732+loop control. (The only difference is the prefix you write to evaluate
733+the variable: for a macro argument, write @samp{\@var{argname}}, but for
734+a preprocessor variable, write @samp{\&@var{varname}}.)
735+
736+@item @var{name} .MACRO
737+@itemx @var{name} .MACRO ( @var{macargs} @dots{} )
738+@c FIXME check: I think no error _and_ no args recognized if I use form
739+@c NAME .MACRO ARG ARG
740+An alternative form of introducing a macro definition: specify the macro
741+name in the label position, and the arguments (if any) between
742+parentheses after the name. Defaulting rules and usage work the same
743+way as for the other macro definition syntax.
744+
745+@item .ENDM
746+Mark the end of a macro definition.
747+
748+@item .EXITM
749+Exit early from the current macro definition, @code{.AREPEAT} loop, or
750+@code{.AWHILE} loop.
751+
752+@cindex number of macros executed
753+@cindex macros, count executed
754+@item \@@
755+@sc{gasp} maintains a counter of how many macros it has
756+executed in this pseudo-variable; you can copy that number to your
757+output with @samp{\@@}, but @emph{only within a macro definition}.
758+
759+@item LOCAL @var{name} [ , @dots{} ]
760+@emph{Warning: @code{LOCAL} is only available if you select ``alternate
761+macro syntax'' with @samp{-a} or @samp{--alternate}.} @xref{Alternate,,
762+Alternate macro syntax}.
763+
764+Generate a string replacement for each of the @var{name} arguments, and
765+replace any instances of @var{name} in each macro expansion. The
766+replacement string is unique in the assembly, and different for each
767+separate macro expansion. @code{LOCAL} allows you to write macros that
768+define symbols, without fear of conflict between separate macro expansions.
769+@end ftable
770+
771+@node Data
772+@section Data output
773+
774+In assembly code, you often need to specify working areas of memory;
775+depending on the application, you may want to initialize such memory or
776+not. @sc{gasp} provides preprocessor directives to help you avoid
777+repetitive coding for both purposes.
778+
779+You can use labels as usual to mark the data areas.
780+
781+@menu
782+* Initialized::
783+* Uninitialized::
784+@end menu
785+
786+@node Initialized
787+@subsection Initialized data
788+
789+These are the @sc{gasp} directives for initialized data, and the standard
790+@sc{gnu} assembler directives they expand to:
791+
792+@ftable @code
793+@item .DATA @var{expr}, @var{expr}, @dots{}
794+@itemx .DATA.B @var{expr}, @var{expr}, @dots{}
795+@itemx .DATA.W @var{expr}, @var{expr}, @dots{}
796+@itemx .DATA.L @var{expr}, @var{expr}, @dots{}
797+Evaluate arithmetic expressions @var{expr}, and emit the corresponding
798+@code{as} directive (labelled with @var{lab}). The unqualified
799+@code{.DATA} emits @samp{.long}; @code{.DATA.B} emits @samp{.byte};
800+@code{.DATA.W} emits @samp{.short}; and @code{.DATA.L} emits
801+@samp{.long}.
802+
803+For example, @samp{foo .DATA 1,2,3} emits @samp{foo: .long 1,2,3}.
804+
805+@item .DATAB @var{repeat}, @var{expr}
806+@itemx .DATAB.B @var{repeat}, @var{expr}
807+@itemx .DATAB.W @var{repeat}, @var{expr}
808+@itemx .DATAB.L @var{repeat}, @var{expr}
809+@c FIXME! Looks like gasp accepts and ignores args after 2nd.
810+Make @code{as} emit @var{repeat} copies of the value of the expression
811+@var{expr} (using the @code{as} directive @code{.fill}).
812+@samp{.DATAB.B} repeats one-byte values; @samp{.DATAB.W} repeats
813+two-byte values; and @samp{.DATAB.L} repeats four-byte values.
814+@samp{.DATAB} without a suffix repeats four-byte values, just like
815+@samp{.DATAB.L}.
816+
817+@c FIXME! Allowing zero might be useful for edge conditions in macros.
818+@var{repeat} must be an absolute expression with a positive value.
819+
820+@item .SDATA "@var{str}" @dots{}
821+String data. Emits a concatenation of bytes, precisely as you specify
822+them (in particular, @emph{nothing is added to mark the end} of the
823+string). @xref{Constants,, String and numeric constants}, for details
824+about how to write strings. @code{.SDATA} concatenates multiple
825+arguments, making it easy to switch between string representations. You
826+can use commas to separate the individual arguments for clarity, if you
827+choose.
828+
829+@item .SDATAB @var{repeat}, "@var{str}" @dots{}
830+Repeated string data. The first argument specifies how many copies of
831+the string to emit; the remaining arguments specify the string, in the
832+same way as the arguments to @code{.SDATA}.
833+
834+@item .SDATAZ "@var{str}" @dots{}
835+Zero-terminated string data. Just like @code{.SDATA}, except that
836+@code{.SDATAZ} writes a zero byte at the end of the string.
837+
838+@item .SDATAC "@var{str}" @dots{}
839+Count-prefixed string data. Just like @code{.SDATA}, except that
840+@sc{gasp} precedes the string with a leading one-byte count. For
841+example, @samp{.SDATAC "HI"} generates @samp{.byte 2,72,73}. Since the
842+count field is only one byte, you can only use @code{.SDATAC} for
843+strings less than 256 bytes in length.
844+@end ftable
845+
846+@node Uninitialized
847+@subsection Uninitialized data
848+
849+@c FIXME! .space different on some platforms, notably HPPA. Config?
850+Use the @code{.RES}, @code{.SRES}, @code{.SRESC}, and @code{.SRESZ}
851+directives to reserve memory and leave it uninitialized. @sc{gasp}
852+resolves these directives to appropriate calls of the @sc{gnu}
853+@code{as} @code{.space} directive.
854+
855+@ftable @code
856+@item .RES @var{count}
857+@itemx .RES.B @var{count}
858+@itemx .RES.W @var{count}
859+@itemx .RES.L @var{count}
860+Reserve room for @var{count} uninitialized elements of data. The
861+suffix specifies the size of each element: @code{.RES.B} reserves
862+@var{count} bytes, @code{.RES.W} reserves @var{count} pairs of bytes,
863+and @code{.RES.L} reserves @var{count} quartets. @code{.RES} without a
864+suffix is equivalent to @code{.RES.L}.
865+
866+@item .SRES @var{count}
867+@itemx .SRES.B @var{count}
868+@itemx .SRES.W @var{count}
869+@itemx .SRES.L @var{count}
870+@c FIXME! This is boring. Shouldn't it at least have a different
871+@c default size? (e.g. the "S" suggests "string", for which .B
872+@c would be more appropriate)
873+@code{.SRES} is a synonym for @samp{.RES}.
874+
875+@item .SRESC @var{count}
876+@itemx .SRESC.B @var{count}
877+@itemx .SRESC.W @var{count}
878+@itemx .SRESC.L @var{count}
879+Like @code{.SRES}, but reserves space for @code{@var{count}+1} elements.
880+
881+@item .SRESZ @var{count}
882+@itemx .SRESZ.B @var{count}
883+@itemx .SRESZ.W @var{count}
884+@itemx .SRESZ.L @var{count}
885+Like @code{.SRES}, but reserves space for @code{@var{count}+1} elements.
886+@end ftable
887+
888+@node Listings
889+@section Assembly listing control
890+
891+The @sc{gasp} listing-control directives correspond to
892+related @sc{gnu} @code{as} directives.
893+
894+@ftable @code
895+@item .PRINT LIST
896+@itemx .PRINT NOLIST
897+Print control. This directive emits the @sc{gnu} @code{as} directive
898+@code{.list} or @code{.nolist}, according to its argument. @xref{List,,
899+@code{.list}, as.info, Using as}, for details on how these directives
900+interact.
901+
902+@item .FORM LIN=@var{ln}
903+@itemx .FORM COL=@var{cols}
904+@itemx .FORM LIN=@var{ln} COL=@var{cols}
905+Specify the page size for assembly listings: @var{ln} represents the
906+number of lines, and @var{cols} the number of columns. You may specify
907+either page dimension independently, or both together. If you do not
908+specify the number of lines, @sc{gasp} assumes 60 lines; if you do not
909+specify the number of columns, @sc{gasp} assumes 132 columns.
910+(Any values you may have specified in previous instances of @code{.FORM}
911+do @emph{not} carry over as defaults.) Emits the @code{.psize}
912+assembler directive.
913+
914+@item .HEADING @var{string}
915+Specify @var{string} as the title of your assembly listings. Emits
916+@samp{.title "@var{string}"}.
917+
918+@item .PAGE
919+Force a new page in assembly listings. Emits @samp{.eject}.
920+@end ftable
921+
922+@node Other Commands
923+@section Miscellaneous commands
924+
925+@ftable @code
926+@item .ALTERNATE
927+Use the alternate macro syntax henceforth in the assembly.
928+@xref{Alternate,, Alternate macro syntax}.
929+
930+@item .ORG
931+@c FIXME! This is very strange, since _GAS_ understands .org
932+This command is recognized, but not yet implemented. @sc{gasp}
933+generates an error message for programs that use @code{.ORG}.
934+
935+@item .RADIX @var{s}
936+@c FIXME no test cases in testsuite/gasp
937+@sc{gasp} understands numbers in any of base two, eight, ten, or
938+sixteen. You can encode the base explicitly in any numeric constant
939+(@pxref{Constants,, String and numeric constants}). If you write
940+numbers without an explicit indication of the base, the most recent
941+@samp{.RADIX @var{s}} command determines how they are interpreted.
942+@var{s} is a single letter, one of the following:
943+
944+@table @code
945+@item .RADIX B
946+Base 2.
947+
948+@item .RADIX Q
949+Base 8.
950+
951+@item .RADIX D
952+Base 10. This is the original default radix.
953+
954+@item .RADIX H
955+Base 16.
956+@end table
957+
958+You may specify the argument @var{s} in lower case (any of @samp{bqdh})
959+with the same effects.
960+
961+@item .EXPORT @var{name}
962+@itemx .GLOBAL @var{name}
963+@c FIXME! No test cases in testsuite/gasp
964+Declare @var{name} global (emits @samp{.global @var{name}}). The two
965+directives are synonymous.
966+
967+@item .PROGRAM
968+No effect: @sc{gasp} accepts this directive, and silently ignores it.
969+
970+@item .END
971+Mark end of each preprocessor file. @sc{gasp} issues a warning if it
972+reaches end of file without seeing this command.
973+
974+@item .INCLUDE "@var{str}"
975+Preprocess the file named by @var{str}, as if its contents appeared
976+where the @code{.INCLUDE} directive does. @sc{gasp} imposes a maximum
977+limit of 30 stacked include files, as a sanity check.
978+@c FIXME! Why is include depth not affected by -u?
979+
980+@item .ALIGN @var{size}
981+@c FIXME! Why is this not utterly pointless?
982+Evaluate the absolute expression @var{size}, and emit the assembly
983+instruction @samp{.align @var{size}} using the result.
984+@end ftable
985+
986+@node Syntax Details
987+@section Details of the GASP syntax
988+
989+Since @sc{gasp} is meant to work with assembly code, its statement
990+syntax has no surprises for the assembly programmer.
991+
992+@cindex whitespace
993+@emph{Whitespace} (blanks or tabs; @emph{not} newline) is partially
994+significant, in that it delimits up to three fields in a line. The
995+amount of whitespace does not matter; you may line up fields in separate
996+lines if you wish, but @sc{gasp} does not require that.
997+
998+@cindex fields of @sc{gasp} source line
999+@cindex label field
1000+The @emph{first field}, an optional @dfn{label}, must be flush left in a
1001+line (with no leading whitespace) if it appears at all. You may use a
1002+colon after the label if you wish; @sc{gasp} neither requires the colon
1003+nor objects to it (but will not include it as part of the label name).
1004+
1005+@cindex directive field
1006+The @emph{second field}, which must appear after some whitespace,
1007+contains a @sc{gasp} or assembly @dfn{directive}.
1008+
1009+@cindex argument fields
1010+Any @emph{further fields} on a line are @dfn{arguments} to the
1011+directive; you can separate them from one another using either commas or
1012+whitespace.
1013+
1014+@menu
1015+* Markers::
1016+* Constants::
1017+* Symbols::
1018+* Expressions::
1019+* String Builtins::
1020+@end menu
1021+
1022+@node Markers
1023+@subsection Special syntactic markers
1024+
1025+@sc{gasp} recognizes a few special markers: to delimit comments, to
1026+continue a statement on the next line, to separate symbols from other
1027+characters, and to copy text to the output literally. (One other
1028+special marker, @samp{\@@}, works only within macro definitions;
1029+@pxref{Macros,, Defining your own directives}.)
1030+
1031+@cindex comments
1032+The trailing part of any @sc{gasp} source line may be a @dfn{comment}.
1033+A comment begins with the first unquoted comment character (@samp{!} by
1034+default), or an escaped or doubled comment character (@samp{\!} or
1035+@samp{!!} by default), and extends to the end of a line. You can
1036+specify what comment character to use with the @samp{-c} option
1037+(@pxref{Invoking GASP,, Command Line Options}). The two kinds of
1038+comment markers lead to slightly different treatment:
1039+
1040+@table @code
1041+@item !
1042+A single, un-escaped comment character generates an assembly comment in
1043+the @sc{gasp} output. @sc{gasp} evaluates any preprocessor variables
1044+(macro arguments, or variables defined with @code{.ASSIGNA} or
1045+@code{.ASSIGNC}) present. For example, a macro that begins like this
1046+
1047+@example
1048+ .MACRO SUM FROM=0, TO=9
1049+ ! \FROM \TO
1050+@end example
1051+
1052+@noindent
1053+issues as the first line of output a comment that records the
1054+values you used to call the macro.
1055+
1056+@c comments, preprocessor-only
1057+@c preprocessor-only comments
1058+@c GASP-only comments
1059+@item \!
1060+@itemx !!
1061+Either an escaped comment character, or a double comment character,
1062+marks a @sc{gasp} source comment. @sc{gasp} does not copy such comments
1063+to the assembly output.
1064+@end table
1065+
1066+@cindex continuation character
1067+@kindex +
1068+To @emph{continue a statement} on the next line of the file, begin the
1069+second line with the character @samp{+}.
1070+
1071+@cindex literal copy to output
1072+@cindex copying literally to output
1073+@cindex preprocessing, avoiding
1074+@cindex avoiding preprocessing
1075+Occasionally you may want to prevent @sc{gasp} from preprocessing some
1076+particular bit of text. To @emph{copy literally} from the @sc{gasp}
1077+source to its output, place @samp{\(} before the string to copy, and
1078+@samp{)} at the end. For example, write @samp{\(\!)} if you need the
1079+characters @samp{\!} in your assembly output.
1080+
1081+@cindex symbol separator
1082+@cindex text, separating from symbols
1083+@cindex symbols, separating from text
1084+To @emph{separate a preprocessor variable} from text to appear
1085+immediately after its value, write a single quote (@code{'}). For
1086+example, @samp{.SDATA "\P'1"} writes a string built by concatenating the
1087+value of @code{P} and the digit @samp{1}. (You cannot achieve this by
1088+writing just @samp{\P1}, since @samp{P1} is itself a valid name for a
1089+preprocessor variable.)
1090+
1091+@node Constants
1092+@subsection String and numeric constants
1093+
1094+There are two ways of writing @dfn{string constants} in @sc{gasp}: as
1095+literal text, and by numeric byte value. Specify a string literal
1096+between double quotes (@code{"@var{str}"}). Specify an individual
1097+numeric byte value as an absolute expression between angle brackets
1098+(@code{<@var{expr}>}. Directives that output strings allow you to
1099+specify any number of either kind of value, in whatever order is
1100+convenient, and concatenate the result. (Alternate syntax mode
1101+introduces a number of alternative string notations; @pxref{Alternate,,
1102+Alternate macro syntax}.)
1103+
1104+@c Details of numeric notation, e.g. base prefixes
1105+You can write @dfn{numeric constants} either in a specific base, or in
1106+whatever base is currently selected (either 10, or selected by the most
1107+recent @code{.RADIX}).
1108+
1109+To write a number in a @emph{specific base}, use the pattern
1110+@code{@var{s}'@var{ddd}}: a base specifier character @var{s}, followed
1111+by a single quote followed by digits @var{ddd}. The base specifier
1112+character matches those you can specify with @code{.RADIX}: @samp{B} for
1113+base 2, @samp{Q} for base 8, @samp{D} for base 10, and @samp{H} for base
1114+16. (You can write this character in lower case if you prefer.)
1115+
1116+You can write floating point constants using the same syntax recognised
1117+by GAS @ref{Flonums,,Flonums,as,The GNU Assembler.}. A constraint is
1118+that these constants will be interpreted as decimal values irrespective
1119+of the currently selected base.
1120+
1121+@c FIXME! What are rules for recognizing number in deflt base? Whatever
1122+@c is left over after parsing other things??
1123+
1124+@node Symbols
1125+@subsection Symbols
1126+
1127+@sc{gasp} recognizes symbol names that start with any alphabetic character,
1128+@samp{_}, or @samp{$}, and continue with any of the same characters or
1129+with digits. Label names follow the same rules.
1130+
1131+@node Expressions
1132+@subsection Arithmetic expressions in GASP
1133+
1134+@cindex absolute expressions
1135+@cindex relocatable expressions
1136+There are two kinds of expressions, depending on their result:
1137+@dfn{absolute} expressions, which resolve to a constant (that is, they
1138+do not involve any values unknown to @sc{gasp}), and @dfn{relocatable}
1139+expressions, which must reduce to the form
1140+
1141+@example
1142+@var{addsym}+@var{const}-@var{subsym}
1143+@end example
1144+
1145+@noindent
1146+where @var{addsym} and @var{subsym} are assembly symbols of unknown
1147+value, and @var{const} is a constant.
1148+
1149+Arithmetic for @sc{gasp} expressions follows very similar rules to C.
1150+You can use parentheses to change precedence; otherwise, arithmetic
1151+primitives have decreasing precedence in the order of the following
1152+list.
1153+
1154+@enumerate
1155+@item
1156+Single-argument @code{+} (identity), @code{-} (arithmetic opposite), or
1157+@code{~} (bitwise negation). @emph{The argument must be an absolute
1158+expression.}
1159+
1160+@item
1161+@code{*} (multiplication) and @code{/} (division). @emph{Both arguments
1162+must be absolute expressions.}
1163+
1164+@item
1165+@code{+} (addition) and @code{-} (subtraction). @emph{At least one argument
1166+must be absolute.}
1167+@c FIXME! Actually, subtraction doesn't check for this.
1168+
1169+@item
1170+@code{&} (bitwise and). @emph{Both arguments must be absolute.}
1171+
1172+@item
1173+@c FIXME! I agree ~ is a better notation than ^ for xor, but is the
1174+@c improvement worth differing from C?
1175+@code{|} (bitwise or) and @code{~} (bitwise exclusive or; @code{^} in
1176+C). @emph{Both arguments must be absolute.}
1177+@end enumerate
1178+
1179+@node String Builtins
1180+@subsection String primitives
1181+
1182+You can use these primitives to manipulate strings (in the argument
1183+field of @sc{gasp} statements):
1184+
1185+@ftable @code
1186+@item .LEN("@var{str}")
1187+Calculate the length of string @code{"@var{str}"}, as an absolute
1188+expression. For example, @samp{.RES.B .LEN("sample")} reserves six
1189+bytes of memory.
1190+
1191+@item .INSTR("@var{string}", "@var{seg}", @var{ix})
1192+Search for the first occurrence of @var{seg} after position @var{ix} of
1193+@var{string}. For example, @samp{.INSTR("ABCDEFG", "CDE", 0)} evaluates
1194+to the absolute result @code{2}.
1195+
1196+The result is @code{-1} if @var{seg} does not occur in @var{string}
1197+after position @var{ix}.
1198+
1199+@item .SUBSTR("@var{string}",@var{start},@var{len})
1200+The substring of @var{string} beginning at byte number @var{start} and
1201+extending for @var{len} bytes.
1202+@end ftable
1203+
1204+@node Alternate
1205+@section Alternate macro syntax
1206+
1207+If you specify @samp{-a} or @samp{--alternate} on the @sc{gasp} command
1208+line, the preprocessor uses somewhat different syntax. This syntax is
1209+reminiscent of the syntax of Phar Lap macro assembler, but it
1210+is @emph{not} meant to be a full emulation of Phar Lap or similar
1211+assemblers. In particular, @sc{gasp} does not support directives such
1212+as @code{DB} and @code{IRP}, even in alternate syntax mode.
1213+
1214+In particular, @samp{-a} (or @samp{--alternate}) elicits these
1215+differences:
1216+
1217+@table @emph
1218+@item Preprocessor directives
1219+You can use @sc{gasp} preprocessor directives without a leading @samp{.}
1220+dot. For example, you can write @samp{SDATA} with the same effect as
1221+@samp{.SDATA}.
1222+
1223+@item LOCAL
1224+One additional directive, @code{LOCAL}, is available. @xref{Macros,,
1225+Defining your own directives}, for an explanation of how to use
1226+@code{LOCAL}.
1227+
1228+@need 2000
1229+@item String delimiters
1230+You can write strings delimited in these other ways besides
1231+@code{"@var{string}"}:
1232+
1233+@table @code
1234+@item '@var{string}'
1235+You can delimit strings with single-quote charaters.
1236+
1237+@item <@var{string}>
1238+You can delimit strings with matching angle brackets.
1239+@end table
1240+
1241+@item single-character string escape
1242+To include any single character literally in a string (even if the
1243+character would otherwise have some special meaning), you can prefix the
1244+character with @samp{!} (an exclamation mark). For example, you can
1245+write @samp{<4.3 !> 5.4!!>} to get the literal text @samp{4.3 > 5.4!}.
1246+
1247+@item Expression results as strings
1248+You can write @samp{%@var{expr}} to evaluate the expression @var{expr}
1249+and use the result as a string.
1250+@end table
1251+
1252+@node GNU Free Documentation License
1253+@chapter GNU Free Documentation License
1254+
1255+ GNU Free Documentation License
1256+
1257+ Version 1.1, March 2000
1258+
1259+ Copyright (C) 2000 Free Software Foundation, Inc.
1260+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1261+
1262+ Everyone is permitted to copy and distribute verbatim copies
1263+ of this license document, but changing it is not allowed.
1264+
1265+
1266+0. PREAMBLE
1267+
1268+The purpose of this License is to make a manual, textbook, or other
1269+written document "free" in the sense of freedom: to assure everyone
1270+the effective freedom to copy and redistribute it, with or without
1271+modifying it, either commercially or noncommercially. Secondarily,
1272+this License preserves for the author and publisher a way to get
1273+credit for their work, while not being considered responsible for
1274+modifications made by others.
1275+
1276+This License is a kind of "copyleft", which means that derivative
1277+works of the document must themselves be free in the same sense. It
1278+complements the GNU General Public License, which is a copyleft
1279+license designed for free software.
1280+
1281+We have designed this License in order to use it for manuals for free
1282+software, because free software needs free documentation: a free
1283+program should come with manuals providing the same freedoms that the
1284+software does. But this License is not limited to software manuals;
1285+it can be used for any textual work, regardless of subject matter or
1286+whether it is published as a printed book. We recommend this License
1287+principally for works whose purpose is instruction or reference.
1288+
1289+
1290+1. APPLICABILITY AND DEFINITIONS
1291+
1292+This License applies to any manual or other work that contains a
1293+notice placed by the copyright holder saying it can be distributed
1294+under the terms of this License. The "Document", below, refers to any
1295+such manual or work. Any member of the public is a licensee, and is
1296+addressed as "you".
1297+
1298+A "Modified Version" of the Document means any work containing the
1299+Document or a portion of it, either copied verbatim, or with
1300+modifications and/or translated into another language.
1301+
1302+A "Secondary Section" is a named appendix or a front-matter section of
1303+the Document that deals exclusively with the relationship of the
1304+publishers or authors of the Document to the Document's overall subject
1305+(or to related matters) and contains nothing that could fall directly
1306+within that overall subject. (For example, if the Document is in part a
1307+textbook of mathematics, a Secondary Section may not explain any
1308+mathematics.) The relationship could be a matter of historical
1309+connection with the subject or with related matters, or of legal,
1310+commercial, philosophical, ethical or political position regarding
1311+them.
1312+
1313+The "Invariant Sections" are certain Secondary Sections whose titles
1314+are designated, as being those of Invariant Sections, in the notice
1315+that says that the Document is released under this License.
1316+
1317+The "Cover Texts" are certain short passages of text that are listed,
1318+as Front-Cover Texts or Back-Cover Texts, in the notice that says that
1319+the Document is released under this License.
1320+
1321+A "Transparent" copy of the Document means a machine-readable copy,
1322+represented in a format whose specification is available to the
1323+general public, whose contents can be viewed and edited directly and
1324+straightforwardly with generic text editors or (for images composed of
1325+pixels) generic paint programs or (for drawings) some widely available
1326+drawing editor, and that is suitable for input to text formatters or
1327+for automatic translation to a variety of formats suitable for input
1328+to text formatters. A copy made in an otherwise Transparent file
1329+format whose markup has been designed to thwart or discourage
1330+subsequent modification by readers is not Transparent. A copy that is
1331+not "Transparent" is called "Opaque".
1332+
1333+Examples of suitable formats for Transparent copies include plain
1334+ASCII without markup, Texinfo input format, LaTeX input format, SGML
1335+or XML using a publicly available DTD, and standard-conforming simple
1336+HTML designed for human modification. Opaque formats include
1337+PostScript, PDF, proprietary formats that can be read and edited only
1338+by proprietary word processors, SGML or XML for which the DTD and/or
1339+processing tools are not generally available, and the
1340+machine-generated HTML produced by some word processors for output
1341+purposes only.
1342+
1343+The "Title Page" means, for a printed book, the title page itself,
1344+plus such following pages as are needed to hold, legibly, the material
1345+this License requires to appear in the title page. For works in
1346+formats which do not have any title page as such, "Title Page" means
1347+the text near the most prominent appearance of the work's title,
1348+preceding the beginning of the body of the text.
1349+
1350+
1351+2. VERBATIM COPYING
1352+
1353+You may copy and distribute the Document in any medium, either
1354+commercially or noncommercially, provided that this License, the
1355+copyright notices, and the license notice saying this License applies
1356+to the Document are reproduced in all copies, and that you add no other
1357+conditions whatsoever to those of this License. You may not use
1358+technical measures to obstruct or control the reading or further
1359+copying of the copies you make or distribute. However, you may accept
1360+compensation in exchange for copies. If you distribute a large enough
1361+number of copies you must also follow the conditions in section 3.
1362+
1363+You may also lend copies, under the same conditions stated above, and
1364+you may publicly display copies.
1365+
1366+
1367+3. COPYING IN QUANTITY
1368+
1369+If you publish printed copies of the Document numbering more than 100,
1370+and the Document's license notice requires Cover Texts, you must enclose
1371+the copies in covers that carry, clearly and legibly, all these Cover
1372+Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
1373+the back cover. Both covers must also clearly and legibly identify
1374+you as the publisher of these copies. The front cover must present
1375+the full title with all words of the title equally prominent and
1376+visible. You may add other material on the covers in addition.
1377+Copying with changes limited to the covers, as long as they preserve
1378+the title of the Document and satisfy these conditions, can be treated
1379+as verbatim copying in other respects.
1380+
1381+If the required texts for either cover are too voluminous to fit
1382+legibly, you should put the first ones listed (as many as fit
1383+reasonably) on the actual cover, and continue the rest onto adjacent
1384+pages.
1385+
1386+If you publish or distribute Opaque copies of the Document numbering
1387+more than 100, you must either include a machine-readable Transparent
1388+copy along with each Opaque copy, or state in or with each Opaque copy
1389+a publicly-accessible computer-network location containing a complete
1390+Transparent copy of the Document, free of added material, which the
1391+general network-using public has access to download anonymously at no
1392+charge using public-standard network protocols. If you use the latter
1393+option, you must take reasonably prudent steps, when you begin
1394+distribution of Opaque copies in quantity, to ensure that this
1395+Transparent copy will remain thus accessible at the stated location
1396+until at least one year after the last time you distribute an Opaque
1397+copy (directly or through your agents or retailers) of that edition to
1398+the public.
1399+
1400+It is requested, but not required, that you contact the authors of the
1401+Document well before redistributing any large number of copies, to give
1402+them a chance to provide you with an updated version of the Document.
1403+
1404+
1405+4. MODIFICATIONS
1406+
1407+You may copy and distribute a Modified Version of the Document under
1408+the conditions of sections 2 and 3 above, provided that you release
1409+the Modified Version under precisely this License, with the Modified
1410+Version filling the role of the Document, thus licensing distribution
1411+and modification of the Modified Version to whoever possesses a copy
1412+of it. In addition, you must do these things in the Modified Version:
1413+
1414+A. Use in the Title Page (and on the covers, if any) a title distinct
1415+ from that of the Document, and from those of previous versions
1416+ (which should, if there were any, be listed in the History section
1417+ of the Document). You may use the same title as a previous version
1418+ if the original publisher of that version gives permission.
1419+B. List on the Title Page, as authors, one or more persons or entities
1420+ responsible for authorship of the modifications in the Modified
1421+ Version, together with at least five of the principal authors of the
1422+ Document (all of its principal authors, if it has less than five).
1423+C. State on the Title page the name of the publisher of the
1424+ Modified Version, as the publisher.
1425+D. Preserve all the copyright notices of the Document.
1426+E. Add an appropriate copyright notice for your modifications
1427+ adjacent to the other copyright notices.
1428+F. Include, immediately after the copyright notices, a license notice
1429+ giving the public permission to use the Modified Version under the
1430+ terms of this License, in the form shown in the Addendum below.
1431+G. Preserve in that license notice the full lists of Invariant Sections
1432+ and required Cover Texts given in the Document's license notice.
1433+H. Include an unaltered copy of this License.
1434+I. Preserve the section entitled "History", and its title, and add to
1435+ it an item stating at least the title, year, new authors, and
1436+ publisher of the Modified Version as given on the Title Page. If
1437+ there is no section entitled "History" in the Document, create one
1438+ stating the title, year, authors, and publisher of the Document as
1439+ given on its Title Page, then add an item describing the Modified
1440+ Version as stated in the previous sentence.
1441+J. Preserve the network location, if any, given in the Document for
1442+ public access to a Transparent copy of the Document, and likewise
1443+ the network locations given in the Document for previous versions
1444+ it was based on. These may be placed in the "History" section.
1445+ You may omit a network location for a work that was published at
1446+ least four years before the Document itself, or if the original
1447+ publisher of the version it refers to gives permission.
1448+K. In any section entitled "Acknowledgements" or "Dedications",
1449+ preserve the section's title, and preserve in the section all the
1450+ substance and tone of each of the contributor acknowledgements
1451+ and/or dedications given therein.
1452+L. Preserve all the Invariant Sections of the Document,
1453+ unaltered in their text and in their titles. Section numbers
1454+ or the equivalent are not considered part of the section titles.
1455+M. Delete any section entitled "Endorsements". Such a section
1456+ may not be included in the Modified Version.
1457+N. Do not retitle any existing section as "Endorsements"
1458+ or to conflict in title with any Invariant Section.
1459+
1460+If the Modified Version includes new front-matter sections or
1461+appendices that qualify as Secondary Sections and contain no material
1462+copied from the Document, you may at your option designate some or all
1463+of these sections as invariant. To do this, add their titles to the
1464+list of Invariant Sections in the Modified Version's license notice.
1465+These titles must be distinct from any other section titles.
1466+
1467+You may add a section entitled "Endorsements", provided it contains
1468+nothing but endorsements of your Modified Version by various
1469+parties--for example, statements of peer review or that the text has
1470+been approved by an organization as the authoritative definition of a
1471+standard.
1472+
1473+You may add a passage of up to five words as a Front-Cover Text, and a
1474+passage of up to 25 words as a Back-Cover Text, to the end of the list
1475+of Cover Texts in the Modified Version. Only one passage of
1476+Front-Cover Text and one of Back-Cover Text may be added by (or
1477+through arrangements made by) any one entity. If the Document already
1478+includes a cover text for the same cover, previously added by you or
1479+by arrangement made by the same entity you are acting on behalf of,
1480+you may not add another; but you may replace the old one, on explicit
1481+permission from the previous publisher that added the old one.
1482+
1483+The author(s) and publisher(s) of the Document do not by this License
1484+give permission to use their names for publicity for or to assert or
1485+imply endorsement of any Modified Version.
1486+
1487+
1488+5. COMBINING DOCUMENTS
1489+
1490+You may combine the Document with other documents released under this
1491+License, under the terms defined in section 4 above for modified
1492+versions, provided that you include in the combination all of the
1493+Invariant Sections of all of the original documents, unmodified, and
1494+list them all as Invariant Sections of your combined work in its
1495+license notice.
1496+
1497+The combined work need only contain one copy of this License, and
1498+multiple identical Invariant Sections may be replaced with a single
1499+copy. If there are multiple Invariant Sections with the same name but
1500+different contents, make the title of each such section unique by
1501+adding at the end of it, in parentheses, the name of the original
1502+author or publisher of that section if known, or else a unique number.
1503+Make the same adjustment to the section titles in the list of
1504+Invariant Sections in the license notice of the combined work.
1505+
1506+In the combination, you must combine any sections entitled "History"
1507+in the various original documents, forming one section entitled
1508+"History"; likewise combine any sections entitled "Acknowledgements",
1509+and any sections entitled "Dedications". You must delete all sections
1510+entitled "Endorsements."
1511+
1512+
1513+6. COLLECTIONS OF DOCUMENTS
1514+
1515+You may make a collection consisting of the Document and other documents
1516+released under this License, and replace the individual copies of this
1517+License in the various documents with a single copy that is included in
1518+the collection, provided that you follow the rules of this License for
1519+verbatim copying of each of the documents in all other respects.
1520+
1521+You may extract a single document from such a collection, and distribute
1522+it individually under this License, provided you insert a copy of this
1523+License into the extracted document, and follow this License in all
1524+other respects regarding verbatim copying of that document.
1525+
1526+
1527+7. AGGREGATION WITH INDEPENDENT WORKS
1528+
1529+A compilation of the Document or its derivatives with other separate
1530+and independent documents or works, in or on a volume of a storage or
1531+distribution medium, does not as a whole count as a Modified Version
1532+of the Document, provided no compilation copyright is claimed for the
1533+compilation. Such a compilation is called an "aggregate", and this
1534+License does not apply to the other self-contained works thus compiled
1535+with the Document, on account of their being thus compiled, if they
1536+are not themselves derivative works of the Document.
1537+
1538+If the Cover Text requirement of section 3 is applicable to these
1539+copies of the Document, then if the Document is less than one quarter
1540+of the entire aggregate, the Document's Cover Texts may be placed on
1541+covers that surround only the Document within the aggregate.
1542+Otherwise they must appear on covers around the whole aggregate.
1543+
1544+
1545+8. TRANSLATION
1546+
1547+Translation is considered a kind of modification, so you may
1548+distribute translations of the Document under the terms of section 4.
1549+Replacing Invariant Sections with translations requires special
1550+permission from their copyright holders, but you may include
1551+translations of some or all Invariant Sections in addition to the
1552+original versions of these Invariant Sections. You may include a
1553+translation of this License provided that you also include the
1554+original English version of this License. In case of a disagreement
1555+between the translation and the original English version of this
1556+License, the original English version will prevail.
1557+
1558+
1559+9. TERMINATION
1560+
1561+You may not copy, modify, sublicense, or distribute the Document except
1562+as expressly provided for under this License. Any other attempt to
1563+copy, modify, sublicense or distribute the Document is void, and will
1564+automatically terminate your rights under this License. However,
1565+parties who have received copies, or rights, from you under this
1566+License will not have their licenses terminated so long as such
1567+parties remain in full compliance.
1568+
1569+
1570+10. FUTURE REVISIONS OF THIS LICENSE
1571+
1572+The Free Software Foundation may publish new, revised versions
1573+of the GNU Free Documentation License from time to time. Such new
1574+versions will be similar in spirit to the present version, but may
1575+differ in detail to address new problems or concerns. See
1576+http://www.gnu.org/copyleft/.
1577+
1578+Each version of the License is given a distinguishing version number.
1579+If the Document specifies that a particular numbered version of this
1580+License "or any later version" applies to it, you have the option of
1581+following the terms and conditions either of that specified version or
1582+of any later version that has been published (not as a draft) by the
1583+Free Software Foundation. If the Document does not specify a version
1584+number of this License, you may choose any version ever published (not
1585+as a draft) by the Free Software Foundation.
1586+
1587+
1588+ADDENDUM: How to use this License for your documents
1589+
1590+To use this License in a document you have written, include a copy of
1591+the License in the document and put the following copyright and
1592+license notices just after the title page:
1593+
1594+@smallexample
1595+ Copyright (c) YEAR YOUR NAME.
1596+ Permission is granted to copy, distribute and/or modify this document
1597+ under the terms of the GNU Free Documentation License, Version 1.1
1598+ or any later version published by the Free Software Foundation;
1599+ with the Invariant Sections being LIST THEIR TITLES, with the
1600+ Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
1601+ A copy of the license is included in the section entitled "GNU
1602+ Free Documentation License".
1603+@end smallexample
1604+
1605+If you have no Invariant Sections, write "with no Invariant Sections"
1606+instead of saying which ones are invariant. If you have no
1607+Front-Cover Texts, write "no Front-Cover Texts" instead of
1608+"Front-Cover Texts being LIST"; likewise for Back-Cover Texts.
1609+
1610+If your document contains nontrivial examples of program code, we
1611+recommend releasing these examples in parallel under your choice of
1612+free software license, such as the GNU General Public License,
1613+to permit their use in free software.
1614+
1615+@node Index
1616+@unnumbered Index
1617+
1618+@printindex cp
1619+
1620+@contents
1621+@bye
1622diff -Nur binutils-2.13.90.0.18.orig/gas/gasp.c binutils-2.13.90.0.18/gas/gasp.c
1623--- binutils-2.13.90.0.18.orig/gas/gasp.c Thu Jan 1 01:00:00 1970
1624+++ binutils-2.13.90.0.18/gas/gasp.c Sun May 26 18:57:12 2002
1625@@ -0,0 +1,3761 @@
1626+/* gasp.c - Gnu assembler preprocessor main program.
1627+ Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
1628+ Free Software Foundation, Inc.
1629+
1630+ Written by Steve and Judy Chamberlain of Cygnus Support,
1631+ sac@cygnus.com
1632+
1633+ This file is part of GASP, the GNU Assembler Preprocessor.
1634+
1635+ GASP is free software; you can redistribute it and/or modify
1636+ it under the terms of the GNU General Public License as published by
1637+ the Free Software Foundation; either version 2, or (at your option)
1638+ any later version.
1639+
1640+ GASP is distributed in the hope that it will be useful,
1641+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1642+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1643+ GNU General Public License for more details.
1644+
1645+ You should have received a copy of the GNU General Public License
1646+ along with GASP; see the file COPYING. If not, write to the Free
1647+ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
1648+ 02111-1307, USA. */
1649+
1650+/*
1651+This program translates the input macros and stuff into a form
1652+suitable for gas to consume.
1653+
1654+ gasp [-sdhau] [-c char] [-o <outfile>] <infile>*
1655+
1656+ -s copy source to output
1657+ -c <char> comments are started with <char> instead of !
1658+ -u allow unreasonable stuff
1659+ -p print line numbers
1660+ -d print debugging stats
1661+ -s semi colons start comments
1662+ -a use alternate syntax
1663+ Pseudo ops can start with or without a .
1664+ Labels have to be in first column.
1665+ -I specify include dir
1666+ Macro arg parameters subsituted by name, don't need the &.
1667+ String can start with ' too.
1668+ Strings can be surrounded by <..>
1669+ A %<exp> in a string evaluates the expression
1670+ Literal char in a string with !
1671+*/
1672+
1673+#include "config.h"
1674+#include "bin-bugs.h"
1675+
1676+#include <assert.h>
1677+#include <stdio.h>
1678+#include <string.h>
1679+#include "getopt.h"
1680+
1681+#ifdef HAVE_STDLIB_H
1682+#include <stdlib.h>
1683+#endif
1684+
1685+#ifdef NEED_MALLOC_DECLARATION
1686+extern char *malloc ();
1687+#endif
1688+
1689+#include "ansidecl.h"
1690+#include "libiberty.h"
1691+#include "safe-ctype.h"
1692+#include "sb.h"
1693+#include "macro.h"
1694+#include "asintl.h"
1695+#include "xregex.h"
1696+
1697+char *program_version = "1.2";
1698+
1699+/* This is normally declared in as.h, but we don't include that. We
1700+ need the function because other files linked with gasp.c might call
1701+ it. */
1702+extern void as_abort PARAMS ((const char *, int, const char *));
1703+
1704+/* The default obstack chunk size. If we set this to zero, the
1705+ obstack code will use whatever will fit in a 4096 byte block. This
1706+ is used by the hash table code used by macro.c. */
1707+int chunksize = 0;
1708+
1709+#define MAX_INCLUDES 30 /* Maximum include depth. */
1710+#define MAX_REASONABLE 1000 /* Maximum number of expansions. */
1711+
1712+int unreasonable; /* -u on command line. */
1713+int stats; /* -d on command line. */
1714+int print_line_number; /* -p flag on command line. */
1715+int copysource; /* -c flag on command line. */
1716+int warnings; /* Number of WARNINGs generated so far. */
1717+int errors; /* Number of ERRORs generated so far. */
1718+int fatals; /* Number of fatal ERRORs generated so far (either 0 or 1). */
1719+int alternate = 0; /* -a on command line. */
1720+int mri = 0; /* -M on command line. */
1721+char comment_char = '!';
1722+int radix = 10; /* Default radix. */
1723+
1724+int had_end; /* Seen .END. */
1725+
1726+/* The output stream. */
1727+FILE *outfile;
1728+
1729+/* The attributes of each character are stored as a bit pattern
1730+ chartype, which gives us quick tests. */
1731+
1732+#define FIRSTBIT 1
1733+#define NEXTBIT 2
1734+#define SEPBIT 4
1735+#define WHITEBIT 8
1736+#define COMMENTBIT 16
1737+#define BASEBIT 32
1738+#define ISCOMMENTCHAR(x) (chartype[(unsigned char)(x)] & COMMENTBIT)
1739+#define ISFIRSTCHAR(x) (chartype[(unsigned char)(x)] & FIRSTBIT)
1740+#define ISNEXTCHAR(x) (chartype[(unsigned char)(x)] & NEXTBIT)
1741+#define ISSEP(x) (chartype[(unsigned char)(x)] & SEPBIT)
1742+#define ISWHITE(x) (chartype[(unsigned char)(x)] & WHITEBIT)
1743+#define ISBASE(x) (chartype[(unsigned char)(x)] & BASEBIT)
1744+static char chartype[256];
1745+
1746+/* Conditional assembly uses the `ifstack'. Each aif pushes another
1747+ entry onto the stack, and sets the on flag if it should. The aelse
1748+ sets hadelse, and toggles on. An aend pops a level. We limit to
1749+ 100 levels of nesting, not because we're facists pigs with read
1750+ only minds, but because more than 100 levels of nesting is probably
1751+ a bug in the user's macro structure. */
1752+
1753+#define IFNESTING 100
1754+struct {
1755+ int on; /* Is the level being output. */
1756+ int hadelse; /* Has an aelse been seen. */
1757+} ifstack[IFNESTING];
1758+
1759+int ifi;
1760+
1761+/* The final and intermediate results of expression evaluation are kept in
1762+ exp_t's. Note that a symbol is not an sb, but a pointer into the input
1763+ line. It must be coped somewhere safe before the next line is read in. */
1764+
1765+typedef struct {
1766+ char *name;
1767+ int len;
1768+} symbol;
1769+
1770+typedef struct {
1771+ int value; /* Constant part. */
1772+ symbol add_symbol; /* Name part. */
1773+ symbol sub_symbol; /* Name part. */
1774+} exp_t;
1775+
1776+/* Hashing is done in a pretty standard way. A hash_table has a
1777+ pointer to a vector of pointers to hash_entrys, and the size of the
1778+ vector. A hash_entry contains a union of all the info we like to
1779+ store in hash table. If there is a hash collision, hash_entries
1780+ with the same hash are kept in a chain. */
1781+
1782+/* What the data in a hash_entry means. */
1783+typedef enum {
1784+ hash_integer, /* Name->integer mapping. */
1785+ hash_string, /* Name->string mapping. */
1786+ hash_macro, /* Name is a macro. */
1787+ hash_formal /* Name is a formal argument. */
1788+} hash_type;
1789+
1790+typedef struct hs {
1791+ sb key; /* Symbol name. */
1792+ hash_type type; /* Symbol meaning. */
1793+ union {
1794+ sb s;
1795+ int i;
1796+ struct macro_struct *m;
1797+ struct formal_struct *f;
1798+ } value;
1799+ struct hs *next; /* Next hash_entry with same hash key. */
1800+} hash_entry;
1801+
1802+typedef struct {
1803+ hash_entry **table;
1804+ int size;
1805+} hash_table;
1806+
1807+/* How we nest files and expand macros etc.
1808+
1809+ We keep a stack of of include_stack structs. Each include file
1810+ pushes a new level onto the stack. We keep an sb with a pushback
1811+ too. unget chars are pushed onto the pushback sb, getchars first
1812+ checks the pushback sb before reading from the input stream.
1813+
1814+ Small things are expanded by adding the text of the item onto the
1815+ pushback sb. Larger items are grown by pushing a new level and
1816+ allocating the entire pushback buf for the item. Each time
1817+ something like a macro is expanded, the stack index is changed. We
1818+ can then perform an exitm by popping all entries off the stack with
1819+ the same stack index. If we're being reasonable, we can detect
1820+ recusive expansion by checking the index is reasonably small. */
1821+
1822+typedef enum {
1823+ include_file, include_repeat, include_while, include_macro
1824+} include_type;
1825+
1826+struct include_stack {
1827+ sb pushback; /* Current pushback stream. */
1828+ int pushback_index; /* Next char to read from stream. */
1829+ FILE *handle; /* Open file. */
1830+ sb name; /* Name of file. */
1831+ int linecount; /* Number of lines read so far. */
1832+ include_type type;
1833+ int index; /* Index of this layer. */
1834+} include_stack[MAX_INCLUDES];
1835+
1836+struct include_stack *sp;
1837+#define isp (sp - include_stack)
1838+
1839+/* Include file list. */
1840+
1841+typedef struct include_path {
1842+ struct include_path *next;
1843+ sb path;
1844+} include_path;
1845+
1846+include_path *paths_head;
1847+include_path *paths_tail;
1848+
1849+static void quit PARAMS ((void));
1850+static void hash_new_table PARAMS ((int, hash_table *));
1851+static int hash PARAMS ((sb *));
1852+static hash_entry *hash_create PARAMS ((hash_table *, sb *));
1853+static void hash_add_to_string_table PARAMS ((hash_table *, sb *, sb *, int));
1854+static void hash_add_to_int_table PARAMS ((hash_table *, sb *, int));
1855+static hash_entry *hash_lookup PARAMS ((hash_table *, sb *));
1856+static void checkconst PARAMS ((int, exp_t *));
1857+static int is_flonum PARAMS ((int, sb *));
1858+static int chew_flonum PARAMS ((int, sb *, sb *));
1859+static int sb_strtol PARAMS ((int, sb *, int, int *));
1860+static int level_0 PARAMS ((int, sb *, exp_t *));
1861+static int level_1 PARAMS ((int, sb *, exp_t *));
1862+static int level_2 PARAMS ((int, sb *, exp_t *));
1863+static int level_3 PARAMS ((int, sb *, exp_t *));
1864+static int level_4 PARAMS ((int, sb *, exp_t *));
1865+static int level_5 PARAMS ((int, sb *, exp_t *));
1866+static int exp_parse PARAMS ((int, sb *, exp_t *));
1867+static void exp_string PARAMS ((exp_t *, sb *));
1868+static int exp_get_abs PARAMS ((const char *, int, sb *, int *));
1869+#if 0
1870+static void strip_comments PARAMS ((sb *));
1871+#endif
1872+static void unget PARAMS ((int));
1873+static void include_buf PARAMS ((sb *, sb *, include_type, int));
1874+static void include_print_where_line PARAMS ((FILE *));
1875+static void include_print_line PARAMS ((FILE *));
1876+static int get_line PARAMS ((sb *));
1877+static int grab_label PARAMS ((sb *, sb *));
1878+static void change_base PARAMS ((int, sb *, sb *));
1879+static void do_end PARAMS ((sb *));
1880+static void do_assign PARAMS ((int, int, sb *));
1881+static void do_radix PARAMS ((sb *));
1882+static int get_opsize PARAMS ((int, sb *, int *));
1883+static int eol PARAMS ((int, sb *));
1884+static void do_data PARAMS ((int, sb *, int));
1885+static void do_datab PARAMS ((int, sb *));
1886+static void do_align PARAMS ((int, sb *));
1887+static void do_res PARAMS ((int, sb *, int));
1888+static void do_export PARAMS ((sb *));
1889+static void do_print PARAMS ((int, sb *));
1890+static void do_heading PARAMS ((int, sb *));
1891+static void do_page PARAMS ((void));
1892+static void do_form PARAMS ((int, sb *));
1893+static int get_any_string PARAMS ((int, sb *, sb *, int, int));
1894+static int skip_openp PARAMS ((int, sb *));
1895+static int skip_closep PARAMS ((int, sb *));
1896+static int dolen PARAMS ((int, sb *, sb *));
1897+static int doinstr PARAMS ((int, sb *, sb *));
1898+static int dosubstr PARAMS ((int, sb *, sb *));
1899+static void process_assigns PARAMS ((int, sb *, sb *));
1900+static int get_and_process PARAMS ((int, sb *, sb *));
1901+static void process_file PARAMS ((void));
1902+static void free_old_entry PARAMS ((hash_entry *));
1903+static void do_assigna PARAMS ((int, sb *));
1904+static void do_assignc PARAMS ((int, sb *));
1905+static void do_reg PARAMS ((int, sb *));
1906+static int condass_lookup_name PARAMS ((sb *, int, sb *, int));
1907+static int whatcond PARAMS ((int, sb *, int *));
1908+static int istrue PARAMS ((int, sb *));
1909+static void do_aif PARAMS ((int, sb *));
1910+static void do_aelse PARAMS ((void));
1911+static void do_aendi PARAMS ((void));
1912+static int condass_on PARAMS ((void));
1913+static void do_if PARAMS ((int, sb *, int));
1914+static int get_mri_string PARAMS ((int, sb *, sb *, int));
1915+static void do_ifc PARAMS ((int, sb *, int));
1916+static void do_aendr PARAMS ((void));
1917+static void do_awhile PARAMS ((int, sb *));
1918+static void do_aendw PARAMS ((void));
1919+static void do_exitm PARAMS ((void));
1920+static void do_arepeat PARAMS ((int, sb *));
1921+static void do_endm PARAMS ((void));
1922+static void do_irp PARAMS ((int, sb *, int));
1923+static void do_local PARAMS ((int, sb *));
1924+static void do_macro PARAMS ((int, sb *));
1925+static int macro_op PARAMS ((int, sb *));
1926+static int getstring PARAMS ((int, sb *, sb *));
1927+static void do_sdata PARAMS ((int, sb *, int));
1928+static void do_sdatab PARAMS ((int, sb *));
1929+static int new_file PARAMS ((const char *));
1930+static void do_include PARAMS ((int, sb *));
1931+static void include_pop PARAMS ((void));
1932+static int get PARAMS ((void));
1933+static int linecount PARAMS ((void));
1934+static int include_next_index PARAMS ((void));
1935+static void chartype_init PARAMS ((void));
1936+static int process_pseudo_op PARAMS ((int, sb *, sb *));
1937+static void add_keyword PARAMS ((const char *, int));
1938+static void process_init PARAMS ((void));
1939+static void do_define PARAMS ((const char *));
1940+static void show_usage PARAMS ((FILE *, int));
1941+static void show_help PARAMS ((void));
1942+
1943+#define FATAL(x) \
1944+ do \
1945+ { \
1946+ include_print_where_line (stderr); \
1947+ fprintf x; \
1948+ fatals++; \
1949+ quit (); \
1950+ } \
1951+ while (0)
1952+
1953+#define ERROR(x) \
1954+ do \
1955+ { \
1956+ include_print_where_line (stderr); \
1957+ fprintf x; \
1958+ errors++; \
1959+ } \
1960+ while (0)
1961+
1962+#define WARNING(x) \
1963+ do \
1964+ { \
1965+ include_print_where_line (stderr); \
1966+ fprintf x; \
1967+ warnings++; \
1968+ } \
1969+ while (0)
1970+
1971+/* Exit the program and return the right ERROR code. */
1972+
1973+static void
1974+quit ()
1975+{
1976+ int exitcode;
1977+ if (fatals + errors)
1978+ exitcode = 1;
1979+ else
1980+ exitcode = 0;
1981+
1982+ if (stats)
1983+ {
1984+ int i;
1985+ for (i = 0; i < sb_max_power_two; i++)
1986+ {
1987+ fprintf (stderr, "strings size %8d : %d\n",
1988+ 1 << i, string_count[i]);
1989+ }
1990+ }
1991+ exit (exitcode);
1992+}
1993+
1994+/* Hash table maintenance. */
1995+
1996+/* Build a new hash table with size buckets
1997+ and fill in the info at ptr. */
1998+
1999+static void
2000+hash_new_table (size, ptr)
2001+ int size;
2002+ hash_table *ptr;
2003+{
2004+ int i;
2005+ ptr->size = size;
2006+ ptr->table = (hash_entry **) xmalloc (size * (sizeof (hash_entry *)));
2007+ /* Fill with null-pointer, not zero-bit-pattern. */
2008+ for (i = 0; i < size; i++)
2009+ ptr->table[i] = 0;
2010+}
2011+
2012+/* Calculate and return the hash value of the sb at key. */
2013+
2014+static int
2015+hash (key)
2016+ sb *key;
2017+{
2018+ int k = 0x1234;
2019+ int i;
2020+ char *p = key->ptr;
2021+ for (i = 0; i < key->len; i++)
2022+ {
2023+ k ^= (k << 2) ^ *p;
2024+ p++;
2025+ }
2026+ return k & 0xf0fff;
2027+}
2028+
2029+/* Look up key in hash_table tab. If present, then return it,
2030+ otherwise build a new one and fill it with hash_integer. */
2031+
2032+static hash_entry *
2033+hash_create (tab, key)
2034+ hash_table *tab;
2035+ sb *key;
2036+{
2037+ int k = hash (key) % tab->size;
2038+ hash_entry *p;
2039+ hash_entry **table = tab->table;
2040+
2041+ p = table[k];
2042+
2043+ while (1)
2044+ {
2045+ if (!p)
2046+ {
2047+ hash_entry *n = (hash_entry *) xmalloc (sizeof (hash_entry));
2048+ n->next = table[k];
2049+ sb_new (&n->key);
2050+ sb_add_sb (&n->key, key);
2051+ table[k] = n;
2052+ n->type = hash_integer;
2053+ return n;
2054+ }
2055+ if (strncmp (table[k]->key.ptr, key->ptr, key->len) == 0)
2056+ {
2057+ return p;
2058+ }
2059+ p = p->next;
2060+ }
2061+}
2062+
2063+/* Add sb name with key into hash_table tab.
2064+ If replacing old value and again, then ERROR. */
2065+
2066+static void
2067+hash_add_to_string_table (tab, key, name, again)
2068+ hash_table *tab;
2069+ sb *key;
2070+ sb *name;
2071+ int again;
2072+{
2073+ hash_entry *ptr = hash_create (tab, key);
2074+ if (ptr->type == hash_integer)
2075+ {
2076+ sb_new (&ptr->value.s);
2077+ }
2078+ if (ptr->value.s.len)
2079+ {
2080+ if (!again)
2081+ ERROR ((stderr, _("redefinition not allowed\n")));
2082+ }
2083+
2084+ ptr->type = hash_string;
2085+ sb_reset (&ptr->value.s);
2086+
2087+ sb_add_sb (&ptr->value.s, name);
2088+}
2089+
2090+/* Add integer name to hash_table tab with sb key. */
2091+
2092+static void
2093+hash_add_to_int_table (tab, key, name)
2094+ hash_table *tab;
2095+ sb *key;
2096+ int name;
2097+{
2098+ hash_entry *ptr = hash_create (tab, key);
2099+ ptr->value.i = name;
2100+}
2101+
2102+/* Look up sb key in hash_table tab.
2103+ If found, return hash_entry result, else 0. */
2104+
2105+static hash_entry *
2106+hash_lookup (tab, key)
2107+ hash_table *tab;
2108+ sb *key;
2109+{
2110+ int k = hash (key) % tab->size;
2111+ hash_entry **table = tab->table;
2112+ hash_entry *p = table[k];
2113+ while (p)
2114+ {
2115+ if (p->key.len == key->len
2116+ && strncmp (p->key.ptr, key->ptr, key->len) == 0)
2117+ return p;
2118+ p = p->next;
2119+ }
2120+ return 0;
2121+}
2122+
2123+/* expressions
2124+
2125+ are handled in a really simple recursive decent way. each bit of
2126+ the machine takes an index into an sb and a pointer to an exp_t,
2127+ modifies the *exp_t and returns the index of the first character
2128+ past the part of the expression parsed.
2129+
2130+ expression precedence:
2131+ ( )
2132+ unary + - ~
2133+ * /
2134+ + -
2135+ &
2136+ | ~
2137+*/
2138+
2139+/* Make sure that the exp_t at term is constant.
2140+ If not the give the op ERROR. */
2141+
2142+static void
2143+checkconst (op, term)
2144+ int op;
2145+ exp_t *term;
2146+{
2147+ if (term->add_symbol.len
2148+ || term->sub_symbol.len)
2149+ {
2150+ ERROR ((stderr, _("the %c operator cannot take non-absolute arguments.\n"), op));
2151+ }
2152+}
2153+
2154+/* Chew the flonum from the string starting at idx. Adjust idx to
2155+ point to the next character after the flonum. */
2156+
2157+static int
2158+chew_flonum (idx, string, out)
2159+ int idx;
2160+ sb *string;
2161+ sb *out;
2162+{
2163+ sb buf;
2164+ regex_t reg;
2165+ regmatch_t match;
2166+
2167+ /* Duplicate and null terminate `string'. */
2168+ sb_new (&buf);
2169+ sb_add_sb (&buf, string);
2170+ sb_add_char (&buf, '\0');
2171+
2172+ if (regcomp (&reg, "([0-9]*\\.[0-9]+([eE][+-]?[0-9]+)?)", REG_EXTENDED) != 0)
2173+ return idx;
2174+ if (regexec (&reg, &buf.ptr[idx], 1, &match, 0) != 0)
2175+ return idx;
2176+
2177+ /* Copy the match to the output. */
2178+ assert (match.rm_eo >= match.rm_so);
2179+ sb_add_buffer (out, &buf.ptr[idx], match.rm_eo - match.rm_so);
2180+
2181+ sb_kill (&buf);
2182+ regfree (&reg);
2183+ idx += match.rm_eo;
2184+ return idx;
2185+}
2186+
2187+static int
2188+is_flonum (idx, string)
2189+ int idx;
2190+ sb *string;
2191+{
2192+ sb buf;
2193+ regex_t reg;
2194+ int rc;
2195+
2196+ /* Duplicate and null terminate `string'. */
2197+ sb_new (&buf);
2198+ sb_add_sb (&buf, string);
2199+ sb_add_char (&buf, '\0');
2200+
2201+ if (regcomp (&reg, "^[0-9]*\\.[0-9]+([eE][+-]?[0-9]+)?", REG_EXTENDED) != 0)
2202+ return 0;
2203+
2204+ rc = regexec (&reg, &buf.ptr[idx], 0, NULL, 0);
2205+ sb_kill (&buf);
2206+ regfree (&reg);
2207+ return (rc == 0);
2208+}
2209+
2210+/* Turn the number in string at idx into a number of base, fill in
2211+ ptr, and return the index of the first character not in the number. */
2212+
2213+static int
2214+sb_strtol (idx, string, base, ptr)
2215+ int idx;
2216+ sb *string;
2217+ int base;
2218+ int *ptr;
2219+{
2220+ int value = 0;
2221+ idx = sb_skip_white (idx, string);
2222+
2223+ while (idx < string->len)
2224+ {
2225+ int ch = string->ptr[idx];
2226+ int dig = 0;
2227+ if (ISDIGIT (ch))
2228+ dig = ch - '0';
2229+ else if (ch >= 'a' && ch <= 'f')
2230+ dig = ch - 'a' + 10;
2231+ else if (ch >= 'A' && ch <= 'F')
2232+ dig = ch - 'A' + 10;
2233+ else
2234+ break;
2235+
2236+ if (dig >= base)
2237+ break;
2238+
2239+ value = value * base + dig;
2240+ idx++;
2241+ }
2242+ *ptr = value;
2243+ return idx;
2244+}
2245+
2246+static int
2247+level_0 (idx, string, lhs)
2248+ int idx;
2249+ sb *string;
2250+ exp_t *lhs;
2251+{
2252+ lhs->add_symbol.len = 0;
2253+ lhs->add_symbol.name = 0;
2254+
2255+ lhs->sub_symbol.len = 0;
2256+ lhs->sub_symbol.name = 0;
2257+
2258+ idx = sb_skip_white (idx, string);
2259+
2260+ lhs->value = 0;
2261+
2262+ if (ISDIGIT (string->ptr[idx]))
2263+ {
2264+ idx = sb_strtol (idx, string, 10, &lhs->value);
2265+ }
2266+ else if (ISFIRSTCHAR (string->ptr[idx]))
2267+ {
2268+ int len = 0;
2269+ lhs->add_symbol.name = string->ptr + idx;
2270+ while (idx < string->len && ISNEXTCHAR (string->ptr[idx]))
2271+ {
2272+ idx++;
2273+ len++;
2274+ }
2275+ lhs->add_symbol.len = len;
2276+ }
2277+ else if (string->ptr[idx] == '"')
2278+ {
2279+ sb acc;
2280+ sb_new (&acc);
2281+ ERROR ((stderr, _("string where expression expected.\n")));
2282+ idx = getstring (idx, string, &acc);
2283+ sb_kill (&acc);
2284+ }
2285+ else
2286+ {
2287+ ERROR ((stderr, _("can't find primary in expression.\n")));
2288+ idx++;
2289+ }
2290+ return sb_skip_white (idx, string);
2291+}
2292+
2293+static int
2294+level_1 (idx, string, lhs)
2295+ int idx;
2296+ sb *string;
2297+ exp_t *lhs;
2298+{
2299+ idx = sb_skip_white (idx, string);
2300+
2301+ switch (string->ptr[idx])
2302+ {
2303+ case '+':
2304+ idx = level_1 (idx + 1, string, lhs);
2305+ break;
2306+ case '~':
2307+ idx = level_1 (idx + 1, string, lhs);
2308+ checkconst ('~', lhs);
2309+ lhs->value = ~lhs->value;
2310+ break;
2311+ case '-':
2312+ {
2313+ symbol t;
2314+ idx = level_1 (idx + 1, string, lhs);
2315+ lhs->value = -lhs->value;
2316+ t = lhs->add_symbol;
2317+ lhs->add_symbol = lhs->sub_symbol;
2318+ lhs->sub_symbol = t;
2319+ break;
2320+ }
2321+ case '(':
2322+ idx++;
2323+ idx = level_5 (sb_skip_white (idx, string), string, lhs);
2324+ if (string->ptr[idx] != ')')
2325+ ERROR ((stderr, _("misplaced closing parens.\n")));
2326+ else
2327+ idx++;
2328+ break;
2329+ default:
2330+ idx = level_0 (idx, string, lhs);
2331+ break;
2332+ }
2333+ return sb_skip_white (idx, string);
2334+}
2335+
2336+static int
2337+level_2 (idx, string, lhs)
2338+ int idx;
2339+ sb *string;
2340+ exp_t *lhs;
2341+{
2342+ exp_t rhs;
2343+
2344+ idx = level_1 (idx, string, lhs);
2345+
2346+ while (idx < string->len && (string->ptr[idx] == '*'
2347+ || string->ptr[idx] == '/'))
2348+ {
2349+ char op = string->ptr[idx++];
2350+ idx = level_1 (idx, string, &rhs);
2351+ switch (op)
2352+ {
2353+ case '*':
2354+ checkconst ('*', lhs);
2355+ checkconst ('*', &rhs);
2356+ lhs->value *= rhs.value;
2357+ break;
2358+ case '/':
2359+ checkconst ('/', lhs);
2360+ checkconst ('/', &rhs);
2361+ if (rhs.value == 0)
2362+ ERROR ((stderr, _("attempt to divide by zero.\n")));
2363+ else
2364+ lhs->value /= rhs.value;
2365+ break;
2366+ }
2367+ }
2368+ return sb_skip_white (idx, string);
2369+}
2370+
2371+static int
2372+level_3 (idx, string, lhs)
2373+ int idx;
2374+ sb *string;
2375+ exp_t *lhs;
2376+{
2377+ exp_t rhs;
2378+
2379+ idx = level_2 (idx, string, lhs);
2380+
2381+ while (idx < string->len
2382+ && (string->ptr[idx] == '+'
2383+ || string->ptr[idx] == '-'))
2384+ {
2385+ char op = string->ptr[idx++];
2386+ idx = level_2 (idx, string, &rhs);
2387+ switch (op)
2388+ {
2389+ case '+':
2390+ lhs->value += rhs.value;
2391+ if (lhs->add_symbol.name && rhs.add_symbol.name)
2392+ {
2393+ ERROR ((stderr, _("can't add two relocatable expressions\n")));
2394+ }
2395+ /* Change nn+symbol to symbol + nn. */
2396+ if (rhs.add_symbol.name)
2397+ {
2398+ lhs->add_symbol = rhs.add_symbol;
2399+ }
2400+ break;
2401+ case '-':
2402+ lhs->value -= rhs.value;
2403+ lhs->sub_symbol = rhs.add_symbol;
2404+ break;
2405+ }
2406+ }
2407+ return sb_skip_white (idx, string);
2408+}
2409+
2410+static int
2411+level_4 (idx, string, lhs)
2412+ int idx;
2413+ sb *string;
2414+ exp_t *lhs;
2415+{
2416+ exp_t rhs;
2417+
2418+ idx = level_3 (idx, string, lhs);
2419+
2420+ while (idx < string->len &&
2421+ string->ptr[idx] == '&')
2422+ {
2423+ char op = string->ptr[idx++];
2424+ idx = level_3 (idx, string, &rhs);
2425+ switch (op)
2426+ {
2427+ case '&':
2428+ checkconst ('&', lhs);
2429+ checkconst ('&', &rhs);
2430+ lhs->value &= rhs.value;
2431+ break;
2432+ }
2433+ }
2434+ return sb_skip_white (idx, string);
2435+}
2436+
2437+static int
2438+level_5 (idx, string, lhs)
2439+ int idx;
2440+ sb *string;
2441+ exp_t *lhs;
2442+{
2443+ exp_t rhs;
2444+
2445+ idx = level_4 (idx, string, lhs);
2446+
2447+ while (idx < string->len
2448+ && (string->ptr[idx] == '|' || string->ptr[idx] == '~'))
2449+ {
2450+ char op = string->ptr[idx++];
2451+ idx = level_4 (idx, string, &rhs);
2452+ switch (op)
2453+ {
2454+ case '|':
2455+ checkconst ('|', lhs);
2456+ checkconst ('|', &rhs);
2457+ lhs->value |= rhs.value;
2458+ break;
2459+ case '~':
2460+ checkconst ('~', lhs);
2461+ checkconst ('~', &rhs);
2462+ lhs->value ^= rhs.value;
2463+ break;
2464+ }
2465+ }
2466+ return sb_skip_white (idx, string);
2467+}
2468+
2469+/* Parse the expression at offset idx into string, fill up res with
2470+ the result. Return the index of the first char past the
2471+ expression. */
2472+
2473+static int
2474+exp_parse (idx, string, res)
2475+ int idx;
2476+ sb *string;
2477+ exp_t *res;
2478+{
2479+ return level_5 (sb_skip_white (idx, string), string, res);
2480+}
2481+
2482+/* Turn the expression at exp into text and glue it onto the end of
2483+ string. */
2484+
2485+static void
2486+exp_string (exp, string)
2487+ exp_t *exp;
2488+ sb *string;
2489+{
2490+ int np = 0;
2491+ int ad = 0;
2492+ sb_reset (string);
2493+
2494+ if (exp->add_symbol.len)
2495+ {
2496+ sb_add_buffer (string, exp->add_symbol.name, exp->add_symbol.len);
2497+ np = 1;
2498+ ad = 1;
2499+ }
2500+ if (exp->value)
2501+ {
2502+ char buf[20];
2503+ if (np)
2504+ sb_add_char (string, '+');
2505+ sprintf (buf, "%d", exp->value);
2506+ sb_add_string (string, buf);
2507+ np = 1;
2508+ ad = 1;
2509+ }
2510+ if (exp->sub_symbol.len)
2511+ {
2512+ sb_add_char (string, '-');
2513+ sb_add_buffer (string, exp->add_symbol.name, exp->add_symbol.len);
2514+ np = 0;
2515+ ad = 1;
2516+ }
2517+
2518+ if (!ad)
2519+ sb_add_char (string, '0');
2520+}
2521+
2522+/* Parse the expression at offset idx into sb in. Return the value in
2523+ val. If the expression is not constant, give ERROR emsg. Return
2524+ the index of the first character past the end of the expression. */
2525+
2526+static int
2527+exp_get_abs (emsg, idx, in, val)
2528+ const char *emsg;
2529+ int idx;
2530+ sb *in;
2531+ int *val;
2532+{
2533+ exp_t res;
2534+ idx = exp_parse (idx, in, &res);
2535+ if (res.add_symbol.len || res.sub_symbol.len)
2536+ ERROR ((stderr, "%s", emsg));
2537+ *val = res.value;
2538+ return idx;
2539+}
2540+
2541+/* Current label parsed from line. */
2542+sb label;
2543+
2544+/* Hash table for all assigned variables. */
2545+hash_table assign_hash_table;
2546+
2547+/* Hash table for keyword. */
2548+hash_table keyword_hash_table;
2549+
2550+/* Hash table for eq variables. */
2551+hash_table vars;
2552+
2553+#define in_comment ';'
2554+
2555+#if 0
2556+static void
2557+strip_comments (out)
2558+ sb *out;
2559+{
2560+ char *s = out->ptr;
2561+ int i = 0;
2562+ for (i = 0; i < out->len; i++)
2563+ {
2564+ if (ISCOMMENTCHAR (s[i]))
2565+ {
2566+ out->len = i;
2567+ return;
2568+ }
2569+ }
2570+}
2571+#endif
2572+
2573+/* Push back character ch so that it can be read again. */
2574+
2575+static void
2576+unget (ch)
2577+ int ch;
2578+{
2579+ if (ch == '\n')
2580+ {
2581+ sp->linecount--;
2582+ }
2583+ if (sp->pushback_index)
2584+ sp->pushback_index--;
2585+ else
2586+ sb_add_char (&sp->pushback, ch);
2587+}
2588+
2589+/* Push the sb ptr onto the include stack, with the given name, type
2590+ and index. */
2591+
2592+static void
2593+include_buf (name, ptr, type, index)
2594+ sb *name;
2595+ sb *ptr;
2596+ include_type type;
2597+ int index;
2598+{
2599+ sp++;
2600+ if (sp - include_stack >= MAX_INCLUDES)
2601+ FATAL ((stderr, _("unreasonable nesting.\n")));
2602+ sb_new (&sp->name);
2603+ sb_add_sb (&sp->name, name);
2604+ sp->handle = 0;
2605+ sp->linecount = 1;
2606+ sp->pushback_index = 0;
2607+ sp->type = type;
2608+ sp->index = index;
2609+ sb_new (&sp->pushback);
2610+ sb_add_sb (&sp->pushback, ptr);
2611+}
2612+
2613+/* Used in ERROR messages, print info on where the include stack is
2614+ onto file. */
2615+
2616+static void
2617+include_print_where_line (file)
2618+ FILE *file;
2619+{
2620+ struct include_stack *p = include_stack + 1;
2621+
2622+ while (p <= sp)
2623+ {
2624+ fprintf (file, "%s:%d ", sb_name (&p->name), p->linecount - 1);
2625+ p++;
2626+ }
2627+}
2628+
2629+/* Used in listings, print the line number onto file. */
2630+
2631+static void
2632+include_print_line (file)
2633+ FILE *file;
2634+{
2635+ int n;
2636+ struct include_stack *p = include_stack + 1;
2637+
2638+ n = fprintf (file, "%4d", p->linecount);
2639+ p++;
2640+ while (p <= sp)
2641+ {
2642+ n += fprintf (file, ".%d", p->linecount);
2643+ p++;
2644+ }
2645+ while (n < 8 * 3)
2646+ {
2647+ fprintf (file, " ");
2648+ n++;
2649+ }
2650+}
2651+
2652+/* Read a line from the top of the include stack into sb in. */
2653+
2654+static int
2655+get_line (in)
2656+ sb *in;
2657+{
2658+ int online = 0;
2659+ int more = 1;
2660+
2661+ if (copysource)
2662+ {
2663+ putc (comment_char, outfile);
2664+ if (print_line_number)
2665+ include_print_line (outfile);
2666+ }
2667+
2668+ while (1)
2669+ {
2670+ int ch = get ();
2671+
2672+ while (ch == '\r')
2673+ ch = get ();
2674+
2675+ if (ch == EOF)
2676+ {
2677+ if (online)
2678+ {
2679+ WARNING ((stderr, _("End of file not at start of line.\n")));
2680+ if (copysource)
2681+ putc ('\n', outfile);
2682+ ch = '\n';
2683+ }
2684+ else
2685+ more = 0;
2686+ break;
2687+ }
2688+
2689+ if (copysource)
2690+ {
2691+ putc (ch, outfile);
2692+ }
2693+
2694+ if (ch == '\n')
2695+ {
2696+ ch = get ();
2697+ online = 0;
2698+ if (ch == '+')
2699+ {
2700+ /* Continued line. */
2701+ if (copysource)
2702+ {
2703+ putc (comment_char, outfile);
2704+ putc ('+', outfile);
2705+ }
2706+ ch = get ();
2707+ }
2708+ else
2709+ {
2710+ if (ch != EOF)
2711+ unget (ch);
2712+ break;
2713+ }
2714+ }
2715+ else
2716+ {
2717+ sb_add_char (in, ch);
2718+ }
2719+ online++;
2720+ }
2721+
2722+ return more;
2723+}
2724+
2725+/* Find a label from sb in and put it in out. */
2726+
2727+static int
2728+grab_label (in, out)
2729+ sb *in;
2730+ sb *out;
2731+{
2732+ int i = 0;
2733+ sb_reset (out);
2734+ if (ISFIRSTCHAR (in->ptr[i]) || in->ptr[i] == '\\')
2735+ {
2736+ sb_add_char (out, in->ptr[i]);
2737+ i++;
2738+ while ((ISNEXTCHAR (in->ptr[i])
2739+ || in->ptr[i] == '\\'
2740+ || in->ptr[i] == '&')
2741+ && i < in->len)
2742+ {
2743+ sb_add_char (out, in->ptr[i]);
2744+ i++;
2745+ }
2746+ }
2747+ return i;
2748+}
2749+
2750+/* Find all strange base stuff and turn into decimal. Also
2751+ find all the other numbers and convert them from the default radix. */
2752+
2753+static void
2754+change_base (idx, in, out)
2755+ int idx;
2756+ sb *in;
2757+ sb *out;
2758+{
2759+ char buffer[20];
2760+
2761+ while (idx < in->len)
2762+ {
2763+ if (in->ptr[idx] == '\\'
2764+ && idx + 1 < in->len
2765+ && in->ptr[idx + 1] == '(')
2766+ {
2767+ idx += 2;
2768+ while (idx < in->len
2769+ && in->ptr[idx] != ')')
2770+ {
2771+ sb_add_char (out, in->ptr[idx]);
2772+ idx++;
2773+ }
2774+ if (idx < in->len)
2775+ idx++;
2776+ }
2777+ else if (idx < in->len - 1 && in->ptr[idx + 1] == '\'' && ! mri)
2778+ {
2779+ int base;
2780+ int value;
2781+ switch (in->ptr[idx])
2782+ {
2783+ case 'b':
2784+ case 'B':
2785+ base = 2;
2786+ break;
2787+ case 'q':
2788+ case 'Q':
2789+ base = 8;
2790+ break;
2791+ case 'h':
2792+ case 'H':
2793+ base = 16;
2794+ break;
2795+ case 'd':
2796+ case 'D':
2797+ base = 10;
2798+ break;
2799+ default:
2800+ ERROR ((stderr, _("Illegal base character %c.\n"), in->ptr[idx]));
2801+ base = 10;
2802+ break;
2803+ }
2804+
2805+ idx = sb_strtol (idx + 2, in, base, &value);
2806+ sprintf (buffer, "%d", value);
2807+ sb_add_string (out, buffer);
2808+ }
2809+ else if (ISFIRSTCHAR (in->ptr[idx]))
2810+ {
2811+ /* Copy entire names through quickly. */
2812+ sb_add_char (out, in->ptr[idx]);
2813+ idx++;
2814+ while (idx < in->len && ISNEXTCHAR (in->ptr[idx]))
2815+ {
2816+ sb_add_char (out, in->ptr[idx]);
2817+ idx++;
2818+ }
2819+ }
2820+ else if (is_flonum (idx, in))
2821+ {
2822+ idx = chew_flonum (idx, in, out);
2823+ }
2824+ else if (ISDIGIT (in->ptr[idx]))
2825+ {
2826+ int value;
2827+ /* All numbers must start with a digit, let's chew it and
2828+ spit out decimal. */
2829+ idx = sb_strtol (idx, in, radix, &value);
2830+ sprintf (buffer, "%d", value);
2831+ sb_add_string (out, buffer);
2832+
2833+ /* Skip all undigsested letters. */
2834+ while (idx < in->len && ISNEXTCHAR (in->ptr[idx]))
2835+ {
2836+ sb_add_char (out, in->ptr[idx]);
2837+ idx++;
2838+ }
2839+ }
2840+ else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'')
2841+ {
2842+ char tchar = in->ptr[idx];
2843+ /* Copy entire names through quickly. */
2844+ sb_add_char (out, in->ptr[idx]);
2845+ idx++;
2846+ while (idx < in->len && in->ptr[idx] != tchar)
2847+ {
2848+ sb_add_char (out, in->ptr[idx]);
2849+ idx++;
2850+ }
2851+ }
2852+ else
2853+ {
2854+ /* Nothing special, just pass it through. */
2855+ sb_add_char (out, in->ptr[idx]);
2856+ idx++;
2857+ }
2858+ }
2859+
2860+}
2861+
2862+/* .end */
2863+
2864+static void
2865+do_end (in)
2866+ sb *in;
2867+{
2868+ had_end = 1;
2869+ if (mri)
2870+ fprintf (outfile, "%s\n", sb_name (in));
2871+}
2872+
2873+/* .assign */
2874+
2875+static void
2876+do_assign (again, idx, in)
2877+ int again;
2878+ int idx;
2879+ sb *in;
2880+{
2881+ /* Stick label in symbol table with following value. */
2882+ exp_t e;
2883+ sb acc;
2884+
2885+ sb_new (&acc);
2886+ idx = exp_parse (idx, in, &e);
2887+ exp_string (&e, &acc);
2888+ hash_add_to_string_table (&assign_hash_table, &label, &acc, again);
2889+ sb_kill (&acc);
2890+}
2891+
2892+/* .radix [b|q|d|h] */
2893+
2894+static void
2895+do_radix (ptr)
2896+ sb *ptr;
2897+{
2898+ int idx = sb_skip_white (0, ptr);
2899+ switch (ptr->ptr[idx])
2900+ {
2901+ case 'B':
2902+ case 'b':
2903+ radix = 2;
2904+ break;
2905+ case 'q':
2906+ case 'Q':
2907+ radix = 8;
2908+ break;
2909+ case 'd':
2910+ case 'D':
2911+ radix = 10;
2912+ break;
2913+ case 'h':
2914+ case 'H':
2915+ radix = 16;
2916+ break;
2917+ default:
2918+ ERROR ((stderr, _("radix is %c must be one of b, q, d or h"), radix));
2919+ }
2920+}
2921+
2922+/* Parse off a .b, .w or .l. */
2923+
2924+static int
2925+get_opsize (idx, in, size)
2926+ int idx;
2927+ sb *in;
2928+ int *size;
2929+{
2930+ *size = 4;
2931+ if (in->ptr[idx] == '.')
2932+ {
2933+ idx++;
2934+ }
2935+ switch (in->ptr[idx])
2936+ {
2937+ case 'b':
2938+ case 'B':
2939+ *size = 1;
2940+ break;
2941+ case 'w':
2942+ case 'W':
2943+ *size = 2;
2944+ break;
2945+ case 'l':
2946+ case 'L':
2947+ *size = 4;
2948+ break;
2949+ case ' ':
2950+ case '\t':
2951+ break;
2952+ default:
2953+ ERROR ((stderr, _("size must be one of b, w or l, is %c.\n"), in->ptr[idx]));
2954+ break;
2955+ }
2956+ idx++;
2957+
2958+ return idx;
2959+}
2960+
2961+static int
2962+eol (idx, line)
2963+ int idx;
2964+ sb *line;
2965+{
2966+ idx = sb_skip_white (idx, line);
2967+ if (idx < line->len
2968+ && ISCOMMENTCHAR(line->ptr[idx]))
2969+ return 1;
2970+ if (idx >= line->len)
2971+ return 1;
2972+ return 0;
2973+}
2974+
2975+/* .data [.b|.w|.l] <data>*
2976+ or d[bwl] <data>* */
2977+
2978+static void
2979+do_data (idx, in, size)
2980+ int idx;
2981+ sb *in;
2982+ int size;
2983+{
2984+ int opsize = 4;
2985+ char *opname = ".yikes!";
2986+ sb acc;
2987+ sb_new (&acc);
2988+
2989+ if (!size)
2990+ {
2991+ idx = get_opsize (idx, in, &opsize);
2992+ }
2993+ else
2994+ {
2995+ opsize = size;
2996+ }
2997+ switch (opsize)
2998+ {
2999+ case 4:
3000+ opname = ".long";
3001+ break;
3002+ case 2:
3003+ opname = ".short";
3004+ break;
3005+ case 1:
3006+ opname = ".byte";
3007+ break;
3008+ }
3009+
3010+ fprintf (outfile, "%s\t", opname);
3011+
3012+ idx = sb_skip_white (idx, in);
3013+
3014+ if (alternate
3015+ && idx < in->len
3016+ && in->ptr[idx] == '"')
3017+ {
3018+ int i;
3019+ idx = getstring (idx, in, &acc);
3020+ for (i = 0; i < acc.len; i++)
3021+ {
3022+ if (i)
3023+ fprintf (outfile, ",");
3024+ fprintf (outfile, "%d", acc.ptr[i]);
3025+ }
3026+ }
3027+ else
3028+ {
3029+ while (!eol (idx, in))
3030+ {
3031+ exp_t e;
3032+ idx = exp_parse (idx, in, &e);
3033+ exp_string (&e, &acc);
3034+ sb_add_char (&acc, 0);
3035+ fprintf (outfile, "%s", acc.ptr);
3036+ if (idx < in->len && in->ptr[idx] == ',')
3037+ {
3038+ fprintf (outfile, ",");
3039+ idx++;
3040+ }
3041+ }
3042+ }
3043+ sb_kill (&acc);
3044+ sb_print_at (outfile, idx, in);
3045+ fprintf (outfile, "\n");
3046+}
3047+
3048+/* .datab [.b|.w|.l] <repeat>,<fill> */
3049+
3050+static void
3051+do_datab (idx, in)
3052+ int idx;
3053+ sb *in;
3054+{
3055+ int opsize;
3056+ int repeat;
3057+ int fill;
3058+
3059+ idx = get_opsize (idx, in, &opsize);
3060+
3061+ idx = exp_get_abs (_("datab repeat must be constant.\n"), idx, in, &repeat);
3062+ idx = sb_skip_comma (idx, in);
3063+ idx = exp_get_abs (_("datab data must be absolute.\n"), idx, in, &fill);
3064+
3065+ fprintf (outfile, ".fill\t%d,%d,%d\n", repeat, opsize, fill);
3066+}
3067+
3068+/* .align <size> */
3069+
3070+static void
3071+do_align (idx, in)
3072+ int idx;
3073+ sb *in;
3074+{
3075+ int al, have_fill, fill;
3076+
3077+ idx = exp_get_abs (_("align needs absolute expression.\n"), idx, in, &al);
3078+ idx = sb_skip_white (idx, in);
3079+ have_fill = 0;
3080+ fill = 0;
3081+ if (! eol (idx, in))
3082+ {
3083+ idx = sb_skip_comma (idx, in);
3084+ idx = exp_get_abs (_(".align needs absolute fill value.\n"), idx, in,
3085+ &fill);
3086+ have_fill = 1;
3087+ }
3088+
3089+ fprintf (outfile, ".align %d", al);
3090+ if (have_fill)
3091+ fprintf (outfile, ",%d", fill);
3092+ fprintf (outfile, "\n");
3093+}
3094+
3095+/* .res[.b|.w|.l] <size> */
3096+
3097+static void
3098+do_res (idx, in, type)
3099+ int idx;
3100+ sb *in;
3101+ int type;
3102+{
3103+ int size = 4;
3104+ int count = 0;
3105+
3106+ idx = get_opsize (idx, in, &size);
3107+ while (!eol (idx, in))
3108+ {
3109+ idx = sb_skip_white (idx, in);
3110+ if (in->ptr[idx] == ',')
3111+ idx++;
3112+ idx = exp_get_abs (_("res needs absolute expression for fill count.\n"), idx, in, &count);
3113+
3114+ if (type == 'c' || type == 'z')
3115+ count++;
3116+
3117+ fprintf (outfile, ".space %d\n", count * size);
3118+ }
3119+}
3120+
3121+/* .export */
3122+
3123+static void
3124+do_export (in)
3125+ sb *in;
3126+{
3127+ fprintf (outfile, ".global %s\n", sb_name (in));
3128+}
3129+
3130+/* .print [list] [nolist] */
3131+
3132+static void
3133+do_print (idx, in)
3134+ int idx;
3135+ sb *in;
3136+{
3137+ idx = sb_skip_white (idx, in);
3138+ while (idx < in->len)
3139+ {
3140+ if (strncasecmp (in->ptr + idx, "LIST", 4) == 0)
3141+ {
3142+ fprintf (outfile, ".list\n");
3143+ idx += 4;
3144+ }
3145+ else if (strncasecmp (in->ptr + idx, "NOLIST", 6) == 0)
3146+ {
3147+ fprintf (outfile, ".nolist\n");
3148+ idx += 6;
3149+ }
3150+ idx++;
3151+ }
3152+}
3153+
3154+/* .head */
3155+
3156+static void
3157+do_heading (idx, in)
3158+ int idx;
3159+ sb *in;
3160+{
3161+ sb head;
3162+ sb_new (&head);
3163+ idx = getstring (idx, in, &head);
3164+ fprintf (outfile, ".title \"%s\"\n", sb_name (&head));
3165+ sb_kill (&head);
3166+}
3167+
3168+/* .page */
3169+
3170+static void
3171+do_page ()
3172+{
3173+ fprintf (outfile, ".eject\n");
3174+}
3175+
3176+/* .form [lin=<value>] [col=<value>] */
3177+
3178+static void
3179+do_form (idx, in)
3180+ int idx;
3181+ sb *in;
3182+{
3183+ int lines = 60;
3184+ int columns = 132;
3185+ idx = sb_skip_white (idx, in);
3186+
3187+ while (idx < in->len)
3188+ {
3189+
3190+ if (strncasecmp (in->ptr + idx, "LIN=", 4) == 0)
3191+ {
3192+ idx += 4;
3193+ idx = exp_get_abs (_("form LIN= needs absolute expresssion.\n"), idx, in, &lines);
3194+ }
3195+
3196+ if (strncasecmp (in->ptr + idx, _("COL="), 4) == 0)
3197+ {
3198+ idx += 4;
3199+ idx = exp_get_abs (_("form COL= needs absolute expresssion.\n"), idx, in, &columns);
3200+ }
3201+
3202+ idx++;
3203+ }
3204+ fprintf (outfile, ".psize %d,%d\n", lines, columns);
3205+
3206+}
3207+
3208+/* Fetch string from the input stream,
3209+ rules:
3210+ 'Bxyx<whitespace> -> return 'Bxyza
3211+ %<char> -> return string of decimal value of x
3212+ "<string>" -> return string
3213+ xyx<whitespace> -> return xyz
3214+*/
3215+
3216+static int
3217+get_any_string (idx, in, out, expand, pretend_quoted)
3218+ int idx;
3219+ sb *in;
3220+ sb *out;
3221+ int expand;
3222+ int pretend_quoted;
3223+{
3224+ sb_reset (out);
3225+ idx = sb_skip_white (idx, in);
3226+
3227+ if (idx < in->len)
3228+ {
3229+ if (in->len > 2 && in->ptr[idx + 1] == '\'' && ISBASE (in->ptr[idx]))
3230+ {
3231+ while (!ISSEP (in->ptr[idx]))
3232+ sb_add_char (out, in->ptr[idx++]);
3233+ }
3234+ else if (in->ptr[idx] == '%'
3235+ && alternate
3236+ && expand)
3237+ {
3238+ int val;
3239+ char buf[20];
3240+ /* Turns the next expression into a string. */
3241+ /* xgettext: no-c-format */
3242+ idx = exp_get_abs (_("% operator needs absolute expression"),
3243+ idx + 1,
3244+ in,
3245+ &val);
3246+ sprintf (buf, "%d", val);
3247+ sb_add_string (out, buf);
3248+ }
3249+ else if (in->ptr[idx] == '"'
3250+ || in->ptr[idx] == '<'
3251+ || (alternate && in->ptr[idx] == '\''))
3252+ {
3253+ if (alternate && expand)
3254+ {
3255+ /* Keep the quotes. */
3256+ sb_add_char (out, '\"');
3257+
3258+ idx = getstring (idx, in, out);
3259+ sb_add_char (out, '\"');
3260+
3261+ }
3262+ else
3263+ {
3264+ idx = getstring (idx, in, out);
3265+ }
3266+ }
3267+ else
3268+ {
3269+ while (idx < in->len
3270+ && (in->ptr[idx] == '"'
3271+ || in->ptr[idx] == '\''
3272+ || pretend_quoted
3273+ || !ISSEP (in->ptr[idx])))
3274+ {
3275+ if (in->ptr[idx] == '"'
3276+ || in->ptr[idx] == '\'')
3277+ {
3278+ char tchar = in->ptr[idx];
3279+ sb_add_char (out, in->ptr[idx++]);
3280+ while (idx < in->len
3281+ && in->ptr[idx] != tchar)
3282+ sb_add_char (out, in->ptr[idx++]);
3283+ if (idx == in->len)
3284+ return idx;
3285+ }
3286+ sb_add_char (out, in->ptr[idx++]);
3287+ }
3288+ }
3289+ }
3290+
3291+ return idx;
3292+}
3293+
3294+/* Skip along sb in starting at idx, suck off whitespace a ( and more
3295+ whitespace. Return the idx of the next char. */
3296+
3297+static int
3298+skip_openp (idx, in)
3299+ int idx;
3300+ sb *in;
3301+{
3302+ idx = sb_skip_white (idx, in);
3303+ if (in->ptr[idx] != '(')
3304+ ERROR ((stderr, _("misplaced ( .\n")));
3305+ idx = sb_skip_white (idx + 1, in);
3306+ return idx;
3307+}
3308+
3309+/* Skip along sb in starting at idx, suck off whitespace a ) and more
3310+ whitespace. Return the idx of the next char. */
3311+
3312+static int
3313+skip_closep (idx, in)
3314+ int idx;
3315+ sb *in;
3316+{
3317+ idx = sb_skip_white (idx, in);
3318+ if (in->ptr[idx] != ')')
3319+ ERROR ((stderr, _("misplaced ).\n")));
3320+ idx = sb_skip_white (idx + 1, in);
3321+ return idx;
3322+}
3323+
3324+/* .len */
3325+
3326+static int
3327+dolen (idx, in, out)
3328+ int idx;
3329+ sb *in;
3330+ sb *out;
3331+{
3332+
3333+ sb stringout;
3334+ char buffer[10];
3335+
3336+ sb_new (&stringout);
3337+ idx = skip_openp (idx, in);
3338+ idx = get_and_process (idx, in, &stringout);
3339+ idx = skip_closep (idx, in);
3340+ sprintf (buffer, "%d", stringout.len);
3341+ sb_add_string (out, buffer);
3342+
3343+ sb_kill (&stringout);
3344+ return idx;
3345+}
3346+
3347+/* .instr */
3348+
3349+static int
3350+doinstr (idx, in, out)
3351+ int idx;
3352+ sb *in;
3353+ sb *out;
3354+{
3355+ sb string;
3356+ sb search;
3357+ int i;
3358+ int start;
3359+ int res;
3360+ char buffer[10];
3361+
3362+ sb_new (&string);
3363+ sb_new (&search);
3364+ idx = skip_openp (idx, in);
3365+ idx = get_and_process (idx, in, &string);
3366+ idx = sb_skip_comma (idx, in);
3367+ idx = get_and_process (idx, in, &search);
3368+ idx = sb_skip_comma (idx, in);
3369+ if (ISDIGIT (in->ptr[idx]))
3370+ {
3371+ idx = exp_get_abs (_(".instr needs absolute expresson.\n"), idx, in, &start);
3372+ }
3373+ else
3374+ {
3375+ start = 0;
3376+ }
3377+ idx = skip_closep (idx, in);
3378+ res = -1;
3379+ for (i = start; i < string.len; i++)
3380+ {
3381+ if (strncmp (string.ptr + i, search.ptr, search.len) == 0)
3382+ {
3383+ res = i;
3384+ break;
3385+ }
3386+ }
3387+ sprintf (buffer, "%d", res);
3388+ sb_add_string (out, buffer);
3389+ sb_kill (&string);
3390+ sb_kill (&search);
3391+ return idx;
3392+}
3393+
3394+static int
3395+dosubstr (idx, in, out)
3396+ int idx;
3397+ sb *in;
3398+ sb *out;
3399+{
3400+ sb string;
3401+ int pos;
3402+ int len;
3403+ sb_new (&string);
3404+
3405+ idx = skip_openp (idx, in);
3406+ idx = get_and_process (idx, in, &string);
3407+ idx = sb_skip_comma (idx, in);
3408+ idx = exp_get_abs (_("need absolute position.\n"), idx, in, &pos);
3409+ idx = sb_skip_comma (idx, in);
3410+ idx = exp_get_abs (_("need absolute length.\n"), idx, in, &len);
3411+ idx = skip_closep (idx, in);
3412+
3413+ if (len < 0 || pos < 0 ||
3414+ pos > string.len
3415+ || pos + len > string.len)
3416+ {
3417+ sb_add_string (out, " ");
3418+ }
3419+ else
3420+ {
3421+ sb_add_char (out, '"');
3422+ while (len > 0)
3423+ {
3424+ sb_add_char (out, string.ptr[pos++]);
3425+ len--;
3426+ }
3427+ sb_add_char (out, '"');
3428+ }
3429+ sb_kill (&string);
3430+ return idx;
3431+}
3432+
3433+/* Scan line, change tokens in the hash table to their replacements. */
3434+
3435+static void
3436+process_assigns (idx, in, buf)
3437+ int idx;
3438+ sb *in;
3439+ sb *buf;
3440+{
3441+ while (idx < in->len)
3442+ {
3443+ hash_entry *ptr;
3444+ if (in->ptr[idx] == '\\'
3445+ && idx + 1 < in->len
3446+ && in->ptr[idx + 1] == '(')
3447+ {
3448+ do
3449+ {
3450+ sb_add_char (buf, in->ptr[idx]);
3451+ idx++;
3452+ }
3453+ while (idx < in->len && in->ptr[idx - 1] != ')');
3454+ }
3455+ else if (in->ptr[idx] == '\\'
3456+ && idx + 1 < in->len
3457+ && in->ptr[idx + 1] == '&')
3458+ {
3459+ idx = condass_lookup_name (in, idx + 2, buf, 1);
3460+ }
3461+ else if (in->ptr[idx] == '\\'
3462+ && idx + 1 < in->len
3463+ && in->ptr[idx + 1] == '$')
3464+ {
3465+ idx = condass_lookup_name (in, idx + 2, buf, 0);
3466+ }
3467+ else if (idx + 3 < in->len
3468+ && in->ptr[idx] == '.'
3469+ && TOUPPER (in->ptr[idx + 1]) == 'L'
3470+ && TOUPPER (in->ptr[idx + 2]) == 'E'
3471+ && TOUPPER (in->ptr[idx + 3]) == 'N')
3472+ idx = dolen (idx + 4, in, buf);
3473+ else if (idx + 6 < in->len
3474+ && in->ptr[idx] == '.'
3475+ && TOUPPER (in->ptr[idx + 1]) == 'I'
3476+ && TOUPPER (in->ptr[idx + 2]) == 'N'
3477+ && TOUPPER (in->ptr[idx + 3]) == 'S'
3478+ && TOUPPER (in->ptr[idx + 4]) == 'T'
3479+ && TOUPPER (in->ptr[idx + 5]) == 'R')
3480+ idx = doinstr (idx + 6, in, buf);
3481+ else if (idx + 7 < in->len
3482+ && in->ptr[idx] == '.'
3483+ && TOUPPER (in->ptr[idx + 1]) == 'S'
3484+ && TOUPPER (in->ptr[idx + 2]) == 'U'
3485+ && TOUPPER (in->ptr[idx + 3]) == 'B'
3486+ && TOUPPER (in->ptr[idx + 4]) == 'S'
3487+ && TOUPPER (in->ptr[idx + 5]) == 'T'
3488+ && TOUPPER (in->ptr[idx + 6]) == 'R')
3489+ idx = dosubstr (idx + 7, in, buf);
3490+ else if (ISFIRSTCHAR (in->ptr[idx]))
3491+ {
3492+ /* May be a simple name subsitution, see if we have a word. */
3493+ sb acc;
3494+ int cur = idx + 1;
3495+ while (cur < in->len
3496+ && (ISNEXTCHAR (in->ptr[cur])))
3497+ cur++;
3498+
3499+ sb_new (&acc);
3500+ sb_add_buffer (&acc, in->ptr + idx, cur - idx);
3501+ ptr = hash_lookup (&assign_hash_table, &acc);
3502+ if (ptr)
3503+ {
3504+ /* Found a definition for it. */
3505+ sb_add_sb (buf, &ptr->value.s);
3506+ }
3507+ else
3508+ {
3509+ /* No definition, just copy the word. */
3510+ sb_add_sb (buf, &acc);
3511+ }
3512+ sb_kill (&acc);
3513+ idx = cur;
3514+ }
3515+ else
3516+ {
3517+ sb_add_char (buf, in->ptr[idx++]);
3518+ }
3519+ }
3520+}
3521+
3522+static int
3523+get_and_process (idx, in, out)
3524+ int idx;
3525+ sb *in;
3526+ sb *out;
3527+{
3528+ sb t;
3529+ sb_new (&t);
3530+ idx = get_any_string (idx, in, &t, 1, 0);
3531+ process_assigns (0, &t, out);
3532+ sb_kill (&t);
3533+ return idx;
3534+}
3535+
3536+static void
3537+process_file ()
3538+{
3539+ sb line;
3540+ sb t1, t2;
3541+ sb acc;
3542+ sb label_in;
3543+ int more;
3544+
3545+ sb_new (&line);
3546+ sb_new (&t1);
3547+ sb_new (&t2);
3548+ sb_new (&acc);
3549+ sb_new (&label_in);
3550+ sb_reset (&line);
3551+ more = get_line (&line);
3552+ while (more)
3553+ {
3554+ /* Find any label and pseudo op that we're intested in. */
3555+ int l;
3556+ if (line.len == 0)
3557+ {
3558+ if (condass_on ())
3559+ fprintf (outfile, "\n");
3560+ }
3561+ else if (mri
3562+ && (line.ptr[0] == '*'
3563+ || line.ptr[0] == '!'))
3564+ {
3565+ /* MRI line comment. */
3566+ fprintf (outfile, "%s", sb_name (&line));
3567+ }
3568+ else
3569+ {
3570+ l = grab_label (&line, &label_in);
3571+ sb_reset (&label);
3572+
3573+ if (line.ptr[l] == ':')
3574+ l++;
3575+ while (ISWHITE (line.ptr[l]) && l < line.len)
3576+ l++;
3577+
3578+ if (label_in.len)
3579+ {
3580+ int do_assigns;
3581+
3582+ /* Munge the label, unless this is EQU or ASSIGN. */
3583+ do_assigns = 1;
3584+ if (l < line.len
3585+ && (line.ptr[l] == '.' || alternate || mri))
3586+ {
3587+ int lx = l;
3588+
3589+ if (line.ptr[lx] == '.')
3590+ ++lx;
3591+ if (lx + 3 <= line.len
3592+ && strncasecmp ("EQU", line.ptr + lx, 3) == 0
3593+ && (lx + 3 == line.len
3594+ || ! ISFIRSTCHAR (line.ptr[lx + 3])))
3595+ do_assigns = 0;
3596+ else if (lx + 6 <= line.len
3597+ && strncasecmp ("ASSIGN", line.ptr + lx, 6) == 0
3598+ && (lx + 6 == line.len
3599+ || ! ISFIRSTCHAR (line.ptr[lx + 6])))
3600+ do_assigns = 0;
3601+ }
3602+
3603+ if (do_assigns)
3604+ process_assigns (0, &label_in, &label);
3605+ else
3606+ sb_add_sb (&label, &label_in);
3607+ }
3608+
3609+ if (l < line.len)
3610+ {
3611+ if (process_pseudo_op (l, &line, &acc))
3612+ {
3613+
3614+ }
3615+ else if (condass_on ())
3616+ {
3617+ if (macro_op (l, &line))
3618+ {
3619+
3620+ }
3621+ else
3622+ {
3623+ {
3624+ if (label.len)
3625+ {
3626+ fprintf (outfile, "%s:\t", sb_name (&label));
3627+ }
3628+ else
3629+ fprintf (outfile, "\t");
3630+ sb_reset (&t1);
3631+ process_assigns (l, &line, &t1);
3632+ sb_reset (&t2);
3633+ change_base (0, &t1, &t2);
3634+ fprintf (outfile, "%s\n", sb_name (&t2));
3635+ }
3636+ }
3637+ }
3638+ }
3639+ else
3640+ {
3641+ /* Only a label on this line. */
3642+ if (label.len && condass_on ())
3643+ {
3644+ fprintf (outfile, "%s:\n", sb_name (&label));
3645+ }
3646+ }
3647+ }
3648+
3649+ if (had_end)
3650+ break;
3651+ sb_reset (&line);
3652+ more = get_line (&line);
3653+ }
3654+
3655+ if (!had_end && !mri)
3656+ WARNING ((stderr, _("END missing from end of file.\n")));
3657+}
3658+
3659+static void
3660+free_old_entry (ptr)
3661+ hash_entry *ptr;
3662+{
3663+ if (ptr)
3664+ {
3665+ if (ptr->type == hash_string)
3666+ sb_kill (&ptr->value.s);
3667+ }
3668+}
3669+
3670+/* name: .ASSIGNA <value> */
3671+
3672+static void
3673+do_assigna (idx, in)
3674+ int idx;
3675+ sb *in;
3676+{
3677+ sb tmp;
3678+ int val;
3679+ sb_new (&tmp);
3680+
3681+ process_assigns (idx, in, &tmp);
3682+ idx = exp_get_abs (_(".ASSIGNA needs constant expression argument.\n"), 0, &tmp, &val);
3683+
3684+ if (!label.len)
3685+ {
3686+ ERROR ((stderr, _(".ASSIGNA without label.\n")));
3687+ }
3688+ else
3689+ {
3690+ hash_entry *ptr = hash_create (&vars, &label);
3691+ free_old_entry (ptr);
3692+ ptr->type = hash_integer;
3693+ ptr->value.i = val;
3694+ }
3695+ sb_kill (&tmp);
3696+}
3697+
3698+/* name: .ASSIGNC <string> */
3699+
3700+static void
3701+do_assignc (idx, in)
3702+ int idx;
3703+ sb *in;
3704+{
3705+ sb acc;
3706+ sb_new (&acc);
3707+ idx = getstring (idx, in, &acc);
3708+
3709+ if (!label.len)
3710+ {
3711+ ERROR ((stderr, _(".ASSIGNS without label.\n")));
3712+ }
3713+ else
3714+ {
3715+ hash_entry *ptr = hash_create (&vars, &label);
3716+ free_old_entry (ptr);
3717+ ptr->type = hash_string;
3718+ sb_new (&ptr->value.s);
3719+ sb_add_sb (&ptr->value.s, &acc);
3720+ }
3721+ sb_kill (&acc);
3722+}
3723+
3724+/* name: .REG (reg) */
3725+
3726+static void
3727+do_reg (idx, in)
3728+ int idx;
3729+ sb *in;
3730+{
3731+ /* Remove reg stuff from inside parens. */
3732+ sb what;
3733+ if (!mri)
3734+ idx = skip_openp (idx, in);
3735+ else
3736+ idx = sb_skip_white (idx, in);
3737+ sb_new (&what);
3738+ while (idx < in->len
3739+ && (mri
3740+ ? ! eol (idx, in)
3741+ : in->ptr[idx] != ')'))
3742+ {
3743+ sb_add_char (&what, in->ptr[idx]);
3744+ idx++;
3745+ }
3746+ hash_add_to_string_table (&assign_hash_table, &label, &what, 1);
3747+ sb_kill (&what);
3748+}
3749+
3750+static int
3751+condass_lookup_name (inbuf, idx, out, warn)
3752+ sb *inbuf;
3753+ int idx;
3754+ sb *out;
3755+ int warn;
3756+{
3757+ hash_entry *ptr;
3758+ sb condass_acc;
3759+ sb_new (&condass_acc);
3760+
3761+ while (idx < inbuf->len
3762+ && ISNEXTCHAR (inbuf->ptr[idx]))
3763+ {
3764+ sb_add_char (&condass_acc, inbuf->ptr[idx++]);
3765+ }
3766+
3767+ if (inbuf->ptr[idx] == '\'')
3768+ idx++;
3769+ ptr = hash_lookup (&vars, &condass_acc);
3770+
3771+ if (!ptr)
3772+ {
3773+ if (warn)
3774+ {
3775+ WARNING ((stderr, _("Can't find preprocessor variable %s.\n"), sb_name (&condass_acc)));
3776+ }
3777+ else
3778+ {
3779+ sb_add_string (out, "0");
3780+ }
3781+ }
3782+ else
3783+ {
3784+ if (ptr->type == hash_integer)
3785+ {
3786+ char buffer[30];
3787+ sprintf (buffer, "%d", ptr->value.i);
3788+ sb_add_string (out, buffer);
3789+ }
3790+ else
3791+ {
3792+ sb_add_sb (out, &ptr->value.s);
3793+ }
3794+ }
3795+ sb_kill (&condass_acc);
3796+ return idx;
3797+}
3798+
3799+#define EQ 1
3800+#define NE 2
3801+#define GE 3
3802+#define LT 4
3803+#define LE 5
3804+#define GT 6
3805+#define NEVER 7
3806+
3807+static int
3808+whatcond (idx, in, val)
3809+ int idx;
3810+ sb *in;
3811+ int *val;
3812+{
3813+ int cond;
3814+
3815+ idx = sb_skip_white (idx, in);
3816+ cond = NEVER;
3817+ if (idx + 1 < in->len)
3818+ {
3819+ char *p;
3820+ char a, b;
3821+
3822+ p = in->ptr + idx;
3823+ a = TOUPPER (p[0]);
3824+ b = TOUPPER (p[1]);
3825+ if (a == 'E' && b == 'Q')
3826+ cond = EQ;
3827+ else if (a == 'N' && b == 'E')
3828+ cond = NE;
3829+ else if (a == 'L' && b == 'T')
3830+ cond = LT;
3831+ else if (a == 'L' && b == 'E')
3832+ cond = LE;
3833+ else if (a == 'G' && b == 'T')
3834+ cond = GT;
3835+ else if (a == 'G' && b == 'E')
3836+ cond = GE;
3837+ }
3838+ if (cond == NEVER)
3839+ {
3840+ ERROR ((stderr, _("Comparison operator must be one of EQ, NE, LT, LE, GT or GE.\n")));
3841+ cond = NEVER;
3842+ }
3843+ idx = sb_skip_white (idx + 2, in);
3844+ *val = cond;
3845+ return idx;
3846+}
3847+
3848+static int
3849+istrue (idx, in)
3850+ int idx;
3851+ sb *in;
3852+{
3853+ int res;
3854+ sb acc_a;
3855+ sb cond;
3856+ sb acc_b;
3857+ sb_new (&acc_a);
3858+ sb_new (&cond);
3859+ sb_new (&acc_b);
3860+ idx = sb_skip_white (idx, in);
3861+
3862+ if (in->ptr[idx] == '"')
3863+ {
3864+ int cond;
3865+ int same;
3866+ /* This is a string comparision. */
3867+ idx = getstring (idx, in, &acc_a);
3868+ idx = whatcond (idx, in, &cond);
3869+ idx = getstring (idx, in, &acc_b);
3870+ same = acc_a.len == acc_b.len
3871+ && (strncmp (acc_a.ptr, acc_b.ptr, acc_a.len) == 0);
3872+
3873+ if (cond != EQ && cond != NE)
3874+ {
3875+ ERROR ((stderr, _("Comparison operator for strings must be EQ or NE\n")));
3876+ res = 0;
3877+ }
3878+ else
3879+ res = (cond != EQ) ^ same;
3880+ }
3881+ else
3882+ /* This is a numeric expression. */
3883+ {
3884+ int vala;
3885+ int valb;
3886+ int cond;
3887+ idx = exp_get_abs (_("Conditional operator must have absolute operands.\n"), idx, in, &vala);
3888+ idx = whatcond (idx, in, &cond);
3889+ idx = sb_skip_white (idx, in);
3890+ if (in->ptr[idx] == '"')
3891+ {
3892+ WARNING ((stderr, _("String compared against expression.\n")));
3893+ res = 0;
3894+ }
3895+ else
3896+ {
3897+ idx = exp_get_abs (_("Conditional operator must have absolute operands.\n"), idx, in, &valb);
3898+ switch (cond)
3899+ {
3900+ default:
3901+ res = 42;
3902+ break;
3903+ case EQ:
3904+ res = vala == valb;
3905+ break;
3906+ case NE:
3907+ res = vala != valb;
3908+ break;
3909+ case LT:
3910+ res = vala < valb;
3911+ break;
3912+ case LE:
3913+ res = vala <= valb;
3914+ break;
3915+ case GT:
3916+ res = vala > valb;
3917+ break;
3918+ case GE:
3919+ res = vala >= valb;
3920+ break;
3921+ case NEVER:
3922+ res = 0;
3923+ break;
3924+ }
3925+ }
3926+ }
3927+
3928+ sb_kill (&acc_a);
3929+ sb_kill (&cond);
3930+ sb_kill (&acc_b);
3931+ return res;
3932+}
3933+
3934+/* .AIF */
3935+
3936+static void
3937+do_aif (idx, in)
3938+ int idx;
3939+ sb *in;
3940+{
3941+ if (ifi >= IFNESTING)
3942+ {
3943+ FATAL ((stderr, _("AIF nesting unreasonable.\n")));
3944+ }
3945+ ifi++;
3946+ ifstack[ifi].on = ifstack[ifi - 1].on ? istrue (idx, in) : 0;
3947+ ifstack[ifi].hadelse = 0;
3948+}
3949+
3950+/* .AELSE */
3951+
3952+static void
3953+do_aelse ()
3954+{
3955+ ifstack[ifi].on = ifstack[ifi - 1].on ? !ifstack[ifi].on : 0;
3956+ if (ifstack[ifi].hadelse)
3957+ {
3958+ ERROR ((stderr, _("Multiple AELSEs in AIF.\n")));
3959+ }
3960+ ifstack[ifi].hadelse = 1;
3961+}
3962+
3963+/* .AENDI */
3964+
3965+static void
3966+do_aendi ()
3967+{
3968+ if (ifi != 0)
3969+ {
3970+ ifi--;
3971+ }
3972+ else
3973+ {
3974+ ERROR ((stderr, _("AENDI without AIF.\n")));
3975+ }
3976+}
3977+
3978+static int
3979+condass_on ()
3980+{
3981+ return ifstack[ifi].on;
3982+}
3983+
3984+/* MRI IFEQ, IFNE, IFLT, IFLE, IFGE, IFGT. */
3985+
3986+static void
3987+do_if (idx, in, cond)
3988+ int idx;
3989+ sb *in;
3990+ int cond;
3991+{
3992+ int val;
3993+ int res;
3994+
3995+ if (ifi >= IFNESTING)
3996+ {
3997+ FATAL ((stderr, _("IF nesting unreasonable.\n")));
3998+ }
3999+
4000+ idx = exp_get_abs (_("Conditional operator must have absolute operands.\n"),
4001+ idx, in, &val);
4002+ switch (cond)
4003+ {
4004+ default:
4005+ case EQ: res = val == 0; break;
4006+ case NE: res = val != 0; break;
4007+ case LT: res = val < 0; break;
4008+ case LE: res = val <= 0; break;
4009+ case GE: res = val >= 0; break;
4010+ case GT: res = val > 0; break;
4011+ }
4012+
4013+ ifi++;
4014+ ifstack[ifi].on = ifstack[ifi - 1].on ? res : 0;
4015+ ifstack[ifi].hadelse = 0;
4016+}
4017+
4018+/* Get a string for the MRI IFC or IFNC pseudo-ops. */
4019+
4020+static int
4021+get_mri_string (idx, in, val, terminator)
4022+ int idx;
4023+ sb *in;
4024+ sb *val;
4025+ int terminator;
4026+{
4027+ idx = sb_skip_white (idx, in);
4028+
4029+ if (idx < in->len
4030+ && in->ptr[idx] == '\'')
4031+ {
4032+ sb_add_char (val, '\'');
4033+ for (++idx; idx < in->len; ++idx)
4034+ {
4035+ sb_add_char (val, in->ptr[idx]);
4036+ if (in->ptr[idx] == '\'')
4037+ {
4038+ ++idx;
4039+ if (idx >= in->len
4040+ || in->ptr[idx] != '\'')
4041+ break;
4042+ }
4043+ }
4044+ idx = sb_skip_white (idx, in);
4045+ }
4046+ else
4047+ {
4048+ int i;
4049+
4050+ while (idx < in->len
4051+ && in->ptr[idx] != terminator)
4052+ {
4053+ sb_add_char (val, in->ptr[idx]);
4054+ ++idx;
4055+ }
4056+ i = val->len - 1;
4057+ while (i >= 0 && ISWHITE (val->ptr[i]))
4058+ --i;
4059+ val->len = i + 1;
4060+ }
4061+
4062+ return idx;
4063+}
4064+
4065+/* MRI IFC, IFNC */
4066+
4067+static void
4068+do_ifc (idx, in, ifnc)
4069+ int idx;
4070+ sb *in;
4071+ int ifnc;
4072+{
4073+ sb first;
4074+ sb second;
4075+ int res;
4076+
4077+ if (ifi >= IFNESTING)
4078+ {
4079+ FATAL ((stderr, _("IF nesting unreasonable.\n")));
4080+ }
4081+
4082+ sb_new (&first);
4083+ sb_new (&second);
4084+
4085+ idx = get_mri_string (idx, in, &first, ',');
4086+
4087+ if (idx >= in->len || in->ptr[idx] != ',')
4088+ {
4089+ ERROR ((stderr, _("Bad format for IF or IFNC.\n")));
4090+ return;
4091+ }
4092+
4093+ idx = get_mri_string (idx + 1, in, &second, ';');
4094+
4095+ res = (first.len == second.len
4096+ && strncmp (first.ptr, second.ptr, first.len) == 0);
4097+ res ^= ifnc;
4098+
4099+ ifi++;
4100+ ifstack[ifi].on = ifstack[ifi - 1].on ? res : 0;
4101+ ifstack[ifi].hadelse = 0;
4102+}
4103+
4104+/* .ENDR */
4105+
4106+static void
4107+do_aendr ()
4108+{
4109+ if (!mri)
4110+ ERROR ((stderr, _("AENDR without a AREPEAT.\n")));
4111+ else
4112+ ERROR ((stderr, _("ENDR without a REPT.\n")));
4113+}
4114+
4115+/* .AWHILE */
4116+
4117+static void
4118+do_awhile (idx, in)
4119+ int idx;
4120+ sb *in;
4121+{
4122+ int line = linecount ();
4123+ sb exp;
4124+ sb sub;
4125+ int doit;
4126+
4127+ sb_new (&sub);
4128+ sb_new (&exp);
4129+
4130+ process_assigns (idx, in, &exp);
4131+ doit = istrue (0, &exp);
4132+
4133+ if (! buffer_and_nest ("AWHILE", "AENDW", &sub, get_line))
4134+ FATAL ((stderr, _("AWHILE without a AENDW at %d.\n"), line - 1));
4135+
4136+ /* Turn
4137+ .AWHILE exp
4138+ foo
4139+ .AENDW
4140+ into
4141+ foo
4142+ .AWHILE exp
4143+ foo
4144+ .ENDW
4145+ */
4146+
4147+ if (doit)
4148+ {
4149+ int index = include_next_index ();
4150+
4151+ sb copy;
4152+ sb_new (&copy);
4153+ sb_add_sb (&copy, &sub);
4154+ sb_add_sb (&copy, in);
4155+ sb_add_string (&copy, "\n");
4156+ sb_add_sb (&copy, &sub);
4157+ sb_add_string (&copy, "\t.AENDW\n");
4158+ /* Push another WHILE. */
4159+ include_buf (&exp, &copy, include_while, index);
4160+ sb_kill (&copy);
4161+ }
4162+ sb_kill (&exp);
4163+ sb_kill (&sub);
4164+}
4165+
4166+/* .AENDW */
4167+
4168+static void
4169+do_aendw ()
4170+{
4171+ ERROR ((stderr, _("AENDW without a AENDW.\n")));
4172+}
4173+
4174+/* .EXITM
4175+
4176+ Pop things off the include stack until the type and index changes. */
4177+
4178+static void
4179+do_exitm ()
4180+{
4181+ include_type type = sp->type;
4182+ if (type == include_repeat
4183+ || type == include_while
4184+ || type == include_macro)
4185+ {
4186+ int index = sp->index;
4187+ include_pop ();
4188+ while (sp->index == index
4189+ && sp->type == type)
4190+ {
4191+ include_pop ();
4192+ }
4193+ }
4194+}
4195+
4196+/* .AREPEAT */
4197+
4198+static void
4199+do_arepeat (idx, in)
4200+ int idx;
4201+ sb *in;
4202+{
4203+ int line = linecount ();
4204+ sb exp; /* Buffer with expression in it. */
4205+ sb copy; /* Expanded repeat block. */
4206+ sb sub; /* Contents of AREPEAT. */
4207+ int rc;
4208+ int ret;
4209+ char buffer[30];
4210+
4211+ sb_new (&exp);
4212+ sb_new (&copy);
4213+ sb_new (&sub);
4214+ process_assigns (idx, in, &exp);
4215+ idx = exp_get_abs (_("AREPEAT must have absolute operand.\n"), 0, &exp, &rc);
4216+ if (!mri)
4217+ ret = buffer_and_nest ("AREPEAT", "AENDR", &sub, get_line);
4218+ else
4219+ ret = buffer_and_nest ("REPT", "ENDR", &sub, get_line);
4220+ if (! ret)
4221+ FATAL ((stderr, _("AREPEAT without a AENDR at %d.\n"), line - 1));
4222+ if (rc > 0)
4223+ {
4224+ /* Push back the text following the repeat, and another repeat block
4225+ so
4226+ .AREPEAT 20
4227+ foo
4228+ .AENDR
4229+ gets turned into
4230+ foo
4231+ .AREPEAT 19
4232+ foo
4233+ .AENDR
4234+ */
4235+ int index = include_next_index ();
4236+ sb_add_sb (&copy, &sub);
4237+ if (rc > 1)
4238+ {
4239+ if (!mri)
4240+ sprintf (buffer, "\t.AREPEAT %d\n", rc - 1);
4241+ else
4242+ sprintf (buffer, "\tREPT %d\n", rc - 1);
4243+ sb_add_string (&copy, buffer);
4244+ sb_add_sb (&copy, &sub);
4245+ if (!mri)
4246+ sb_add_string (&copy, " .AENDR\n");
4247+ else
4248+ sb_add_string (&copy, " ENDR\n");
4249+ }
4250+
4251+ include_buf (&exp, &copy, include_repeat, index);
4252+ }
4253+ sb_kill (&exp);
4254+ sb_kill (&sub);
4255+ sb_kill (&copy);
4256+}
4257+
4258+/* .ENDM */
4259+
4260+static void
4261+do_endm ()
4262+{
4263+ ERROR ((stderr, _(".ENDM without a matching .MACRO.\n")));
4264+}
4265+
4266+/* MRI IRP pseudo-op. */
4267+
4268+static void
4269+do_irp (idx, in, irpc)
4270+ int idx;
4271+ sb *in;
4272+ int irpc;
4273+{
4274+ const char *err;
4275+ sb out;
4276+
4277+ sb_new (&out);
4278+
4279+ err = expand_irp (irpc, idx, in, &out, get_line, comment_char);
4280+ if (err != NULL)
4281+ ERROR ((stderr, "%s\n", err));
4282+
4283+ fprintf (outfile, "%s", sb_terminate (&out));
4284+
4285+ sb_kill (&out);
4286+}
4287+
4288+/* Macro processing. */
4289+
4290+/* Parse off LOCAL n1, n2,... Invent a label name for it. */
4291+
4292+static void
4293+do_local (idx, line)
4294+ int idx ATTRIBUTE_UNUSED;
4295+ sb *line ATTRIBUTE_UNUSED;
4296+{
4297+ ERROR ((stderr, _("LOCAL outside of MACRO")));
4298+}
4299+
4300+static void
4301+do_macro (idx, in)
4302+ int idx;
4303+ sb *in;
4304+{
4305+ const char *err;
4306+ int line = linecount ();
4307+
4308+ err = define_macro (idx, in, &label, get_line, (const char **) NULL);
4309+ if (err != NULL)
4310+ ERROR ((stderr, _("macro at line %d: %s\n"), line - 1, err));
4311+}
4312+
4313+static int
4314+macro_op (idx, in)
4315+ int idx;
4316+ sb *in;
4317+{
4318+ const char *err;
4319+ sb out;
4320+ sb name;
4321+
4322+ if (! macro_defined)
4323+ return 0;
4324+
4325+ sb_terminate (in);
4326+ if (! check_macro (in->ptr + idx, &out, comment_char, &err, NULL))
4327+ return 0;
4328+
4329+ if (err != NULL)
4330+ ERROR ((stderr, "%s\n", err));
4331+
4332+ sb_new (&name);
4333+ sb_add_string (&name, _("macro expansion"));
4334+
4335+ include_buf (&name, &out, include_macro, include_next_index ());
4336+
4337+ sb_kill (&name);
4338+ sb_kill (&out);
4339+
4340+ return 1;
4341+}
4342+
4343+/* String handling. */
4344+
4345+static int
4346+getstring (idx, in, acc)
4347+ int idx;
4348+ sb *in;
4349+ sb *acc;
4350+{
4351+ idx = sb_skip_white (idx, in);
4352+
4353+ while (idx < in->len
4354+ && (in->ptr[idx] == '"'
4355+ || in->ptr[idx] == '<'
4356+ || (in->ptr[idx] == '\'' && alternate)))
4357+ {
4358+ if (in->ptr[idx] == '<')
4359+ {
4360+ if (alternate || mri)
4361+ {
4362+ int nest = 0;
4363+ idx++;
4364+ while ((in->ptr[idx] != '>' || nest)
4365+ && idx < in->len)
4366+ {
4367+ if (in->ptr[idx] == '!')
4368+ {
4369+ idx++;
4370+ sb_add_char (acc, in->ptr[idx++]);
4371+ }
4372+ else
4373+ {
4374+ if (in->ptr[idx] == '>')
4375+ nest--;
4376+ if (in->ptr[idx] == '<')
4377+ nest++;
4378+ sb_add_char (acc, in->ptr[idx++]);
4379+ }
4380+ }
4381+ idx++;
4382+ }
4383+ else
4384+ {
4385+ int code;
4386+ idx++;
4387+ idx = exp_get_abs (_("Character code in string must be absolute expression.\n"),
4388+ idx, in, &code);
4389+ sb_add_char (acc, code);
4390+
4391+ if (in->ptr[idx] != '>')
4392+ ERROR ((stderr, _("Missing > for character code.\n")));
4393+ idx++;
4394+ }
4395+ }
4396+ else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'')
4397+ {
4398+ char tchar = in->ptr[idx];
4399+ idx++;
4400+ while (idx < in->len)
4401+ {
4402+ if (alternate && in->ptr[idx] == '!')
4403+ {
4404+ idx++;
4405+ sb_add_char (acc, in->ptr[idx++]);
4406+ }
4407+ else
4408+ {
4409+ if (in->ptr[idx] == tchar)
4410+ {
4411+ idx++;
4412+ if (idx >= in->len || in->ptr[idx] != tchar)
4413+ break;
4414+ }
4415+ sb_add_char (acc, in->ptr[idx]);
4416+ idx++;
4417+ }
4418+ }
4419+ }
4420+ }
4421+
4422+ return idx;
4423+}
4424+
4425+/* .SDATA[C|Z] <string> */
4426+
4427+static void
4428+do_sdata (idx, in, type)
4429+ int idx;
4430+ sb *in;
4431+ int type;
4432+{
4433+ int nc = 0;
4434+ int pidx = -1;
4435+ sb acc;
4436+ sb_new (&acc);
4437+ fprintf (outfile, ".byte\t");
4438+
4439+ while (!eol (idx, in))
4440+ {
4441+ int i;
4442+ sb_reset (&acc);
4443+ idx = sb_skip_white (idx, in);
4444+ while (!eol (idx, in))
4445+ {
4446+ pidx = idx = get_any_string (idx, in, &acc, 0, 1);
4447+ if (type == 'c')
4448+ {
4449+ if (acc.len > 255)
4450+ {
4451+ ERROR ((stderr, _("string for SDATAC longer than 255 characters (%d).\n"), acc.len));
4452+ }
4453+ fprintf (outfile, "%d", acc.len);
4454+ nc = 1;
4455+ }
4456+
4457+ for (i = 0; i < acc.len; i++)
4458+ {
4459+ if (nc)
4460+ {
4461+ fprintf (outfile, ",");
4462+ }
4463+ fprintf (outfile, "%d", acc.ptr[i]);
4464+ nc = 1;
4465+ }
4466+
4467+ if (type == 'z')
4468+ {
4469+ if (nc)
4470+ fprintf (outfile, ",");
4471+ fprintf (outfile, "0");
4472+ }
4473+ idx = sb_skip_comma (idx, in);
4474+ if (idx == pidx)
4475+ break;
4476+ }
4477+ if (!alternate && in->ptr[idx] != ',' && idx != in->len)
4478+ {
4479+ fprintf (outfile, "\n");
4480+ ERROR ((stderr, _("illegal character in SDATA line (0x%x).\n"),
4481+ in->ptr[idx]));
4482+ break;
4483+ }
4484+ idx++;
4485+ }
4486+ sb_kill (&acc);
4487+ fprintf (outfile, "\n");
4488+}
4489+
4490+/* .SDATAB <count> <string> */
4491+
4492+static void
4493+do_sdatab (idx, in)
4494+ int idx;
4495+ sb *in;
4496+{
4497+ int repeat;
4498+ int i;
4499+ sb acc;
4500+ sb_new (&acc);
4501+
4502+ idx = exp_get_abs (_("Must have absolute SDATAB repeat count.\n"), idx, in, &repeat);
4503+ if (repeat <= 0)
4504+ {
4505+ ERROR ((stderr, _("Must have positive SDATAB repeat count (%d).\n"), repeat));
4506+ repeat = 1;
4507+ }
4508+
4509+ idx = sb_skip_comma (idx, in);
4510+ idx = getstring (idx, in, &acc);
4511+
4512+ for (i = 0; i < repeat; i++)
4513+ {
4514+ if (i)
4515+ fprintf (outfile, "\t");
4516+ fprintf (outfile, ".byte\t");
4517+ sb_print (outfile, &acc);
4518+ fprintf (outfile, "\n");
4519+ }
4520+ sb_kill (&acc);
4521+
4522+}
4523+
4524+static int
4525+new_file (name)
4526+ const char *name;
4527+{
4528+ FILE *newone = fopen (name, "r");
4529+ if (!newone)
4530+ return 0;
4531+
4532+ if (isp == MAX_INCLUDES)
4533+ FATAL ((stderr, _("Unreasonable include depth (%ld).\n"), (long) isp));
4534+
4535+ sp++;
4536+ sp->handle = newone;
4537+
4538+ sb_new (&sp->name);
4539+ sb_add_string (&sp->name, name);
4540+
4541+ sp->linecount = 1;
4542+ sp->pushback_index = 0;
4543+ sp->type = include_file;
4544+ sp->index = 0;
4545+ sb_new (&sp->pushback);
4546+ return 1;
4547+}
4548+
4549+static void
4550+do_include (idx, in)
4551+ int idx;
4552+ sb *in;
4553+{
4554+ sb t;
4555+ sb cat;
4556+ include_path *includes;
4557+
4558+ sb_new (&t);
4559+ sb_new (&cat);
4560+
4561+ if (! mri)
4562+ idx = getstring (idx, in, &t);
4563+ else
4564+ {
4565+ idx = sb_skip_white (idx, in);
4566+ while (idx < in->len && ! ISWHITE (in->ptr[idx]))
4567+ {
4568+ sb_add_char (&t, in->ptr[idx]);
4569+ ++idx;
4570+ }
4571+ }
4572+
4573+ for (includes = paths_head; includes; includes = includes->next)
4574+ {
4575+ sb_reset (&cat);
4576+ sb_add_sb (&cat, &includes->path);
4577+ sb_add_char (&cat, '/');
4578+ sb_add_sb (&cat, &t);
4579+ if (new_file (sb_name (&cat)))
4580+ {
4581+ break;
4582+ }
4583+ }
4584+ if (!includes)
4585+ {
4586+ if (! new_file (sb_name (&t)))
4587+ FATAL ((stderr, _("Can't open include file `%s'.\n"), sb_name (&t)));
4588+ }
4589+ sb_kill (&cat);
4590+ sb_kill (&t);
4591+}
4592+
4593+static void
4594+include_pop ()
4595+{
4596+ if (sp != include_stack)
4597+ {
4598+ if (sp->handle)
4599+ fclose (sp->handle);
4600+ sp--;
4601+ }
4602+}
4603+
4604+/* Get the next character from the include stack. If there's anything
4605+ in the pushback buffer, take that first. If we're at eof, pop from
4606+ the stack and try again. Keep the linecount up to date. */
4607+
4608+static int
4609+get ()
4610+{
4611+ int r;
4612+
4613+ if (sp->pushback.len != sp->pushback_index)
4614+ {
4615+ r = (char) (sp->pushback.ptr[sp->pushback_index++]);
4616+ /* When they've all gone, reset the pointer. */
4617+ if (sp->pushback_index == sp->pushback.len)
4618+ {
4619+ sp->pushback.len = 0;
4620+ sp->pushback_index = 0;
4621+ }
4622+ }
4623+ else if (sp->handle)
4624+ {
4625+ r = getc (sp->handle);
4626+ }
4627+ else
4628+ r = EOF;
4629+
4630+ if (r == EOF && isp)
4631+ {
4632+ include_pop ();
4633+ r = get ();
4634+ while (r == EOF && isp)
4635+ {
4636+ include_pop ();
4637+ r = get ();
4638+ }
4639+ return r;
4640+ }
4641+ if (r == '\n')
4642+ {
4643+ sp->linecount++;
4644+ }
4645+
4646+ return r;
4647+}
4648+
4649+static int
4650+linecount ()
4651+{
4652+ return sp->linecount;
4653+}
4654+
4655+static int
4656+include_next_index ()
4657+{
4658+ static int index;
4659+ if (!unreasonable
4660+ && index > MAX_REASONABLE)
4661+ FATAL ((stderr, _("Unreasonable expansion (-u turns off check).\n")));
4662+ return ++index;
4663+}
4664+
4665+/* Initialize the chartype vector. */
4666+
4667+static void
4668+chartype_init ()
4669+{
4670+ int x;
4671+ for (x = 0; x < 256; x++)
4672+ {
4673+ if (ISALPHA (x) || x == '_' || x == '$')
4674+ chartype[x] |= FIRSTBIT;
4675+
4676+ if (mri && x == '.')
4677+ chartype[x] |= FIRSTBIT;
4678+
4679+ if (ISDIGIT (x) || ISALPHA (x) || x == '_' || x == '$')
4680+ chartype[x] |= NEXTBIT;
4681+
4682+ if (x == ' ' || x == '\t' || x == ',' || x == '"' || x == ';'
4683+ || x == '"' || x == '<' || x == '>' || x == ')' || x == '(')
4684+ chartype[x] |= SEPBIT;
4685+
4686+ if (x == 'b' || x == 'B'
4687+ || x == 'q' || x == 'Q'
4688+ || x == 'h' || x == 'H'
4689+ || x == 'd' || x == 'D')
4690+ chartype [x] |= BASEBIT;
4691+
4692+ if (x == ' ' || x == '\t')
4693+ chartype[x] |= WHITEBIT;
4694+
4695+ if (x == comment_char)
4696+ chartype[x] |= COMMENTBIT;
4697+ }
4698+}
4699+
4700+/* What to do with all the keywords. */
4701+#define PROCESS 0x1000 /* Run substitution over the line. */
4702+#define LAB 0x2000 /* Spit out the label. */
4703+
4704+#define K_EQU (PROCESS|1)
4705+#define K_ASSIGN (PROCESS|2)
4706+#define K_REG (PROCESS|3)
4707+#define K_ORG (PROCESS|4)
4708+#define K_RADIX (PROCESS|5)
4709+#define K_DATA (LAB|PROCESS|6)
4710+#define K_DATAB (LAB|PROCESS|7)
4711+#define K_SDATA (LAB|PROCESS|8)
4712+#define K_SDATAB (LAB|PROCESS|9)
4713+#define K_SDATAC (LAB|PROCESS|10)
4714+#define K_SDATAZ (LAB|PROCESS|11)
4715+#define K_RES (LAB|PROCESS|12)
4716+#define K_SRES (LAB|PROCESS|13)
4717+#define K_SRESC (LAB|PROCESS|14)
4718+#define K_SRESZ (LAB|PROCESS|15)
4719+#define K_EXPORT (LAB|PROCESS|16)
4720+#define K_GLOBAL (LAB|PROCESS|17)
4721+#define K_PRINT (LAB|PROCESS|19)
4722+#define K_FORM (LAB|PROCESS|20)
4723+#define K_HEADING (LAB|PROCESS|21)
4724+#define K_PAGE (LAB|PROCESS|22)
4725+#define K_IMPORT (LAB|PROCESS|23)
4726+#define K_PROGRAM (LAB|PROCESS|24)
4727+#define K_END (PROCESS|25)
4728+#define K_INCLUDE (PROCESS|26)
4729+#define K_IGNORED (PROCESS|27)
4730+#define K_ASSIGNA (PROCESS|28)
4731+#define K_ASSIGNC (29)
4732+#define K_AIF (PROCESS|30)
4733+#define K_AELSE (PROCESS|31)
4734+#define K_AENDI (PROCESS|32)
4735+#define K_AREPEAT (PROCESS|33)
4736+#define K_AENDR (PROCESS|34)
4737+#define K_AWHILE (35)
4738+#define K_AENDW (PROCESS|36)
4739+#define K_EXITM (37)
4740+#define K_MACRO (PROCESS|38)
4741+#define K_ENDM (39)
4742+#define K_ALIGN (PROCESS|LAB|40)
4743+#define K_ALTERNATE (41)
4744+#define K_DB (LAB|PROCESS|42)
4745+#define K_DW (LAB|PROCESS|43)
4746+#define K_DL (LAB|PROCESS|44)
4747+#define K_LOCAL (45)
4748+#define K_IFEQ (PROCESS|46)
4749+#define K_IFNE (PROCESS|47)
4750+#define K_IFLT (PROCESS|48)
4751+#define K_IFLE (PROCESS|49)
4752+#define K_IFGE (PROCESS|50)
4753+#define K_IFGT (PROCESS|51)
4754+#define K_IFC (PROCESS|52)
4755+#define K_IFNC (PROCESS|53)
4756+#define K_IRP (PROCESS|54)
4757+#define K_IRPC (PROCESS|55)
4758+
4759+struct keyword {
4760+ char *name;
4761+ int code;
4762+ int extra;
4763+};
4764+
4765+static struct keyword kinfo[] = {
4766+ { "EQU", K_EQU, 0 },
4767+ { "ALTERNATE", K_ALTERNATE, 0 },
4768+ { "ASSIGN", K_ASSIGN, 0 },
4769+ { "REG", K_REG, 0 },
4770+ { "ORG", K_ORG, 0 },
4771+ { "RADIX", K_RADIX, 0 },
4772+ { "DATA", K_DATA, 0 },
4773+ { "DB", K_DB, 0 },
4774+ { "DW", K_DW, 0 },
4775+ { "DL", K_DL, 0 },
4776+ { "DATAB", K_DATAB, 0 },
4777+ { "SDATA", K_SDATA, 0 },
4778+ { "SDATAB", K_SDATAB, 0 },
4779+ { "SDATAZ", K_SDATAZ, 0 },
4780+ { "SDATAC", K_SDATAC, 0 },
4781+ { "RES", K_RES, 0 },
4782+ { "SRES", K_SRES, 0 },
4783+ { "SRESC", K_SRESC, 0 },
4784+ { "SRESZ", K_SRESZ, 0 },
4785+ { "EXPORT", K_EXPORT, 0 },
4786+ { "GLOBAL", K_GLOBAL, 0 },
4787+ { "PRINT", K_PRINT, 0 },
4788+ { "FORM", K_FORM, 0 },
4789+ { "HEADING", K_HEADING, 0 },
4790+ { "PAGE", K_PAGE, 0 },
4791+ { "PROGRAM", K_IGNORED, 0 },
4792+ { "END", K_END, 0 },
4793+ { "INCLUDE", K_INCLUDE, 0 },
4794+ { "ASSIGNA", K_ASSIGNA, 0 },
4795+ { "ASSIGNC", K_ASSIGNC, 0 },
4796+ { "AIF", K_AIF, 0 },
4797+ { "AELSE", K_AELSE, 0 },
4798+ { "AENDI", K_AENDI, 0 },
4799+ { "AREPEAT", K_AREPEAT, 0 },
4800+ { "AENDR", K_AENDR, 0 },
4801+ { "EXITM", K_EXITM, 0 },
4802+ { "MACRO", K_MACRO, 0 },
4803+ { "ENDM", K_ENDM, 0 },
4804+ { "AWHILE", K_AWHILE, 0 },
4805+ { "ALIGN", K_ALIGN, 0 },
4806+ { "AENDW", K_AENDW, 0 },
4807+ { "ALTERNATE", K_ALTERNATE, 0 },
4808+ { "LOCAL", K_LOCAL, 0 },
4809+ { NULL, 0, 0 }
4810+};
4811+
4812+/* Although the conditional operators are handled by gas, we need to
4813+ handle them here as well, in case they are used in a recursive
4814+ macro to end the recursion. */
4815+
4816+static struct keyword mrikinfo[] = {
4817+ { "IFEQ", K_IFEQ, 0 },
4818+ { "IFNE", K_IFNE, 0 },
4819+ { "IFLT", K_IFLT, 0 },
4820+ { "IFLE", K_IFLE, 0 },
4821+ { "IFGE", K_IFGE, 0 },
4822+ { "IFGT", K_IFGT, 0 },
4823+ { "IFC", K_IFC, 0 },
4824+ { "IFNC", K_IFNC, 0 },
4825+ { "ELSEC", K_AELSE, 0 },
4826+ { "ENDC", K_AENDI, 0 },
4827+ { "MEXIT", K_EXITM, 0 },
4828+ { "REPT", K_AREPEAT, 0 },
4829+ { "IRP", K_IRP, 0 },
4830+ { "IRPC", K_IRPC, 0 },
4831+ { "ENDR", K_AENDR, 0 },
4832+ { NULL, 0, 0 }
4833+};
4834+
4835+/* Look for a pseudo op on the line. If one's there then call
4836+ its handler. */
4837+
4838+static int
4839+process_pseudo_op (idx, line, acc)
4840+ int idx;
4841+ sb *line;
4842+ sb *acc;
4843+{
4844+ int oidx = idx;
4845+
4846+ if (line->ptr[idx] == '.' || alternate || mri)
4847+ {
4848+ /* Scan forward and find pseudo name. */
4849+ char *in;
4850+ hash_entry *ptr;
4851+
4852+ char *s;
4853+ char *e;
4854+ if (line->ptr[idx] == '.')
4855+ idx++;
4856+ in = line->ptr + idx;
4857+ s = in;
4858+ e = s;
4859+ sb_reset (acc);
4860+
4861+ while (idx < line->len && *e && ISFIRSTCHAR (*e))
4862+ {
4863+ sb_add_char (acc, *e);
4864+ e++;
4865+ idx++;
4866+ }
4867+
4868+ ptr = hash_lookup (&keyword_hash_table, acc);
4869+
4870+ if (!ptr)
4871+ {
4872+#if 0
4873+ /* This one causes lots of pain when trying to preprocess
4874+ ordinary code. */
4875+ WARNING ((stderr, _("Unrecognised pseudo op `%s'.\n"),
4876+ sb_name (acc)));
4877+#endif
4878+ return 0;
4879+ }
4880+ if (ptr->value.i & LAB)
4881+ {
4882+ /* Output the label. */
4883+ if (label.len)
4884+ {
4885+ fprintf (outfile, "%s:\t", sb_name (&label));
4886+ }
4887+ else
4888+ fprintf (outfile, "\t");
4889+ }
4890+
4891+ if (mri && ptr->value.i == K_END)
4892+ {
4893+ sb t;
4894+
4895+ sb_new (&t);
4896+ sb_add_buffer (&t, line->ptr + oidx, idx - oidx);
4897+ fprintf (outfile, "\t%s", sb_name (&t));
4898+ sb_kill (&t);
4899+ }
4900+
4901+ if (ptr->value.i & PROCESS)
4902+ {
4903+ /* Polish the rest of the line before handling the pseudo op. */
4904+#if 0
4905+ strip_comments (line);
4906+#endif
4907+ sb_reset (acc);
4908+ process_assigns (idx, line, acc);
4909+ sb_reset (line);
4910+ change_base (0, acc, line);
4911+ idx = 0;
4912+ }
4913+ if (!condass_on ())
4914+ {
4915+ switch (ptr->value.i)
4916+ {
4917+ case K_AIF:
4918+ do_aif (idx, line);
4919+ break;
4920+ case K_AELSE:
4921+ do_aelse ();
4922+ break;
4923+ case K_AENDI:
4924+ do_aendi ();
4925+ break;
4926+ }
4927+ return 1;
4928+ }
4929+ else
4930+ {
4931+ switch (ptr->value.i)
4932+ {
4933+ case K_ALTERNATE:
4934+ alternate = 1;
4935+ macro_init (1, mri, 0, exp_get_abs);
4936+ return 1;
4937+ case K_AELSE:
4938+ do_aelse ();
4939+ return 1;
4940+ case K_AENDI:
4941+ do_aendi ();
4942+ return 1;
4943+ case K_ORG:
4944+ ERROR ((stderr, _("ORG command not allowed.\n")));
4945+ break;
4946+ case K_RADIX:
4947+ do_radix (line);
4948+ return 1;
4949+ case K_DB:
4950+ do_data (idx, line, 1);
4951+ return 1;
4952+ case K_DW:
4953+ do_data (idx, line, 2);
4954+ return 1;
4955+ case K_DL:
4956+ do_data (idx, line, 4);
4957+ return 1;
4958+ case K_DATA:
4959+ do_data (idx, line, 0);
4960+ return 1;
4961+ case K_DATAB:
4962+ do_datab (idx, line);
4963+ return 1;
4964+ case K_SDATA:
4965+ do_sdata (idx, line, 0);
4966+ return 1;
4967+ case K_SDATAB:
4968+ do_sdatab (idx, line);
4969+ return 1;
4970+ case K_SDATAC:
4971+ do_sdata (idx, line, 'c');
4972+ return 1;
4973+ case K_SDATAZ:
4974+ do_sdata (idx, line, 'z');
4975+ return 1;
4976+ case K_ASSIGN:
4977+ do_assign (0, 0, line);
4978+ return 1;
4979+ case K_AIF:
4980+ do_aif (idx, line);
4981+ return 1;
4982+ case K_AREPEAT:
4983+ do_arepeat (idx, line);
4984+ return 1;
4985+ case K_AENDW:
4986+ do_aendw ();
4987+ return 1;
4988+ case K_AWHILE:
4989+ do_awhile (idx, line);
4990+ return 1;
4991+ case K_AENDR:
4992+ do_aendr ();
4993+ return 1;
4994+ case K_EQU:
4995+ do_assign (1, idx, line);
4996+ return 1;
4997+ case K_ALIGN:
4998+ do_align (idx, line);
4999+ return 1;
5000+ case K_RES:
5001+ do_res (idx, line, 0);
5002+ return 1;
5003+ case K_SRES:
5004+ do_res (idx, line, 's');
5005+ return 1;
5006+ case K_INCLUDE:
5007+ do_include (idx, line);
5008+ return 1;
5009+ case K_LOCAL:
5010+ do_local (idx, line);
5011+ return 1;
5012+ case K_MACRO:
5013+ do_macro (idx, line);
5014+ return 1;
5015+ case K_ENDM:
5016+ do_endm ();
5017+ return 1;
5018+ case K_SRESC:
5019+ do_res (idx, line, 'c');
5020+ return 1;
5021+ case K_PRINT:
5022+ do_print (idx, line);
5023+ return 1;
5024+ case K_FORM:
5025+ do_form (idx, line);
5026+ return 1;
5027+ case K_HEADING:
5028+ do_heading (idx, line);
5029+ return 1;
5030+ case K_PAGE:
5031+ do_page ();
5032+ return 1;
5033+ case K_GLOBAL:
5034+ case K_EXPORT:
5035+ do_export (line);
5036+ return 1;
5037+ case K_IMPORT:
5038+ return 1;
5039+ case K_SRESZ:
5040+ do_res (idx, line, 'z');
5041+ return 1;
5042+ case K_IGNORED:
5043+ return 1;
5044+ case K_END:
5045+ do_end (line);
5046+ return 1;
5047+ case K_ASSIGNA:
5048+ do_assigna (idx, line);
5049+ return 1;
5050+ case K_ASSIGNC:
5051+ do_assignc (idx, line);
5052+ return 1;
5053+ case K_EXITM:
5054+ do_exitm ();
5055+ return 1;
5056+ case K_REG:
5057+ do_reg (idx, line);
5058+ return 1;
5059+ case K_IFEQ:
5060+ do_if (idx, line, EQ);
5061+ return 1;
5062+ case K_IFNE:
5063+ do_if (idx, line, NE);
5064+ return 1;
5065+ case K_IFLT:
5066+ do_if (idx, line, LT);
5067+ return 1;
5068+ case K_IFLE:
5069+ do_if (idx, line, LE);
5070+ return 1;
5071+ case K_IFGE:
5072+ do_if (idx, line, GE);
5073+ return 1;
5074+ case K_IFGT:
5075+ do_if (idx, line, GT);
5076+ return 1;
5077+ case K_IFC:
5078+ do_ifc (idx, line, 0);
5079+ return 1;
5080+ case K_IFNC:
5081+ do_ifc (idx, line, 1);
5082+ return 1;
5083+ case K_IRP:
5084+ do_irp (idx, line, 0);
5085+ return 1;
5086+ case K_IRPC:
5087+ do_irp (idx, line, 1);
5088+ return 1;
5089+ }
5090+ }
5091+ }
5092+ return 0;
5093+}
5094+
5095+/* Add a keyword to the hash table. */
5096+
5097+static void
5098+add_keyword (name, code)
5099+ const char *name;
5100+ int code;
5101+{
5102+ sb label;
5103+ int j;
5104+
5105+ sb_new (&label);
5106+ sb_add_string (&label, name);
5107+
5108+ hash_add_to_int_table (&keyword_hash_table, &label, code);
5109+
5110+ sb_reset (&label);
5111+ for (j = 0; name[j]; j++)
5112+ sb_add_char (&label, name[j] - 'A' + 'a');
5113+ hash_add_to_int_table (&keyword_hash_table, &label, code);
5114+
5115+ sb_kill (&label);
5116+}
5117+
5118+/* Build the keyword hash table - put each keyword in the table twice,
5119+ once upper and once lower case. */
5120+
5121+static void
5122+process_init ()
5123+{
5124+ int i;
5125+
5126+ for (i = 0; kinfo[i].name; i++)
5127+ add_keyword (kinfo[i].name, kinfo[i].code);
5128+
5129+ if (mri)
5130+ {
5131+ for (i = 0; mrikinfo[i].name; i++)
5132+ add_keyword (mrikinfo[i].name, mrikinfo[i].code);
5133+ }
5134+}
5135+
5136+static void
5137+do_define (string)
5138+ const char *string;
5139+{
5140+ sb label;
5141+ int res = 1;
5142+ hash_entry *ptr;
5143+ sb_new (&label);
5144+
5145+ while (*string)
5146+ {
5147+ if (*string == '=')
5148+ {
5149+ sb value;
5150+ sb_new (&value);
5151+ string++;
5152+ while (*string)
5153+ {
5154+ sb_add_char (&value, *string);
5155+ string++;
5156+ }
5157+ exp_get_abs (_("Invalid expression on command line.\n"),
5158+ 0, &value, &res);
5159+ sb_kill (&value);
5160+ break;
5161+ }
5162+ sb_add_char (&label, *string);
5163+
5164+ string++;
5165+ }
5166+
5167+ ptr = hash_create (&vars, &label);
5168+ free_old_entry (ptr);
5169+ ptr->type = hash_integer;
5170+ ptr->value.i = res;
5171+ sb_kill (&label);
5172+}
5173+
5174+char *program_name;
5175+
5176+/* The list of long options. */
5177+static struct option long_options[] =
5178+{
5179+ { "alternate", no_argument, 0, 'a' },
5180+ { "include", required_argument, 0, 'I' },
5181+ { "commentchar", required_argument, 0, 'c' },
5182+ { "copysource", no_argument, 0, 's' },
5183+ { "debug", no_argument, 0, 'd' },
5184+ { "help", no_argument, 0, 'h' },
5185+ { "mri", no_argument, 0, 'M' },
5186+ { "output", required_argument, 0, 'o' },
5187+ { "print", no_argument, 0, 'p' },
5188+ { "unreasonable", no_argument, 0, 'u' },
5189+ { "version", no_argument, 0, 'v' },
5190+ { "define", required_argument, 0, 'd' },
5191+ { NULL, no_argument, 0, 0 }
5192+};
5193+
5194+/* Show a usage message and exit. */
5195+static void
5196+show_usage (file, status)
5197+ FILE *file;
5198+ int status;
5199+{
5200+ fprintf (file, _("\
5201+Usage: %s \n\
5202+ [-a] [--alternate] enter alternate macro mode\n\
5203+ [-c char] [--commentchar char] change the comment character from !\n\
5204+ [-d] [--debug] print some debugging info\n\
5205+ [-h] [--help] print this message\n\
5206+ [-M] [--mri] enter MRI compatibility mode\n\
5207+ [-o out] [--output out] set the output file\n\
5208+ [-p] [--print] print line numbers\n"), program_name);
5209+ fprintf (file, _("\
5210+ [-s] [--copysource] copy source through as comments \n\
5211+ [-u] [--unreasonable] allow unreasonable nesting\n\
5212+ [-v] [--version] print the program version\n\
5213+ [-Dname=value] create preprocessor variable called name, with value\n\
5214+ [-Ipath] add to include path list\n\
5215+ [in-file]\n"));
5216+ if (status == 0)
5217+ printf (_("Report bugs to %s\n"), REPORT_BUGS_TO);
5218+ exit (status);
5219+}
5220+
5221+/* Display a help message and exit. */
5222+
5223+static void
5224+show_help ()
5225+{
5226+ printf (_("%s: Gnu Assembler Macro Preprocessor\n"), program_name);
5227+ show_usage (stdout, 0);
5228+}
5229+
5230+int main PARAMS ((int, char **));
5231+
5232+int
5233+main (argc, argv)
5234+ int argc;
5235+ char **argv;
5236+{
5237+ int opt;
5238+ char *out_name = 0;
5239+ sp = include_stack;
5240+
5241+ ifstack[0].on = 1;
5242+ ifi = 0;
5243+
5244+#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
5245+ setlocale (LC_MESSAGES, "");
5246+#endif
5247+#if defined (HAVE_SETLOCALE)
5248+ setlocale (LC_CTYPE, "");
5249+#endif
5250+ bindtextdomain (PACKAGE, LOCALEDIR);
5251+ textdomain (PACKAGE);
5252+
5253+ program_name = argv[0];
5254+ xmalloc_set_program_name (program_name);
5255+
5256+ hash_new_table (101, &keyword_hash_table);
5257+ hash_new_table (101, &assign_hash_table);
5258+ hash_new_table (101, &vars);
5259+
5260+ sb_new (&label);
5261+
5262+ while ((opt = getopt_long (argc, argv, "I:sdhavc:upo:D:M", long_options,
5263+ (int *) NULL))
5264+ != EOF)
5265+ {
5266+ switch (opt)
5267+ {
5268+ case 'o':
5269+ out_name = optarg;
5270+ break;
5271+ case 'u':
5272+ unreasonable = 1;
5273+ break;
5274+ case 'I':
5275+ {
5276+ include_path *p = (include_path *) xmalloc (sizeof (include_path));
5277+ p->next = NULL;
5278+ sb_new (&p->path);
5279+ sb_add_string (&p->path, optarg);
5280+ if (paths_tail)
5281+ paths_tail->next = p;
5282+ else
5283+ paths_head = p;
5284+ paths_tail = p;
5285+ }
5286+ break;
5287+ case 'p':
5288+ print_line_number = 1;
5289+ break;
5290+ case 'c':
5291+ comment_char = optarg[0];
5292+ break;
5293+ case 'a':
5294+ alternate = 1;
5295+ break;
5296+ case 's':
5297+ copysource = 1;
5298+ break;
5299+ case 'd':
5300+ stats = 1;
5301+ break;
5302+ case 'D':
5303+ do_define (optarg);
5304+ break;
5305+ case 'M':
5306+ mri = 1;
5307+ comment_char = ';';
5308+ break;
5309+ case 'h':
5310+ show_help ();
5311+ /* NOTREACHED */
5312+ case 'v':
5313+ /* This output is intended to follow the GNU standards document. */
5314+ printf (_("GNU assembler pre-processor %s\n"), program_version);
5315+ printf (_("Copyright 1996 Free Software Foundation, Inc.\n"));
5316+ printf (_("\
5317+This program is free software; you may redistribute it under the terms of\n\
5318+the GNU General Public License. This program has absolutely no warranty.\n"));
5319+ exit (0);
5320+ /* NOTREACHED */
5321+ case 0:
5322+ break;
5323+ default:
5324+ show_usage (stderr, 1);
5325+ /* NOTREACHED */
5326+ }
5327+ }
5328+
5329+ process_init ();
5330+
5331+ macro_init (alternate, mri, 0, exp_get_abs);
5332+
5333+ if (out_name)
5334+ {
5335+ outfile = fopen (out_name, "w");
5336+ if (!outfile)
5337+ {
5338+ fprintf (stderr, _("%s: Can't open output file `%s'.\n"),
5339+ program_name, out_name);
5340+ exit (1);
5341+ }
5342+ }
5343+ else
5344+ {
5345+ outfile = stdout;
5346+ }
5347+
5348+ chartype_init ();
5349+ if (!outfile)
5350+ outfile = stdout;
5351+
5352+ /* Process all the input files. */
5353+
5354+ while (optind < argc)
5355+ {
5356+ if (new_file (argv[optind]))
5357+ {
5358+ process_file ();
5359+ }
5360+ else
5361+ {
5362+ fprintf (stderr, _("%s: Can't open input file `%s'.\n"),
5363+ program_name, argv[optind]);
5364+ exit (1);
5365+ }
5366+ optind++;
5367+ }
5368+
5369+ quit ();
5370+ return 0;
5371+}
5372+
5373+/* This function is used because an abort in some of the other files
5374+ may be compiled into as_abort because they include as.h. */
5375+
5376+void
5377+as_abort (file, line, fn)
5378+ const char *file, *fn;
5379+ int line;
5380+{
5381+ fprintf (stderr, _("Internal error, aborting at %s line %d"), file, line);
5382+ if (fn)
5383+ fprintf (stderr, " in %s", fn);
5384+ fprintf (stderr, _("\nPlease report this bug.\n"));
5385+ exit (1);
5386+}
5387diff -Nur binutils-2.13.90.0.18.orig/gas/macro.c binutils-2.13.90.0.18/gas/macro.c
5388--- binutils-2.13.90.0.18.orig/gas/macro.c Sun Feb 2 03:21:18 2003
5389+++ binutils-2.13.90.0.18/gas/macro.c Sun Feb 2 15:19:38 2003
5390@@ -75,8 +75,8 @@
5391 static int sub_actual
5392 PARAMS ((int, sb *, sb *, struct hash_control *, int, sb *, int));
5393 static const char *macro_expand_body
5394- PARAMS ((sb *, sb *, formal_entry *, struct hash_control *, int));
5395-static const char *macro_expand PARAMS ((int, sb *, macro_entry *, sb *));
5396+ PARAMS ((sb *, sb *, formal_entry *, struct hash_control *, int,int ));
5397+static const char *macro_expand PARAMS ((int, sb *, macro_entry *, sb *, int));
5398
5399 #define ISWHITE(x) ((x) == ' ' || (x) == '\t')
5400
5401@@ -653,11 +653,12 @@
5402 /* Expand the body of a macro. */
5403
5404 static const char *
5405-macro_expand_body (in, out, formals, formal_hash, locals)
5406+macro_expand_body (in, out, formals, formal_hash, comment_char, locals)
5407 sb *in;
5408 sb *out;
5409 formal_entry *formals;
5410 struct hash_control *formal_hash;
5411+ int comment_char;
5412 int locals;
5413 {
5414 sb t;
5415@@ -688,7 +689,14 @@
5416 else if (in->ptr[src] == '\\')
5417 {
5418 src++;
5419- if (in->ptr[src] == '(')
5420+ if (in->ptr[src] == comment_char && comment_char != '\0')
5421+ {
5422+ /* This is a comment, just drop the rest of the line. */
5423+ while (src < in->len
5424+ && in->ptr[src] != '\n')
5425+ src++;
5426+ }
5427+ else if (in->ptr[src] == '(')
5428 {
5429 /* Sub in till the next ')' literally. */
5430 src++;
5431@@ -771,7 +779,7 @@
5432 formal_entry *f;
5433
5434 src = sb_skip_white (src + 5, in);
5435- while (in->ptr[src] != '\n')
5436+ while (in->ptr[src] != '\n' && in->ptr[src] != comment_char)
5437 {
5438 static int loccnt;
5439 char buf[20];
5440@@ -798,6 +806,17 @@
5441 }
5442 }
5443 }
5444+ else if (comment_char != '\0'
5445+ && in->ptr[src] == comment_char
5446+ && src + 1 < in->len
5447+ && in->ptr[src + 1] == comment_char
5448+ && !inquote)
5449+ {
5450+ /* Two comment chars in a row cause the rest of the line to
5451+ be dropped. */
5452+ while (src < in->len && in->ptr[src] != '\n')
5453+ src++;
5454+ }
5455 else if (in->ptr[src] == '"'
5456 || (macro_mri && in->ptr[src] == '\''))
5457 {
5458@@ -880,11 +899,12 @@
5459 body. */
5460
5461 static const char *
5462-macro_expand (idx, in, m, out)
5463+macro_expand (idx, in, m, out, comment_char)
5464 int idx;
5465 sb *in;
5466 macro_entry *m;
5467 sb *out;
5468+ int comment_char;
5469 {
5470 sb t;
5471 formal_entry *ptr;
5472@@ -934,7 +954,7 @@
5473
5474 /* Peel off the actuals and store them away in the hash tables' actuals. */
5475 idx = sb_skip_white (idx, in);
5476- while (idx < in->len)
5477+ while (idx < in->len && in->ptr[idx] != comment_char)
5478 {
5479 int scan;
5480
5481@@ -1036,7 +1056,7 @@
5482 sb_add_string (&ptr->actual, buffer);
5483 }
5484
5485- err = macro_expand_body (&m->sub, out, m->formals, m->formal_hash, 1);
5486+ err = macro_expand_body (&m->sub, out, m->formals, m->formal_hash, comment_char, 1);
5487 if (err != NULL)
5488 return err;
5489
5490@@ -1072,9 +1092,10 @@
5491 *EXPAND. Return 1 if a macro is found, 0 otherwise. */
5492
5493 int
5494-check_macro (line, expand, error, info)
5495+check_macro (line, expand, comment_char, error, info)
5496 const char *line;
5497 sb *expand;
5498+ int comment_char;
5499 const char **error;
5500 macro_entry **info;
5501 {
5502@@ -1112,7 +1133,7 @@
5503 sb_add_char (&line_sb, *s++);
5504
5505 sb_new (expand);
5506- *error = macro_expand (0, &line_sb, macro, expand);
5507+ *error = macro_expand (0, &line_sb, macro, expand, comment_char);
5508
5509 sb_kill (&line_sb);
5510
5511@@ -1137,12 +1158,13 @@
5512 success, or an error message otherwise. */
5513
5514 const char *
5515-expand_irp (irpc, idx, in, out, get_line)
5516+expand_irp (irpc, idx, in, out, get_line, comment_char)
5517 int irpc;
5518 int idx;
5519 sb *in;
5520 sb *out;
5521 int (*get_line) PARAMS ((sb *));
5522+ int comment_char;
5523 {
5524 const char *mn;
5525 sb sub;
5526@@ -1180,10 +1202,10 @@
5527 sb_reset (out);
5528
5529 idx = sb_skip_comma (idx, in);
5530- if (idx >= in->len)
5531+ if (idx >= in->len || in->ptr[idx] == comment_char)
5532 {
5533 /* Expand once with a null string. */
5534- err = macro_expand_body (&sub, out, &f, h, 0);
5535+ err = macro_expand_body (&sub, out, &f, h, comment_char, 0);
5536 if (err != NULL)
5537 return err;
5538 }
5539@@ -1191,7 +1213,7 @@
5540 {
5541 if (irpc && in->ptr[idx] == '"')
5542 ++idx;
5543- while (idx < in->len)
5544+ while (idx < in->len && in->ptr[idx] != comment_char)
5545 {
5546 if (!irpc)
5547 idx = get_any_string (idx, in, &f.actual, 1, 0);
5548@@ -1202,7 +1224,7 @@
5549 int nxt;
5550
5551 nxt = sb_skip_white (idx + 1, in);
5552- if (nxt >= in->len)
5553+ if (nxt >= in->len || in->ptr[nxt] == comment_char)
5554 {
5555 idx = nxt;
5556 break;
5557@@ -1212,7 +1234,7 @@
5558 sb_add_char (&f.actual, in->ptr[idx]);
5559 ++idx;
5560 }
5561- err = macro_expand_body (&sub, out, &f, h, 0);
5562+ err = macro_expand_body (&sub, out, &f, h, comment_char, 0);
5563 if (err != NULL)
5564 return err;
5565 if (!irpc)
5566diff -Nur binutils-2.13.90.0.18.orig/gas/macro.h binutils-2.13.90.0.18/gas/macro.h
5567--- binutils-2.13.90.0.18.orig/gas/macro.h Sun Feb 2 03:21:18 2003
5568+++ binutils-2.13.90.0.18/gas/macro.h Sun Feb 2 15:23:24 2003
5569@@ -79,10 +79,10 @@
5570 extern const char *define_macro
5571 PARAMS ((int, sb *, sb *, int (*) PARAMS ((sb *)), const char **));
5572 extern int check_macro
5573- PARAMS ((const char *, sb *, const char **, macro_entry **));
5574+ PARAMS ((const char *, sb *, int, const char **, macro_entry **));
5575 extern void delete_macro
5576 PARAMS ((const char *));
5577 extern const char *expand_irp
5578- PARAMS ((int, int, sb *, sb *, int (*) PARAMS ((sb *))));
5579+ PARAMS ((int, int, sb *, sb *, int (*) PARAMS ((sb *)), int));
5580
5581 #endif
5582diff -Nur binutils-2.13.90.0.18.orig/gas/read.c binutils-2.13.90.0.18/gas/read.c
5583--- binutils-2.13.90.0.18.orig/gas/read.c Sun Feb 2 03:21:18 2003
5584+++ binutils-2.13.90.0.18/gas/read.c Sun Feb 2 15:26:06 2003
5585@@ -862,7 +862,7 @@
5586 const char *err;
5587 macro_entry *macro;
5588
5589- if (check_macro (s, &out, &err, &macro))
5590+ if (check_macro (s, &out, '\0', &err, &macro))
5591 {
5592 if (err != NULL)
5593 as_bad ("%s", err);
5594@@ -1855,7 +1855,7 @@
5595
5596 sb_new (&out);
5597
5598- err = expand_irp (irpc, 0, &s, &out, get_line_sb);
5599+ err = expand_irp (irpc, 0, &s, &out, get_line_sb, '\0');
5600 if (err != NULL)
5601 as_bad_where (file, line, "%s", err);
5602
This page took 1.080964 seconds and 4 git commands to generate.