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