look in srcdir for texinfo source, then in objdir
[deliverable/binutils-gdb.git] / gas / read.c
CommitLineData
fecd2382 1/* read.c - read a source file -
f8701a3f 2 Copyright (C) 1986, 1987, 1990, 1991 Free Software Foundation, Inc.
3340f7e5 3
f8701a3f
SC
4This file is part of GAS, the GNU Assembler.
5
6GAS is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GAS is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GAS; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
fecd2382 19
016e0d42 20#if 0
fecd2382
RP
21#define MASK_CHAR (0xFF) /* If your chars aren't 8 bits, you will
22 change this a bit. But then, GNU isn't
23 spozed to run on your machine anyway.
24 (RMS is so shortsighted sometimes.)
25 */
016e0d42
ILT
26#else
27#define MASK_CHAR ((int)(unsigned char)-1)
28#endif
fecd2382 29
9471a360
KR
30/* This is the largest known floating point format (for now). It will
31 grow when we do 4361 style flonums. */
fecd2382 32
9471a360 33#define MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT (16)
fecd2382 34
016e0d42
ILT
35/* Routines that read assembler source text to build spagetti in memory.
36 Another group of these functions is in the expr.c module. */
fecd2382 37
9471a360 38/* for isdigit() */
6efd877d
KR
39#include <ctype.h>
40
fecd2382 41#include "as.h"
9471a360
KR
42#ifdef BFD_ASSEMBLER
43#include "subsegs.h"
44#endif
fecd2382
RP
45
46#include "obstack.h"
fecd2382 47
016e0d42
ILT
48/* The NOP_OPCODE is for the alignment fill value.
49 * fill it a nop instruction so that the disassembler does not choke
50 * on it
51 */
52#ifndef NOP_OPCODE
53#define NOP_OPCODE 0x00
54#endif
55
56char *input_line_pointer; /*->next char of source file to parse. */
fecd2382
RP
57
58#if BITS_PER_CHAR != 8
6efd877d
KR
59/* The following table is indexed by[(char)] and will break if
60 a char does not have exactly 256 states (hopefully 0:255!)! */
61die horribly;
fecd2382 62#endif
f8701a3f 63
016e0d42
ILT
64/* used by is_... macros. our ctype[] */
65const char lex_type[256] =
66{
67 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ABCDEFGHIJKLMNO */
68 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* PQRSTUVWXYZ[\]^_ */
69 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, /* _!"#$%&'()*+,-./ */
70 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0123456789:;<=>? */
71 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* @ABCDEFGHIJKLMNO */
72 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, /* PQRSTUVWXYZ[\]^_ */
73 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* `abcdefghijklmno */
74 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, /* pqrstuvwxyz{|}~. */
75 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
76 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
77 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
78 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
79 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
80 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
81 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
82};
83
84
85/*
fecd2382
RP
86 * In: a character.
87 * Out: 1 if this character ends a line.
88 */
89#define _ (0)
016e0d42
ILT
90char is_end_of_line[256] =
91{
fecd2382 92#ifdef CR_EOL
016e0d42 93 _, _, _, _, _, _, _, _, _, _, 99, _, _, 99, _, _, /* @abcdefghijklmno */
fecd2382 94#else
016e0d42 95 _, _, _, _, _, _, _, _, _, _, 99, _, _, _, _, _, /* @abcdefghijklmno */
fecd2382 96#endif
016e0d42
ILT
97 _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
98 _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
99 _, _, _, _, _, _, _, _, _, _, _, 99, _, _, _, _, /* 0123456789:;<=>? */
100 _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
101 _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
102 _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
103 _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
104 _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
105 _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
106 _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
107 _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
108 _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
109};
fecd2382
RP
110#undef _
111
016e0d42
ILT
112/* Functions private to this file. */
113
114static char *buffer; /* 1st char of each buffer of lines is here. */
115static char *buffer_limit; /*->1 + last char in buffer. */
fecd2382 116
016e0d42
ILT
117static char *bignum_low; /* Lowest char of bignum. */
118static char *bignum_limit; /* 1st illegal address of bignum. */
119static char *bignum_high; /* Highest char of bignum. */
120/* May point to (bignum_start-1). */
121/* Never >= bignum_limit. */
fecd2382 122
9471a360 123static char *old_buffer; /* JF a hack */
016e0d42
ILT
124static char *old_input;
125static char *old_limit;
fecd2382 126
016e0d42 127/* Variables for handling include file directory list. */
fecd2382 128
016e0d42
ILT
129char **include_dirs; /* List of pointers to directories to
130 search for .include's */
131int include_dir_count; /* How many are in the list */
132int include_dir_maxlen = 1;/* Length of longest in list */
fecd2382
RP
133
134#ifndef WORKING_DOT_WORD
016e0d42 135struct broken_word *broken_words;
9471a360 136int new_broken_words;
fecd2382
RP
137#endif
138
016e0d42
ILT
139static char *demand_copy_string PARAMS ((int *lenP));
140int is_it_end_of_statement PARAMS ((void));
141unsigned int next_char_of_string PARAMS ((void));
142static segT get_known_segmented_expression PARAMS ((expressionS * expP));
143static void grow_bignum PARAMS ((void));
144static void pobegin PARAMS ((void));
145void stringer PARAMS ((int append_zero));
fecd2382 146
016e0d42 147extern int listing;
fecd2382 148\f
6efd877d 149
016e0d42
ILT
150void
151read_begin ()
fecd2382 152{
016e0d42 153 const char *p;
f8701a3f 154
6efd877d
KR
155 pobegin ();
156 obj_read_begin_hook ();
f8701a3f 157
6efd877d
KR
158 obstack_begin (&notes, 5000);
159 obstack_begin (&cond_obstack, 960);
f8701a3f 160
fecd2382 161#define BIGNUM_BEGIN_SIZE (16)
6efd877d 162 bignum_low = xmalloc ((long) BIGNUM_BEGIN_SIZE);
f8701a3f
SC
163 bignum_limit = bignum_low + BIGNUM_BEGIN_SIZE;
164
165 /* Use machine dependent syntax */
166 for (p = line_separator_chars; *p; p++)
167 is_end_of_line[*p] = 1;
168 /* Use more. FIXME-SOMEDAY. */
fecd2382
RP
169}
170\f
171/* set up pseudo-op tables */
172
c8863a58 173struct hash_control *po_hash;
fecd2382 174
016e0d42 175static const pseudo_typeS potable[] =
fecd2382 176{
6efd877d
KR
177 {"abort", s_abort, 0},
178 {"align", s_align_ptwo, 0},
179 {"ascii", stringer, 0},
180 {"asciz", stringer, 1},
f8701a3f 181/* block */
6efd877d
KR
182 {"byte", cons, 1},
183 {"comm", s_comm, 0},
184 {"data", s_data, 0},
f8701a3f 185/* dim */
6efd877d 186 {"double", float_cons, 'd'},
f8701a3f 187/* dsect */
6efd877d
KR
188 {"eject", listing_eject, 0}, /* Formfeed listing */
189 {"else", s_else, 0},
190 {"end", s_end, 0},
191 {"endif", s_endif, 0},
f8701a3f 192/* endef */
6efd877d 193 {"equ", s_set, 0},
f8701a3f
SC
194/* err */
195/* extend */
6efd877d
KR
196 {"extern", s_ignore, 0}, /* We treat all undef as ext */
197 {"app-file", s_app_file, 0},
198 {"file", s_app_file, 0},
199 {"fill", s_fill, 0},
200 {"float", float_cons, 'f'},
6efd877d
KR
201 {"global", s_globl, 0},
202 {"globl", s_globl, 0},
203 {"hword", cons, 2},
204 {"if", s_if, 0},
205 {"ifdef", s_ifdef, 0},
206 {"ifeqs", s_ifeqs, 0},
207 {"ifndef", s_ifdef, 1},
208 {"ifnes", s_ifeqs, 1},
209 {"ifnotdef", s_ifdef, 1},
210 {"include", s_include, 0},
211 {"int", cons, 4},
212 {"lcomm", s_lcomm, 0},
213 {"lflags", listing_flags, 0}, /* Listing flags */
214 {"list", listing_list, 1}, /* Turn listing on */
215 {"long", cons, 4},
216 {"lsym", s_lsym, 0},
217 {"nolist", listing_list, 0}, /* Turn listing off */
218 {"octa", big_cons, 16},
219 {"org", s_org, 0},
220 {"psize", listing_psize, 0}, /* set paper size */
f8701a3f 221/* print */
6efd877d
KR
222 {"quad", big_cons, 8},
223 {"sbttl", listing_title, 1}, /* Subtitle of listing */
f8701a3f
SC
224/* scl */
225/* sect */
6efd877d
KR
226 {"set", s_set, 0},
227 {"short", cons, 2},
228 {"single", float_cons, 'f'},
f8701a3f 229/* size */
6efd877d 230 {"space", s_space, 0},
f8701a3f 231/* tag */
6efd877d
KR
232 {"text", s_text, 0},
233 {"title", listing_title, 0}, /* Listing title */
f8701a3f
SC
234/* type */
235/* use */
236/* val */
6efd877d
KR
237 {"word", cons, 2},
238 {NULL} /* end sentinel */
fecd2382
RP
239};
240
6efd877d
KR
241static void
242pobegin ()
243{
244 char *errtxt; /* error text */
245 const pseudo_typeS *pop;
246
247 po_hash = hash_new ();
248
249 /* Do the target-specific pseudo ops. */
250 for (pop = md_pseudo_table; pop->poc_name; pop++)
251 {
252 errtxt = hash_insert (po_hash, pop->poc_name, (char *) pop);
253 if (errtxt && *errtxt)
254 {
255 as_fatal ("error constructing md pseudo-op table");
256 } /* on error */
257 } /* for each op */
258
259 /* Now object specific. Skip any that were in the target table. */
260 for (pop = obj_pseudo_table; pop->poc_name; pop++)
261 {
262 errtxt = hash_insert (po_hash, pop->poc_name, (char *) pop);
263 if (errtxt && *errtxt)
264 {
265 if (!strcmp (errtxt, "exists"))
266 {
fecd2382 267#ifdef DIE_ON_OVERRIDES
6efd877d 268 as_fatal ("pseudo op \".%s\" overridden.\n", pop->poc_name);
fecd2382 269#endif /* DIE_ON_OVERRIDES */
6efd877d
KR
270 continue; /* OK if target table overrides. */
271 }
272 else
273 {
274 as_fatal ("error constructing obj pseudo-op table");
275 } /* if overridden */
276 } /* on error */
277 } /* for each op */
278
279 /* Now portable ones. Skip any that we've seen already. */
280 for (pop = potable; pop->poc_name; pop++)
281 {
282 errtxt = hash_insert (po_hash, pop->poc_name, (char *) pop);
283 if (errtxt && *errtxt)
284 {
285 if (!strcmp (errtxt, "exists"))
286 {
fecd2382 287#ifdef DIE_ON_OVERRIDES
6efd877d 288 as_fatal ("pseudo op \".%s\" overridden.\n", pop->poc_name);
fecd2382 289#endif /* DIE_ON_OVERRIDES */
6efd877d
KR
290 continue; /* OK if target table overrides. */
291 }
292 else
293 {
294 as_fatal ("error constructing obj pseudo-op table");
295 } /* if overridden */
296 } /* on error */
297 } /* for each op */
298
299 return;
300} /* pobegin() */
fecd2382
RP
301\f
302#define HANDLE_CONDITIONAL_ASSEMBLY() \
f8701a3f
SC
303 if (ignore_input ()) \
304 { \
305 while (! is_end_of_line[*input_line_pointer++]) \
306 if (input_line_pointer == buffer_limit) \
307 break; \
308 continue; \
309 }
a39116f1 310
fecd2382
RP
311
312/* read_a_source_file()
313 *
314 * We read the file, putting things into a web that
315 * represents what we have been reading.
316 */
6efd877d
KR
317void
318read_a_source_file (name)
319 char *name;
fecd2382 320{
f8701a3f 321 register char c;
6efd877d 322 register char *s; /* string of symbol, '\0' appended */
f8701a3f 323 register int temp;
6efd877d
KR
324 /* register struct frag * fragP; JF unused *//* a frag we just made */
325 pseudo_typeS *pop;
f8701a3f 326
6efd877d 327 buffer = input_scrub_new_file (name);
f8701a3f 328
6efd877d
KR
329 listing_file (name);
330 listing_newline ("");
f8701a3f 331
6efd877d
KR
332 while ((buffer_limit = input_scrub_next_buffer (&input_line_pointer)) != 0)
333 { /* We have another line to parse. */
334 know (buffer_limit[-1] == '\n'); /* Must have a sentinel. */
9471a360
KR
335 contin: /* JF this goto is my fault I admit it.
336 Someone brave please re-write the whole
337 input section here? Pleeze??? */
6efd877d 338 while (input_line_pointer < buffer_limit)
9471a360
KR
339 {
340 /* We have more of this buffer to parse. */
f8701a3f
SC
341
342 /*
343 * We now have input_line_pointer->1st char of next line.
344 * If input_line_pointer [-1] == '\n' then we just
345 * scanned another line: so bump line counters.
346 */
6efd877d
KR
347 if (input_line_pointer[-1] == '\n')
348 {
349 bump_line_counters ();
f8701a3f
SC
350
351#ifdef MRI
352 /* Text at the start of a line must be a label, we run down and stick a colon in */
6efd877d
KR
353 if (is_name_beginner (*input_line_pointer))
354 {
355 char *line_start = input_line_pointer;
356 char c = get_symbol_end ();
357 colon (line_start);
358 *input_line_pointer = c;
359 if (c == ':')
360 input_line_pointer++;
361
362 }
f8701a3f 363#endif
9471a360 364 }
f8701a3f
SC
365
366
f8701a3f
SC
367 /*
368 * We are at the begining of a line, or similar place.
369 * We expect a well-formed assembler statement.
370 * A "symbol-name:" is a statement.
371 *
372 * Depending on what compiler is used, the order of these tests
373 * may vary to catch most common case 1st.
374 * Each test is independent of all other tests at the (top) level.
375 * PLEASE make a compiler that doesn't use this assembler.
376 * It is crufty to waste a compiler's time encoding things for this
377 * assembler, which then wastes more time decoding it.
378 * (And communicating via (linear) files is silly!
379 * If you must pass stuff, please pass a tree!)
380 */
9471a360
KR
381 if ((c = *input_line_pointer++) == '\t'
382 || c == ' '
383 || c == '\f'
384 || c == 0)
6efd877d
KR
385 {
386 c = *input_line_pointer++;
387 }
388 know (c != ' '); /* No further leading whitespace. */
389 LISTING_NEWLINE ();
f8701a3f
SC
390 /*
391 * C is the 1st significant character.
392 * Input_line_pointer points after that character.
393 */
6efd877d
KR
394 if (is_name_beginner (c))
395 { /* want user-defined label or pseudo/opcode */
396 HANDLE_CONDITIONAL_ASSEMBLY ();
397
f8701a3f 398 s = --input_line_pointer;
6efd877d 399 c = get_symbol_end (); /* name's delimiter */
f8701a3f
SC
400 /*
401 * C is character after symbol.
402 * That character's place in the input line is now '\0'.
403 * S points to the beginning of the symbol.
404 * [In case of pseudo-op, s->'.'.]
405 * Input_line_pointer->'\0' where c was.
406 */
6efd877d
KR
407 if (c == ':')
408 {
409 colon (s); /* user-defined label */
410 *input_line_pointer++ = ':'; /* Put ':' back for error messages' sake. */
f8701a3f 411 /* Input_line_pointer->after ':'. */
6efd877d
KR
412 SKIP_WHITESPACE ();
413
f8701a3f 414
6efd877d
KR
415 }
416 else if (c == '=' || input_line_pointer[1] == '=')
417 { /* JF deal with FOO=BAR */
418 equals (s);
419 demand_empty_rest_of_line ();
420 }
421 else
422 { /* expect pseudo-op or machine instruction */
f8701a3f 423#ifdef MRI
6efd877d
KR
424 if (!done_pseudo (s))
425
f8701a3f 426#else
6efd877d
KR
427 if (*s == '.')
428 {
429 /*
9471a360
KR
430 * PSEUDO - OP.
431 *
432 * WARNING: c has next char, which may be end-of-line.
433 * We lookup the pseudo-op table with s+1 because we
434 * already know that the pseudo-op begins with a '.'.
435 */
6efd877d
KR
436
437 pop = (pseudo_typeS *) hash_find (po_hash, s + 1);
438
439 /* Print the error msg now, while we still can */
440 if (!pop)
441 {
442 as_bad ("Unknown pseudo-op: `%s'", s);
f8701a3f 443 *input_line_pointer = c;
6efd877d
KR
444 s_ignore (0);
445 break;
446 }
447
448 /* Put it back for error messages etc. */
449 *input_line_pointer = c;
450 /* The following skip of whitespace is compulsory. */
451 /* A well shaped space is sometimes all that separates keyword from operands. */
452 if (c == ' ' || c == '\t')
453 {
454 input_line_pointer++;
455 } /* Skip seperator after keyword. */
456 /*
9471a360
KR
457 * Input_line is restored.
458 * Input_line_pointer->1st non-blank char
459 * after pseudo-operation.
460 */
6efd877d
KR
461 if (!pop)
462 {
463 ignore_rest_of_line ();
464 break;
465 }
466 else
467 {
468 (*pop->poc_handler) (pop->poc_val);
469 } /* if we have one */
470 }
471 else
f8701a3f 472#endif
6efd877d
KR
473 { /* machine instruction */
474 /* WARNING: c has char, which may be end-of-line. */
475 /* Also: input_line_pointer->`\0` where c was. */
476 *input_line_pointer = c;
477 while (!is_end_of_line[*input_line_pointer])
478 {
479 input_line_pointer++;
480 }
f8701a3f 481
6efd877d
KR
482 c = *input_line_pointer;
483 *input_line_pointer = '\0';
f8701a3f 484
6efd877d 485 md_assemble (s); /* Assemble 1 instruction. */
f8701a3f 486
6efd877d 487 *input_line_pointer++ = c;
f8701a3f 488
6efd877d
KR
489 /* We resume loop AFTER the end-of-line from this instruction */
490 } /* if (*s=='.') */
491
492 } /* if c==':' */
f8701a3f 493 continue;
6efd877d 494 } /* if (is_name_beginner(c) */
f8701a3f 495
f8701a3f 496
6efd877d
KR
497 if (is_end_of_line[c])
498 {
f8701a3f 499 continue;
6efd877d
KR
500 } /* empty statement */
501
502
503#if defined(LOCAL_LABELS_DOLLAR) || defined(LOCAL_LABELS_FB)
504 if (isdigit (c))
505 { /* local label ("4:") */
506 char *backup = input_line_pointer;
507
508 HANDLE_CONDITIONAL_ASSEMBLY ();
509
510 temp = c - '0';
511
512 while (isdigit (*input_line_pointer))
513 {
514 temp = (temp * 10) + *input_line_pointer - '0';
515 ++input_line_pointer;
516 } /* read the whole number */
517
518#ifdef LOCAL_LABELS_DOLLAR
519 if (*input_line_pointer == '$'
520 && *(input_line_pointer + 1) == ':')
521 {
522 input_line_pointer += 2;
523
524 if (dollar_label_defined (temp))
525 {
526 as_fatal ("label \"%d$\" redefined", temp);
527 }
528
529 define_dollar_label (temp);
530 colon (dollar_label_name (temp, 0));
531 continue;
532 }
f8701a3f 533#endif /* LOCAL_LABELS_DOLLAR */
6efd877d 534
f8701a3f 535#ifdef LOCAL_LABELS_FB
6efd877d
KR
536 if (*input_line_pointer++ == ':')
537 {
538 fb_label_instance_inc (temp);
539 colon (fb_label_name (temp, 0));
540 continue;
541 }
f8701a3f 542#endif /* LOCAL_LABELS_FB */
6efd877d
KR
543
544 input_line_pointer = backup;
545 } /* local label ("4:") */
f8701a3f
SC
546#endif /* LOCAL_LABELS_DOLLAR or LOCAL_LABELS_FB */
547
6efd877d
KR
548 if (c && strchr (line_comment_chars, c))
549 { /* Its a comment. Better say APP or NO_APP */
f8701a3f
SC
550 char *ends;
551 char *new_buf;
552 char *new_tmp;
553 int new_length;
554 char *tmp_buf = 0;
6efd877d
KR
555 extern char *scrub_string, *scrub_last_string;
556
557 bump_line_counters ();
558 s = input_line_pointer;
559 if (strncmp (s, "APP\n", 4))
560 continue; /* We ignore it */
561 s += 4;
562
563 ends = strstr (s, "#NO_APP\n");
564
565 if (!ends)
566 {
f8701a3f
SC
567 int tmp_len;
568 int num;
6efd877d 569
f8701a3f
SC
570 /* The end of the #APP wasn't in this buffer. We
571 keep reading in buffers until we find the #NO_APP
572 that goes with this #APP There is one. The specs
573 guarentee it. . . */
6efd877d 574 tmp_len = buffer_limit - s;
85825401 575 tmp_buf = xmalloc (tmp_len + 1);
6efd877d
KR
576 bcopy (s, tmp_buf, tmp_len);
577 do
578 {
579 new_tmp = input_scrub_next_buffer (&buffer);
f8701a3f 580 if (!new_tmp)
6efd877d 581 break;
f8701a3f 582 else
6efd877d 583 buffer_limit = new_tmp;
f8701a3f 584 input_line_pointer = buffer;
6efd877d 585 ends = strstr (buffer, "#NO_APP\n");
f8701a3f 586 if (ends)
6efd877d 587 num = ends - buffer;
f8701a3f 588 else
6efd877d
KR
589 num = buffer_limit - buffer;
590
591 tmp_buf = xrealloc (tmp_buf, tmp_len + num);
592 bcopy (buffer, tmp_buf + tmp_len, num);
593 tmp_len += num;
594 }
595 while (!ends);
596
597 input_line_pointer = ends ? ends + 8 : NULL;
598
599 s = tmp_buf;
600 ends = s + tmp_len;
601
602 }
603 else
604 {
605 input_line_pointer = ends + 8;
606 }
607 new_buf = xmalloc (100);
608 new_length = 100;
609 new_tmp = new_buf;
610
611 scrub_string = s;
f8701a3f 612 scrub_last_string = ends;
6efd877d
KR
613 for (;;)
614 {
f8701a3f
SC
615 int ch;
616
6efd877d
KR
617 ch = do_scrub_next_char (scrub_from_string, scrub_to_string);
618 if (ch == EOF)
619 break;
620 *new_tmp++ = ch;
621 if (new_tmp == new_buf + new_length)
622 {
623 new_buf = xrealloc (new_buf, new_length + 100);
624 new_tmp = new_buf + new_length;
625 new_length += 100;
f8701a3f 626 }
fecd2382 627 }
f8701a3f
SC
628
629 if (tmp_buf)
6efd877d
KR
630 free (tmp_buf);
631 old_buffer = buffer;
632 old_input = input_line_pointer;
633 old_limit = buffer_limit;
634 buffer = new_buf;
635 input_line_pointer = new_buf;
636 buffer_limit = new_tmp;
f8701a3f
SC
637 continue;
638 }
639
6efd877d 640 HANDLE_CONDITIONAL_ASSEMBLY ();
f8701a3f
SC
641
642 /* as_warn("Junk character %d.",c); Now done by ignore_rest */
643 input_line_pointer--; /* Report unknown char as ignored. */
6efd877d
KR
644 ignore_rest_of_line ();
645 } /* while (input_line_pointer<buffer_limit) */
646 if (old_buffer)
647 {
648 bump_line_counters ();
649 if (old_input != 0)
650 {
651 buffer = old_buffer;
652 input_line_pointer = old_input;
653 buffer_limit = old_limit;
f8701a3f
SC
654 old_buffer = 0;
655 goto contin;
656 }
657 }
6efd877d
KR
658 } /* while (more buffers to scan) */
659 input_scrub_close (); /* Close the input file */
f8701a3f 660
6efd877d 661} /* read_a_source_file() */
fecd2382 662
6efd877d
KR
663void
664s_abort ()
665{
666 as_fatal (".abort detected. Abandoning ship.");
667} /* s_abort() */
fecd2382
RP
668
669/* For machines where ".align 4" means align to a 4 byte boundary. */
6efd877d
KR
670void
671s_align_bytes (arg)
672 int arg;
fecd2382 673{
6efd877d
KR
674 register unsigned int temp;
675 register long temp_fill;
676 unsigned int i = 0;
677 unsigned long max_alignment = 1 << 15;
f8701a3f 678
6efd877d
KR
679 if (is_end_of_line[*input_line_pointer])
680 temp = arg; /* Default value from pseudo-op table */
681 else
682 temp = get_absolute_expression ();
f8701a3f 683
6efd877d
KR
684 if (temp > max_alignment)
685 {
686 as_bad ("Alignment too large: %d. assumed.", temp = max_alignment);
f8701a3f
SC
687 }
688
6efd877d 689 /*
f8701a3f
SC
690 * For the sparc, `.align (1<<n)' actually means `.align n'
691 * so we have to convert it.
692 */
6efd877d
KR
693 if (temp != 0)
694 {
695 for (i = 0; (temp & 1) == 0; temp >>= 1, ++i)
696 ;
f8701a3f 697 }
6efd877d
KR
698 if (temp != 1)
699 as_bad ("Alignment not a power of 2");
f8701a3f 700
6efd877d
KR
701 temp = i;
702 if (*input_line_pointer == ',')
703 {
704 input_line_pointer++;
705 temp_fill = get_absolute_expression ();
f8701a3f 706 }
9471a360 707 else if (now_seg != data_section && now_seg != bss_section)
016e0d42 708 temp_fill = NOP_OPCODE;
6efd877d 709 else
016e0d42 710 temp_fill = 0;
6efd877d
KR
711 /* Only make a frag if we HAVE to. . . */
712 if (temp && !need_pass_2)
713 frag_align (temp, (int) temp_fill);
f8701a3f 714
6efd877d
KR
715 demand_empty_rest_of_line ();
716} /* s_align_bytes() */
fecd2382
RP
717
718/* For machines where ".align 4" means align to 2**4 boundary. */
6efd877d
KR
719void
720s_align_ptwo ()
721{
722 register int temp;
723 register long temp_fill;
724 long max_alignment = 15;
725
726 temp = get_absolute_expression ();
727 if (temp > max_alignment)
728 as_bad ("Alignment too large: %d. assumed.", temp = max_alignment);
729 else if (temp < 0)
730 {
731 as_bad ("Alignment negative. 0 assumed.");
732 temp = 0;
733 }
734 if (*input_line_pointer == ',')
735 {
736 input_line_pointer++;
737 temp_fill = get_absolute_expression ();
738 }
9471a360
KR
739 /* @@ Fix this right for BFD! */
740 else if (now_seg != data_section && now_seg != bss_section)
016e0d42 741 temp_fill = NOP_OPCODE;
6efd877d
KR
742 else
743 temp_fill = 0;
744 /* Only make a frag if we HAVE to. . . */
745 if (temp && !need_pass_2)
746 frag_align (temp, (int) temp_fill);
747
748 record_alignment (now_seg, temp);
749
750 demand_empty_rest_of_line ();
751} /* s_align_ptwo() */
752
753void
754s_comm ()
755{
756 register char *name;
757 register char c;
758 register char *p;
759 register int temp;
760 register symbolS *symbolP;
761
762 name = input_line_pointer;
763 c = get_symbol_end ();
764 /* just after name is now '\0' */
765 p = input_line_pointer;
766 *p = c;
767 SKIP_WHITESPACE ();
768 if (*input_line_pointer != ',')
769 {
770 as_bad ("Expected comma after symbol-name: rest of line ignored.");
771 ignore_rest_of_line ();
772 return;
773 }
774 input_line_pointer++; /* skip ',' */
775 if ((temp = get_absolute_expression ()) < 0)
776 {
777 as_warn (".COMMon length (%d.) <0! Ignored.", temp);
778 ignore_rest_of_line ();
779 return;
780 }
781 *p = 0;
782 symbolP = symbol_find_or_make (name);
783 *p = c;
784 if (S_IS_DEFINED (symbolP))
785 {
786 as_bad ("Ignoring attempt to re-define symbol");
787 ignore_rest_of_line ();
788 return;
789 }
790 if (S_GET_VALUE (symbolP))
791 {
792 if (S_GET_VALUE (symbolP) != temp)
793 as_bad ("Length of .comm \"%s\" is already %d. Not changed to %d.",
794 S_GET_NAME (symbolP),
795 S_GET_VALUE (symbolP),
796 temp);
797 }
798 else
799 {
800 S_SET_VALUE (symbolP, temp);
801 S_SET_EXTERNAL (symbolP);
802 }
9471a360
KR
803#ifdef OBJ_VMS
804 if ( (!temp) || !flagseen['1'])
805 S_GET_OTHER(symbolP) = const_flag;
806#endif /* not OBJ_VMS */
6efd877d
KR
807 know (symbolP->sy_frag == &zero_address_frag);
808 demand_empty_rest_of_line ();
809} /* s_comm() */
fecd2382
RP
810
811void
6efd877d 812s_data ()
fecd2382 813{
6efd877d 814 register int temp;
f8701a3f 815
6efd877d 816 temp = get_absolute_expression ();
db81c5e7 817#ifdef BFD_ASSEMBLER
c8863a58 818 subseg_set (data_section, (subsegT) temp);
db81c5e7 819#else
9471a360 820 subseg_new (data_section, (subsegT) temp);
db81c5e7 821#endif
f8701a3f 822
9471a360 823#ifdef OBJ_VMS
6efd877d 824 const_flag = 0;
fecd2382 825#endif
6efd877d 826 demand_empty_rest_of_line ();
fecd2382
RP
827}
828
6efd877d
KR
829void
830s_app_file ()
831{
832 register char *s;
833 int length;
f8701a3f 834
6efd877d
KR
835 /* Some assemblers tolerate immediately following '"' */
836 if ((s = demand_copy_string (&length)) != 0)
837 {
838 new_logical_line (s, -1);
839 demand_empty_rest_of_line ();
840 }
fecd2382 841#ifdef OBJ_COFF
6efd877d 842 c_dot_file_symbol (s);
fecd2382 843#endif /* OBJ_COFF */
6efd877d 844} /* s_app_file() */
fecd2382 845
6efd877d
KR
846void
847s_fill ()
848{
849 long temp_repeat = 0;
850 long temp_size = 1;
851 register long temp_fill = 0;
852 char *p;
f8701a3f 853
7c2d4011 854
6efd877d
KR
855 temp_repeat = get_absolute_expression ();
856 if (*input_line_pointer == ',')
857 {
858 input_line_pointer++;
859 temp_size = get_absolute_expression ();
860 if (*input_line_pointer == ',')
7c2d4011
SC
861 {
862 input_line_pointer++;
6efd877d 863 temp_fill = get_absolute_expression ();
fecd2382 864 }
6efd877d 865 }
c8863a58 866 /* This is to be compatible with BSD 4.2 AS, not for any rational reason. */
fecd2382 867#define BSD_FILL_SIZE_CROCK_8 (8)
6efd877d
KR
868 if (temp_size > BSD_FILL_SIZE_CROCK_8)
869 {
870 as_warn (".fill size clamped to %d.", BSD_FILL_SIZE_CROCK_8);
871 temp_size = BSD_FILL_SIZE_CROCK_8;
872 }
873 if (temp_size < 0)
874 {
875 as_warn ("Size negative: .fill ignored.");
876 temp_size = 0;
877 }
878 else if (temp_repeat <= 0)
879 {
880 as_warn ("Repeat < 0, .fill ignored");
881 temp_size = 0;
882 }
7fd3560a 883
6efd877d
KR
884 if (temp_size && !need_pass_2)
885 {
886 p = frag_var (rs_fill, (int) temp_size, (int) temp_size, (relax_substateT) 0, (symbolS *) 0, temp_repeat, (char *) 0);
c8863a58
KR
887 memset (p, 0, (int) temp_size);
888 /* The magic number BSD_FILL_SIZE_CROCK_4 is from BSD 4.2 VAX
889 * flavoured AS. The following bizzare behaviour is to be
890 * compatible with above. I guess they tried to take up to 8
891 * bytes from a 4-byte expression and they forgot to sign
892 * extend. Un*x Sux. */
fecd2382 893#define BSD_FILL_SIZE_CROCK_4 (4)
c8863a58
KR
894 md_number_to_chars (p, temp_fill,
895 (temp_size > BSD_FILL_SIZE_CROCK_4
896 ? BSD_FILL_SIZE_CROCK_4
897 : (int) temp_size));
898 /* Note: .fill (),0 emits no frag (since we are asked to .fill 0 bytes)
899 * but emits no error message because it seems a legal thing to do.
900 * It is a degenerate case of .fill but could be emitted by a compiler.
901 */
6efd877d 902 }
6efd877d 903 demand_empty_rest_of_line ();
f8701a3f
SC
904}
905
6efd877d
KR
906void
907s_globl ()
908{
909 register char *name;
910 register int c;
911 register symbolS *symbolP;
fecd2382 912
6efd877d
KR
913 do
914 {
915 name = input_line_pointer;
916 c = get_symbol_end ();
917 symbolP = symbol_find_or_make (name);
918 *input_line_pointer = c;
919 SKIP_WHITESPACE ();
920 S_SET_EXTERNAL (symbolP);
921 if (c == ',')
922 {
923 input_line_pointer++;
924 SKIP_WHITESPACE ();
925 if (*input_line_pointer == '\n')
926 c = '\n';
927 }
928 }
929 while (c == ',');
930 demand_empty_rest_of_line ();
931} /* s_globl() */
932
933void
934s_lcomm (needs_align)
c8863a58
KR
935 /* 1 if this was a ".bss" directive, which may require a 3rd argument
936 (alignment); 0 if it was an ".lcomm" (2 args only) */
937 int needs_align;
fecd2382 938{
6efd877d
KR
939 register char *name;
940 register char c;
941 register char *p;
942 register int temp;
943 register symbolS *symbolP;
944 const int max_alignment = 15;
945 int align = 0;
946
947 name = input_line_pointer;
948 c = get_symbol_end ();
949 p = input_line_pointer;
950 *p = c;
951 SKIP_WHITESPACE ();
952 if (*input_line_pointer != ',')
953 {
954 as_bad ("Expected comma after name");
955 ignore_rest_of_line ();
956 return;
957 }
f8701a3f 958
6efd877d 959 ++input_line_pointer;
f8701a3f 960
6efd877d
KR
961 if (*input_line_pointer == '\n')
962 {
963 as_bad ("Missing size expression");
964 return;
965 }
f8701a3f 966
6efd877d
KR
967 if ((temp = get_absolute_expression ()) < 0)
968 {
969 as_warn ("BSS length (%d.) <0! Ignored.", temp);
970 ignore_rest_of_line ();
971 return;
972 }
f8701a3f 973
6efd877d
KR
974 if (needs_align)
975 {
976 align = 0;
977 SKIP_WHITESPACE ();
978 if (*input_line_pointer != ',')
979 {
980 as_bad ("Expected comma after size");
981 ignore_rest_of_line ();
982 return;
983 }
984 input_line_pointer++;
985 SKIP_WHITESPACE ();
986 if (*input_line_pointer == '\n')
987 {
988 as_bad ("Missing alignment");
989 return;
990 }
991 align = get_absolute_expression ();
992 if (align > max_alignment)
993 {
994 align = max_alignment;
995 as_warn ("Alignment too large: %d. assumed.", align);
996 }
997 else if (align < 0)
998 {
999 align = 0;
1000 as_warn ("Alignment negative. 0 assumed.");
1001 }
c8863a58 1002 record_alignment (bss_section, align);
6efd877d 1003 } /* if needs align */
f8701a3f 1004
6efd877d
KR
1005 *p = 0;
1006 symbolP = symbol_find_or_make (name);
1007 *p = c;
f8701a3f 1008
6efd877d 1009 if (
fecd2382 1010#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
6efd877d
KR
1011 S_GET_OTHER (symbolP) == 0 &&
1012 S_GET_DESC (symbolP) == 0 &&
fecd2382 1013#endif /* OBJ_AOUT or OBJ_BOUT */
c8863a58 1014 (S_GET_SEGMENT (symbolP) == bss_section
6efd877d
KR
1015 || (!S_IS_DEFINED (symbolP) && S_GET_VALUE (symbolP) == 0)))
1016 {
85825401
ILT
1017 char *p;
1018 segT current_seg = now_seg;
1019 subsegT current_subseg = now_subseg;
1020
9471a360
KR
1021#ifdef BFD_ASSEMBLER
1022 subseg_set (bss_section, 1);
1023#else
c8863a58 1024 subseg_new (bss_section, 1);
9471a360 1025#endif
85825401
ILT
1026
1027 if (align)
1028 frag_align (align, 0);
1029 /* detach from old frag */
c8863a58 1030 if (S_GET_SEGMENT (symbolP) == bss_section)
85825401
ILT
1031 symbolP->sy_frag->fr_symbol = NULL;
1032
1033 symbolP->sy_frag = frag_now;
1034 p = frag_var (rs_org, 1, 1, (relax_substateT)0, symbolP,
1035 temp, (char *)0);
1036 *p = 0;
f8701a3f 1037
c8863a58 1038 S_SET_SEGMENT (symbolP, bss_section);
85825401 1039
fecd2382 1040#ifdef OBJ_COFF
6efd877d 1041 /* The symbol may already have been created with a preceding
c8863a58
KR
1042 ".globl" directive -- be careful not to step on storage class
1043 in that case. Otherwise, set it to static. */
6efd877d
KR
1044 if (S_GET_STORAGE_CLASS (symbolP) != C_EXT)
1045 {
1046 S_SET_STORAGE_CLASS (symbolP, C_STAT);
fecd2382 1047 }
6efd877d 1048#endif /* OBJ_COFF */
9471a360
KR
1049#ifdef BFD_ASSEMBLER
1050 subseg_set (current_seg, current_subseg);
1051#else
85825401 1052 subseg_new (current_seg, current_subseg);
9471a360 1053#endif
6efd877d
KR
1054 }
1055 else
1056 {
85825401 1057 as_bad ("Ignoring attempt to re-define symbol %s.", name);
6efd877d
KR
1058 }
1059 demand_empty_rest_of_line ();
f8701a3f 1060
6efd877d
KR
1061 return;
1062} /* s_lcomm() */
fecd2382
RP
1063
1064void
6efd877d 1065s_long ()
fecd2382 1066{
6efd877d 1067 cons (4);
fecd2382
RP
1068}
1069
1070void
6efd877d 1071s_int ()
fecd2382 1072{
6efd877d 1073 cons (4);
fecd2382
RP
1074}
1075
6efd877d
KR
1076void
1077s_lsym ()
1078{
1079 register char *name;
1080 register char c;
1081 register char *p;
1082 register segT segment;
1083 expressionS exp;
1084 register symbolS *symbolP;
1085
1086 /* we permit ANY defined expression: BSD4.2 demands constants */
1087 name = input_line_pointer;
1088 c = get_symbol_end ();
1089 p = input_line_pointer;
1090 *p = c;
1091 SKIP_WHITESPACE ();
1092 if (*input_line_pointer != ',')
1093 {
1094 *p = 0;
1095 as_bad ("Expected comma after name \"%s\"", name);
1096 *p = c;
1097 ignore_rest_of_line ();
1098 return;
1099 }
1100 input_line_pointer++;
1101 segment = expression (&exp);
9471a360
KR
1102 if (segment != absolute_section
1103 && segment != reg_section
1104 && ! SEG_NORMAL (segment))
6efd877d
KR
1105 {
1106 as_bad ("Bad expression: %s", segment_name (segment));
1107 ignore_rest_of_line ();
1108 return;
1109 }
1110 *p = 0;
1111 symbolP = symbol_find_or_make (name);
f8701a3f 1112
c8863a58
KR
1113 /* FIXME-SOON I pulled a (&& symbolP->sy_other == 0 &&
1114 symbolP->sy_desc == 0) out of this test because coff doesn't have
1115 those fields, and I can't see when they'd ever be tripped. I
1116 don't think I understand why they were here so I may have
1117 introduced a bug. As recently as 1.37 didn't have this test
1118 anyway. xoxorich. */
f8701a3f 1119
9471a360 1120 if (S_GET_SEGMENT (symbolP) == undefined_section
6efd877d
KR
1121 && S_GET_VALUE (symbolP) == 0)
1122 {
c8863a58
KR
1123 /* The name might be an undefined .global symbol; be sure to
1124 keep the "external" bit. */
6efd877d
KR
1125 S_SET_SEGMENT (symbolP, segment);
1126 S_SET_VALUE (symbolP, (valueT) (exp.X_add_number));
1127 }
1128 else
1129 {
1130 as_bad ("Symbol %s already defined", name);
1131 }
1132 *p = c;
1133 demand_empty_rest_of_line ();
1134} /* s_lsym() */
1135
1136void
1137s_org ()
1138{
1139 register segT segment;
1140 expressionS exp;
1141 register long temp_fill;
1142 register char *p;
9471a360
KR
1143 /* Don't believe the documentation of BSD 4.2 AS. There is no such
1144 thing as a sub-segment-relative origin. Any absolute origin is
1145 given a warning, then assumed to be segment-relative. Any
1146 segmented origin expression ("foo+42") had better be in the right
1147 segment or the .org is ignored.
1148
1149 BSD 4.2 AS warns if you try to .org backwards. We cannot because
1150 we never know sub-segment sizes when we are reading code. BSD
1151 will crash trying to emit negative numbers of filler bytes in
1152 certain .orgs. We don't crash, but see as-write for that code.
1153
1154 Don't make frag if need_pass_2==1. */
6efd877d
KR
1155 segment = get_known_segmented_expression (&exp);
1156 if (*input_line_pointer == ',')
1157 {
1158 input_line_pointer++;
1159 temp_fill = get_absolute_expression ();
1160 }
1161 else
1162 temp_fill = 0;
1163 if (!need_pass_2)
1164 {
9471a360 1165 if (segment != now_seg && segment != absolute_section)
6efd877d
KR
1166 as_bad ("Invalid segment \"%s\". Segment \"%s\" assumed.",
1167 segment_name (segment), segment_name (now_seg));
1168 p = frag_var (rs_org, 1, 1, (relax_substateT) 0, exp.X_add_symbol,
1169 exp.X_add_number, (char *) 0);
1170 *p = temp_fill;
1171 } /* if (ok to make frag) */
1172 demand_empty_rest_of_line ();
1173} /* s_org() */
1174
1175void
1176s_set ()
1177{
1178 register char *name;
1179 register char delim;
1180 register char *end_name;
1181 register symbolS *symbolP;
1182
1183 /*
c8863a58
KR
1184 * Especial apologies for the random logic:
1185 * this just grew, and could be parsed much more simply!
1186 * Dean in haste.
1187 */
6efd877d
KR
1188 name = input_line_pointer;
1189 delim = get_symbol_end ();
1190 end_name = input_line_pointer;
1191 *end_name = delim;
1192 SKIP_WHITESPACE ();
f8701a3f 1193
6efd877d
KR
1194 if (*input_line_pointer != ',')
1195 {
1196 *end_name = 0;
1197 as_bad ("Expected comma after name \"%s\"", name);
1198 *end_name = delim;
1199 ignore_rest_of_line ();
1200 return;
1201 }
1202
1203 input_line_pointer++;
1204 *end_name = 0;
1205
1206 if (name[0] == '.' && name[1] == '\0')
1207 {
1208 /* Turn '. = mumble' into a .org mumble */
1209 register segT segment;
1210 expressionS exp;
1211 register char *ptr;
1212
1213 segment = get_known_segmented_expression (&exp);
f8701a3f 1214
6efd877d
KR
1215 if (!need_pass_2)
1216 {
9471a360 1217 if (segment != now_seg && segment != absolute_section)
6efd877d
KR
1218 as_bad ("Invalid segment \"%s\". Segment \"%s\" assumed.",
1219 segment_name (segment),
1220 segment_name (now_seg));
1221 ptr = frag_var (rs_org, 1, 1, (relax_substateT) 0, exp.X_add_symbol,
1222 exp.X_add_number, (char *) 0);
1223 *ptr = 0;
1224 } /* if (ok to make frag) */
1225
1226 *end_name = delim;
1227 return;
1228 }
1229
1230 if ((symbolP = symbol_find (name)) == NULL
1231 && (symbolP = md_undefined_symbol (name)) == NULL)
1232 {
9471a360 1233 symbolP = symbol_new (name, undefined_section, 0, &zero_address_frag);
fecd2382 1234#ifdef OBJ_COFF
6efd877d
KR
1235 /* "set" symbols are local unless otherwise specified. */
1236 SF_SET_LOCAL (symbolP);
fecd2382 1237#endif /* OBJ_COFF */
f8701a3f 1238
6efd877d 1239 } /* make a new symbol */
f8701a3f 1240
6efd877d 1241 symbol_table_insert (symbolP);
f8701a3f 1242
6efd877d
KR
1243 *end_name = delim;
1244 pseudo_set (symbolP);
1245 demand_empty_rest_of_line ();
1246} /* s_set() */
fecd2382 1247
6efd877d
KR
1248void
1249s_space (mult)
1250 int mult;
b53ccaac 1251{
6efd877d
KR
1252 long temp_repeat;
1253 register long temp_fill;
1254 register char *p;
1255
1256 /* Just like .fill, but temp_size = 1 */
1257 if (get_absolute_expression_and_terminator (&temp_repeat) == ',')
1258 {
1259 temp_fill = get_absolute_expression ();
1260 }
1261 else
1262 {
1263 input_line_pointer--; /* Backup over what was not a ','. */
1264 temp_fill = 0;
1265 }
1266 if (mult)
1267 {
bf449293 1268 temp_repeat *= mult;
6efd877d
KR
1269 }
1270 if (temp_repeat <= 0)
1271 {
1272 as_warn ("Repeat < 0, .space ignored");
1273 ignore_rest_of_line ();
1274 return;
1275 }
1276 if (!need_pass_2)
1277 {
1278 p = frag_var (rs_fill, 1, 1, (relax_substateT) 0, (symbolS *) 0,
1279 temp_repeat, (char *) 0);
1280 *p = temp_fill;
1281 }
1282 demand_empty_rest_of_line ();
1283} /* s_space() */
fecd2382
RP
1284
1285void
6efd877d 1286s_text ()
fecd2382 1287{
6efd877d 1288 register int temp;
f8701a3f 1289
6efd877d 1290 temp = get_absolute_expression ();
9471a360
KR
1291#ifdef BFD_ASSEMBLER
1292 subseg_set (text_section, (subsegT) temp);
a39116f1 1293#else
9471a360 1294 subseg_new (text_section, (subsegT) temp);
a39116f1 1295#endif
6efd877d
KR
1296 demand_empty_rest_of_line ();
1297} /* s_text() */
fecd2382 1298\f
6efd877d 1299
6efd877d
KR
1300void
1301demand_empty_rest_of_line ()
1302{
1303 SKIP_WHITESPACE ();
1304 if (is_end_of_line[*input_line_pointer])
1305 {
1306 input_line_pointer++;
1307 }
1308 else
1309 {
1310 ignore_rest_of_line ();
1311 }
1312 /* Return having already swallowed end-of-line. */
1313} /* Return pointing just after end-of-line. */
fecd2382
RP
1314
1315void
6efd877d 1316ignore_rest_of_line () /* For suspect lines: gives warning. */
fecd2382 1317{
6efd877d 1318 if (!is_end_of_line[*input_line_pointer])
f8701a3f 1319 {
6efd877d
KR
1320 if (isprint (*input_line_pointer))
1321 as_bad ("Rest of line ignored. First ignored character is `%c'.",
f8701a3f
SC
1322 *input_line_pointer);
1323 else
6efd877d 1324 as_bad ("Rest of line ignored. First ignored character valued 0x%x.",
f8701a3f
SC
1325 *input_line_pointer);
1326 while (input_line_pointer < buffer_limit
6efd877d 1327 && !is_end_of_line[*input_line_pointer])
f8701a3f 1328 {
6efd877d 1329 input_line_pointer++;
f8701a3f
SC
1330 }
1331 }
6efd877d
KR
1332 input_line_pointer++; /* Return pointing just after end-of-line. */
1333 know (is_end_of_line[input_line_pointer[-1]]);
fecd2382
RP
1334}
1335
1336/*
1337 * pseudo_set()
1338 *
1339 * In: Pointer to a symbol.
1340 * Input_line_pointer->expression.
1341 *
1342 * Out: Input_line_pointer->just after any whitespace after expression.
1343 * Tried to set symbol to value of expression.
1344 * Will change symbols type, value, and frag;
1345 * May set need_pass_2 == 1.
1346 */
1347void
f8701a3f 1348pseudo_set (symbolP)
6efd877d 1349 symbolS *symbolP;
fecd2382 1350{
6efd877d
KR
1351 expressionS exp;
1352 register segT segment;
fecd2382 1353#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
f8701a3f 1354 int ext;
fecd2382 1355#endif /* OBJ_AOUT or OBJ_BOUT */
f8701a3f 1356
6efd877d 1357 know (symbolP); /* NULL pointer is logic error. */
fecd2382 1358#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
9471a360 1359 /* @@ Fix this right for BFD. */
6efd877d 1360 ext = S_IS_EXTERNAL (symbolP);
fecd2382 1361#endif /* OBJ_AOUT or OBJ_BOUT */
f8701a3f 1362
9471a360 1363 if ((segment = expression (&exp)) == absent_section)
f8701a3f 1364 {
6efd877d 1365 as_bad ("Missing expression: absolute 0 assumed");
9471a360 1366 exp.X_seg = absolute_section;
6efd877d 1367 exp.X_add_number = 0;
f8701a3f
SC
1368 }
1369
9471a360 1370 if (segment == reg_section)
f8701a3f 1371 {
9471a360 1372 S_SET_SEGMENT (symbolP, reg_section);
6efd877d
KR
1373 S_SET_VALUE (symbolP, exp.X_add_number);
1374 symbolP->sy_frag = &zero_address_frag;
9471a360
KR
1375 }
1376 else if (segment == big_section)
1377 {
6efd877d
KR
1378 as_bad ("%s number invalid. Absolute 0 assumed.",
1379 exp.X_add_number > 0 ? "Bignum" : "Floating-Point");
9471a360 1380 S_SET_SEGMENT (symbolP, absolute_section);
fecd2382 1381#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
9471a360 1382 /* @@ Fix this right for BFD. */
6efd877d
KR
1383 ext ? S_SET_EXTERNAL (symbolP) :
1384 S_CLEAR_EXTERNAL (symbolP);
fecd2382 1385#endif /* OBJ_AOUT or OBJ_BOUT */
6efd877d
KR
1386 S_SET_VALUE (symbolP, 0);
1387 symbolP->sy_frag = &zero_address_frag;
9471a360
KR
1388 }
1389 else if (segment == absent_section)
1390 {
6efd877d 1391 as_warn ("No expression: Using absolute 0");
9471a360 1392 S_SET_SEGMENT (symbolP, absolute_section);
fecd2382 1393#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
9471a360 1394 /* @@ Fix this right for BFD. */
6efd877d
KR
1395 ext ? S_SET_EXTERNAL (symbolP) :
1396 S_CLEAR_EXTERNAL (symbolP);
fecd2382 1397#endif /* OBJ_AOUT or OBJ_BOUT */
6efd877d
KR
1398 S_SET_VALUE (symbolP, 0);
1399 symbolP->sy_frag = &zero_address_frag;
9471a360
KR
1400 }
1401 else if (segment == diff_section)
1402 {
f8701a3f 1403 if (exp.X_add_symbol && exp.X_subtract_symbol
6efd877d
KR
1404 && (S_GET_SEGMENT (exp.X_add_symbol) ==
1405 S_GET_SEGMENT (exp.X_subtract_symbol)))
1406 {
1407 if (exp.X_add_symbol->sy_frag != exp.X_subtract_symbol->sy_frag)
1408 {
1409 as_bad ("Unknown expression: symbols %s and %s are in different frags.",
1410 S_GET_NAME (exp.X_add_symbol), S_GET_NAME (exp.X_subtract_symbol));
1411 need_pass_2++;
1412 }
1413 exp.X_add_number += S_GET_VALUE (exp.X_add_symbol) -
1414 S_GET_VALUE (exp.X_subtract_symbol);
f8701a3f 1415 }
6efd877d
KR
1416 else
1417 as_bad ("Complex expression. Absolute segment assumed.");
9471a360
KR
1418 goto abs;
1419 }
1420 else if (segment == absolute_section)
1421 {
1422 abs:
1423 S_SET_SEGMENT (symbolP, absolute_section);
fecd2382 1424#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
9471a360 1425 /* @@ Fix this right for BFD. */
6efd877d
KR
1426 ext ? S_SET_EXTERNAL (symbolP) :
1427 S_CLEAR_EXTERNAL (symbolP);
fecd2382 1428#endif /* OBJ_AOUT or OBJ_BOUT */
6efd877d
KR
1429 S_SET_VALUE (symbolP, exp.X_add_number);
1430 symbolP->sy_frag = &zero_address_frag;
9471a360
KR
1431 }
1432 else if (segment == pass1_section)
1433 {
1434 symbolP->sy_forward = exp.X_add_symbol;
1435 as_bad ("Unknown expression");
1436 know (need_pass_2 == 1);
1437 }
1438 else if (segment == undefined_section)
1439 {
1440 symbolP->sy_forward = exp.X_add_symbol;
1441 }
1442 else
1443 {
1444#ifndef BFD_ASSEMBLER
1445#ifndef MANY_SEGMENTS
6efd877d
KR
1446 switch (segment)
1447 {
1448 case SEG_DATA:
6efd877d 1449 case SEG_TEXT:
6efd877d 1450 case SEG_BSS:
6efd877d 1451 break;
f8701a3f 1452
6efd877d
KR
1453 default:
1454 as_fatal ("failed sanity check.");
1455 } /* switch on segment */
a39116f1 1456#endif
9471a360
KR
1457#endif
1458 S_SET_SEGMENT (symbolP, segment);
fecd2382 1459#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
9471a360 1460 /* @@ Fix this right for BFD! */
6efd877d
KR
1461 if (ext)
1462 {
1463 S_SET_EXTERNAL (symbolP);
1464 }
1465 else
1466 {
1467 S_CLEAR_EXTERNAL (symbolP);
1468 } /* if external */
fecd2382 1469#endif /* OBJ_AOUT or OBJ_BOUT */
f8701a3f 1470
6efd877d
KR
1471 S_SET_VALUE (symbolP, exp.X_add_number + S_GET_VALUE (exp.X_add_symbol));
1472 symbolP->sy_frag = exp.X_add_symbol->sy_frag;
f8701a3f 1473 }
fecd2382
RP
1474}
1475\f
1476/*
1477 * cons()
1478 *
1479 * CONStruct more frag of .bytes, or .words etc.
1480 * Should need_pass_2 be 1 then emit no frag(s).
1481 * This understands EXPRESSIONS, as opposed to big_cons().
1482 *
1483 * Bug (?)
1484 *
1485 * This has a split personality. We use expression() to read the
1486 * value. We can detect if the value won't fit in a byte or word.
1487 * But we can't detect if expression() discarded significant digits
1488 * in the case of a long. Not worth the crocks required to fix it.
1489 */
1490
6efd877d
KR
1491/* worker to do .byte etc statements */
1492/* clobbers input_line_pointer, checks */
1493/* end-of-line. */
1494void
1495cons (nbytes)
1496 register unsigned int nbytes; /* 1=.byte, 2=.word, 4=.long */
fecd2382 1497{
f8701a3f 1498 register char c;
6efd877d 1499 register long mask; /* High-order bits we will left-truncate, */
f8701a3f 1500 /* but includes sign bit also. */
6efd877d
KR
1501 register long get; /* what we get */
1502 register long use; /* get after truncation. */
1503 register long unmask; /* what bits we will store */
1504 register char *p;
1505 register segT segment;
1506 expressionS exp;
f8701a3f
SC
1507
1508 /*
1509 * Input_line_pointer->1st char after pseudo-op-code and could legally
1510 * be a end-of-line. (Or, less legally an eof - which we cope with.)
1511 */
1512 /* JF << of >= number of bits in the object is undefined. In particular
1513 SPARC (Sun 4) has problems */
1514
6efd877d
KR
1515 if (nbytes >= sizeof (long))
1516 {
f8701a3f 1517 mask = 0;
6efd877d
KR
1518 }
1519 else
1520 {
1521 mask = ~0 << (BITS_PER_CHAR * nbytes); /* Don't store these bits. */
1522 } /* bigger than a long */
f8701a3f 1523
6efd877d 1524 unmask = ~mask; /* Do store these bits. */
f8701a3f 1525
fecd2382 1526#ifdef NEVER
f8701a3f 1527 "Do this mod if you want every overflow check to assume SIGNED 2's complement data.";
6efd877d 1528 mask = ~(unmask >> 1); /* Includes sign bit now. */
fecd2382 1529#endif
f8701a3f
SC
1530
1531 /*
1532 * The following awkward logic is to parse ZERO or more expressions,
1533 * comma seperated. Recall an expression includes its leading &
1534 * trailing blanks. We fake a leading ',' if there is (supposed to
1535 * be) a 1st expression, and keep demanding 1 expression for each ','.
1536 */
6efd877d
KR
1537 if (is_it_end_of_statement ())
1538 {
1539 c = 0; /* Skip loop. */
1540 input_line_pointer++; /* Matches end-of-loop 'correction'. */
1541 }
1542 else
1543 {
1544 c = ',';
1545 } /* if the end else fake it */
f8701a3f
SC
1546
1547 /* Do loop. */
6efd877d
KR
1548 while (c == ',')
1549 {
fecd2382 1550#ifdef WANT_BITFIELDS
f8701a3f
SC
1551 unsigned int bits_available = BITS_PER_CHAR * nbytes;
1552 /* used for error messages and rescanning */
1553 char *hold = input_line_pointer;
fecd2382 1554#endif /* WANT_BITFIELDS */
f8701a3f 1555#ifdef MRI
6efd877d
KR
1556 if (*input_line_pointer == '\'')
1557 {
1558 /* An MRI style string, cut into as many bytes as will fit
f8701a3f
SC
1559 into a nbyte chunk, left justify if necessary, and sepatate
1560 with commas so we can try again later */
6efd877d
KR
1561 int scan = 0;
1562 unsigned int result = 0;
1563 input_line_pointer++;
1564 for (scan = 0; scan < nbytes; scan++)
f8701a3f 1565 {
6efd877d
KR
1566 if (*input_line_pointer == '\'')
1567 {
1568 if (input_line_pointer[1] == '\'')
1569 {
1570 input_line_pointer++;
1571 }
1572 else
1573 break;
1574 }
1575 result = (result << 8) | (*input_line_pointer++);
f8701a3f 1576 }
6efd877d
KR
1577
1578 /* Left justify */
1579 while (scan < nbytes)
1580 {
1581 result <<= 8;
1582 scan++;
1583 }
1584 /* Create correct expression */
1585 exp.X_add_symbol = 0;
1586 exp.X_add_number = result;
9471a360 1587 exp.X_seg = segment = absolute_section;
6efd877d
KR
1588 /* Fake it so that we can read the next char too */
1589 if (input_line_pointer[0] != '\'' ||
1590 (input_line_pointer[0] == '\'' && input_line_pointer[1] == '\''))
1591 {
1592 input_line_pointer -= 2;
1593 input_line_pointer[0] = ',';
1594 input_line_pointer[1] = '\'';
1595 }
1596 else
1597 input_line_pointer++;
1598
f8701a3f 1599 }
6efd877d 1600 else
f8701a3f 1601#endif
6efd877d
KR
1602 /* At least scan over the expression. */
1603 segment = expression (&exp);
f8701a3f 1604
a39116f1 1605#ifdef WANT_BITFIELDS
f8701a3f
SC
1606 /* Some other assemblers, (eg, asm960), allow
1607 bitfields after ".byte" as w:x,y:z, where w and
1608 y are bitwidths and x and y are values. They
1609 then pack them all together. We do a little
1610 better in that we allow them in words, longs,
1611 etc. and we'll pack them in target byte order
1612 for you.
6efd877d 1613
f8701a3f
SC
1614 The rules are: pack least significat bit first,
1615 if a field doesn't entirely fit, put it in the
1616 next unit. Overflowing the bitfield is
1617 explicitly *not* even a warning. The bitwidth
1618 should be considered a "mask".
6efd877d 1619
f8701a3f
SC
1620 FIXME-SOMEDAY: If this is considered generally
1621 useful, this logic should probably be reworked.
1622 xoxorich. */
1623
6efd877d
KR
1624 if (*input_line_pointer == ':')
1625 { /* bitfields */
f8701a3f
SC
1626 long value = 0;
1627
6efd877d
KR
1628 for (;;)
1629 {
f8701a3f 1630 unsigned long width;
6efd877d
KR
1631
1632 if (*input_line_pointer != ':')
1633 {
f8701a3f
SC
1634 input_line_pointer = hold;
1635 break;
6efd877d
KR
1636 } /* next piece is not a bitfield */
1637
f8701a3f
SC
1638 /* In the general case, we can't allow
1639 full expressions with symbol
1640 differences and such. The relocation
1641 entries for symbols not defined in this
1642 assembly would require arbitrary field
1643 widths, positions, and masks which most
1644 of our current object formats don't
1645 support.
6efd877d 1646
f8701a3f
SC
1647 In the specific case where a symbol
1648 *is* defined in this assembly, we
1649 *could* build fixups and track it, but
1650 this could lead to confusion for the
1651 backends. I'm lazy. I'll take any
1652 SEG_ABSOLUTE. I think that means that
1653 you can use a previous .set or
1654 .equ type symbol. xoxorich. */
6efd877d 1655
9471a360 1656 if (segment == absent_section)
6efd877d
KR
1657 {
1658 as_warn ("Using a bit field width of zero.");
f8701a3f 1659 exp.X_add_number = 0;
9471a360 1660 segment = absolute_section;
6efd877d
KR
1661 } /* implied zero width bitfield */
1662
9471a360 1663 if (segment != absolute_section)
6efd877d 1664 {
f8701a3f 1665 *input_line_pointer = '\0';
6efd877d 1666 as_bad ("Field width \"%s\" too complex for a bitfield.\n", hold);
f8701a3f 1667 *input_line_pointer = ':';
6efd877d 1668 demand_empty_rest_of_line ();
f8701a3f 1669 return;
6efd877d
KR
1670 } /* too complex */
1671
1672 if ((width = exp.X_add_number) > (BITS_PER_CHAR * nbytes))
1673 {
1674 as_warn ("Field width %d too big to fit in %d bytes: truncated to %d bits.",
1675 width, nbytes, (BITS_PER_CHAR * nbytes));
f8701a3f 1676 width = BITS_PER_CHAR * nbytes;
6efd877d
KR
1677 } /* too big */
1678
1679 if (width > bits_available)
1680 {
f8701a3f
SC
1681 /* FIXME-SOMEDAY: backing up and
1682 reparsing is wasteful */
1683 input_line_pointer = hold;
1684 exp.X_add_number = value;
1685 break;
6efd877d
KR
1686 } /* won't fit */
1687
1688 hold = ++input_line_pointer; /* skip ':' */
1689
9471a360 1690 if ((segment = expression (&exp)) != absolute_section)
6efd877d 1691 {
f8701a3f 1692 char cache = *input_line_pointer;
6efd877d 1693
f8701a3f 1694 *input_line_pointer = '\0';
6efd877d 1695 as_bad ("Field value \"%s\" too complex for a bitfield.\n", hold);
f8701a3f 1696 *input_line_pointer = cache;
6efd877d 1697 demand_empty_rest_of_line ();
f8701a3f 1698 return;
6efd877d
KR
1699 } /* too complex */
1700
f8701a3f 1701 value |= (~(-1 << width) & exp.X_add_number)
6efd877d
KR
1702 << ((BITS_PER_CHAR * nbytes) - bits_available);
1703
f8701a3f 1704 if ((bits_available -= width) == 0
6efd877d
KR
1705 || is_it_end_of_statement ()
1706 || *input_line_pointer != ',')
1707 {
f8701a3f 1708 break;
6efd877d 1709 } /* all the bitfields we're gonna get */
f8701a3f
SC
1710
1711 hold = ++input_line_pointer;
6efd877d
KR
1712 segment = expression (&exp);
1713 } /* forever loop */
f8701a3f
SC
1714
1715 exp.X_add_number = value;
9471a360 1716 segment = absolute_section;
6efd877d 1717 } /* if looks like a bitfield */
a39116f1 1718#endif /* WANT_BITFIELDS */
f8701a3f 1719
6efd877d
KR
1720 if (!need_pass_2)
1721 { /* Still worthwhile making frags. */
f8701a3f
SC
1722
1723 /* Don't call this if we are going to junk this pass anyway! */
9471a360 1724 know (segment != pass1_section);
f8701a3f 1725
9471a360 1726 if (segment == diff_section && exp.X_add_symbol == NULL)
6efd877d
KR
1727 {
1728 as_bad ("Subtracting symbol \"%s\"(segment\"%s\") is too hard. Absolute segment assumed.",
1729 S_GET_NAME (exp.X_subtract_symbol),
1730 segment_name (S_GET_SEGMENT (exp.X_subtract_symbol)));
9471a360 1731 segment = absolute_section;
f8701a3f
SC
1732 /* Leave exp . X_add_number alone. */
1733 }
6efd877d 1734 p = frag_more (nbytes);
9471a360 1735 if (segment == big_section)
6efd877d 1736 {
6efd877d
KR
1737 as_bad ("%s number invalid. Absolute 0 assumed.",
1738 exp.X_add_number > 0 ? "Bignum" : "Floating-Point");
1739 md_number_to_chars (p, (long) 0, nbytes);
9471a360
KR
1740 }
1741 else if (segment == absent_section)
1742 {
6efd877d
KR
1743 as_warn ("0 assumed for missing expression");
1744 exp.X_add_number = 0;
1745 know (exp.X_add_symbol == NULL);
9471a360
KR
1746 goto abs_sec;
1747 }
1748 else if (segment == absolute_section)
1749 {
1750 abs_sec:
6efd877d 1751 get = exp.X_add_number;
f8701a3f
SC
1752 use = get & unmask;
1753 if ((get & mask) && (get & mask) != mask)
6efd877d
KR
1754 { /* Leading bits contain both 0s & 1s. */
1755 as_warn ("Value 0x%x truncated to 0x%x.", get, use);
1756 }
1757 md_number_to_chars (p, use, nbytes); /* put bytes in right order. */
9471a360
KR
1758 }
1759 else if (segment == diff_section)
1760 {
fecd2382 1761#ifndef WORKING_DOT_WORD
6efd877d
KR
1762 if (nbytes == 2)
1763 {
f8701a3f
SC
1764 struct broken_word *x;
1765
6efd877d
KR
1766 x = (struct broken_word *) xmalloc (sizeof (struct broken_word));
1767 x->next_broken_word = broken_words;
1768 broken_words = x;
1769 x->frag = frag_now;
1770 x->word_goes_here = p;
1771 x->dispfrag = 0;
1772 x->add = exp.X_add_symbol;
1773 x->sub = exp.X_subtract_symbol;
1774 x->addnum = exp.X_add_number;
1775 x->added = 0;
f8701a3f 1776 new_broken_words++;
9471a360 1777 goto after_switch;
f8701a3f 1778 }
fecd2382 1779#endif
9471a360
KR
1780 goto defalt;
1781 }
1782 else
1783 /* undefined_section, others */
1784 {
1785 defalt:
1786#ifdef BFD_ASSEMBLER
1787 fix_new (frag_now, p - frag_now->fr_literal, nbytes,
1788 exp.X_add_symbol, exp.X_subtract_symbol,
1789 exp.X_add_number, 0,
1790 /* @@ Should look at CPU word size. */
1791 BFD_RELOC_32);
1792#else
fecd2382 1793#ifdef TC_NS32K
f8701a3f 1794 fix_new_ns32k (frag_now, p - frag_now->fr_literal, nbytes,
6efd877d
KR
1795 exp.X_add_symbol, exp.X_subtract_symbol,
1796 exp.X_add_number, 0, 0, 2, 0, 0);
fecd2382 1797#else
9471a360 1798#if defined(TC_SPARC) || defined(TC_A29K)
f8701a3f 1799 fix_new (frag_now, p - frag_now->fr_literal, nbytes,
6efd877d
KR
1800 exp.X_add_symbol, exp.X_subtract_symbol,
1801 exp.X_add_number, 0, RELOC_32);
9471a360
KR
1802#else
1803#if defined(TC_H8300)
f8701a3f 1804 fix_new (frag_now, p - frag_now->fr_literal, nbytes,
6efd877d
KR
1805 exp.X_add_symbol, exp.X_subtract_symbol,
1806 exp.X_add_number, 0, R_RELWORD);
f8701a3f 1807
9471a360 1808#else
6efd877d 1809#ifdef NO_RELOC
f8701a3f 1810 fix_new (frag_now, p - frag_now->fr_literal, nbytes,
6efd877d
KR
1811 exp.X_add_symbol, exp.X_subtract_symbol,
1812 exp.X_add_number, 0, NO_RELOC);
1813#else
1814 fix_new (frag_now, p - frag_now->fr_literal, nbytes,
1815 exp.X_add_symbol, exp.X_subtract_symbol,
1816 exp.X_add_number, 0, 0);
1817#endif /* NO_RELOC */
9471a360
KR
1818#endif /* tc_h8300 */
1819#endif /* tc_sparc|tc_a29k */
fecd2382 1820#endif /* TC_NS32K */
9471a360 1821#endif /* BFD_ASSEMBLER */
6efd877d 1822 } /* switch(segment) */
9471a360
KR
1823 after_switch:
1824 ;
6efd877d 1825 } /* if (!need_pass_2) */
f8701a3f 1826 c = *input_line_pointer++;
6efd877d
KR
1827 } /* while(c==',') */
1828 input_line_pointer--; /* Put terminator back into stream. */
1829 demand_empty_rest_of_line ();
1830} /* cons() */
fecd2382
RP
1831\f
1832/*
1833 * big_cons()
1834 *
1835 * CONStruct more frag(s) of .quads, or .octa etc.
1836 * Makes 0 or more new frags.
1837 * If need_pass_2 == 1, generate no frag.
1838 * This understands only bignums, not expressions. Cons() understands
1839 * expressions.
1840 *
1841 * Constants recognised are '0...'(octal) '0x...'(hex) '...'(decimal).
1842 *
1843 * This creates objects with struct obstack_control objs, destroying
1844 * any context objs held about a partially completed object. Beware!
1845 *
1846 *
1847 * I think it sucks to have 2 different types of integers, with 2
1848 * routines to read them, store them etc.
1849 * It would be nicer to permit bignums in expressions and only
1850 * complain if the result overflowed. However, due to "efficiency"...
1851 */
1852/* worker to do .quad etc statements */
1853/* clobbers input_line_pointer, checks */
1854/* end-of-line. */
1855/* 8=.quad 16=.octa ... */
1856
6efd877d
KR
1857void
1858big_cons (nbytes)
f8701a3f 1859 register int nbytes;
fecd2382 1860{
6efd877d 1861 register char c; /* input_line_pointer->c. */
f8701a3f 1862 register int radix;
6efd877d
KR
1863 register long length; /* Number of chars in an object. */
1864 register int digit; /* Value of 1 digit. */
1865 register int carry; /* For multi-precision arithmetic. */
1866 register int work; /* For multi-precision arithmetic. */
1867 register char *p; /* For multi-precision arithmetic. */
f8701a3f 1868
9471a360 1869 extern const char hex_value[]; /* In hex_value.c. */
f8701a3f
SC
1870
1871 /*
1872 * The following awkward logic is to parse ZERO or more strings,
1873 * comma seperated. Recall an expression includes its leading &
1874 * trailing blanks. We fake a leading ',' if there is (supposed to
1875 * be) a 1st expression, and keep demanding 1 expression for each ','.
1876 */
6efd877d 1877 if (is_it_end_of_statement ())
f8701a3f
SC
1878 {
1879 c = 0; /* Skip loop. */
1880 }
1881 else
1882 {
1883 c = ','; /* Do loop. */
6efd877d 1884 --input_line_pointer;
f8701a3f
SC
1885 }
1886 while (c == ',')
1887 {
6efd877d
KR
1888 ++input_line_pointer;
1889 SKIP_WHITESPACE ();
1890 c = *input_line_pointer;
f8701a3f
SC
1891 /* C contains 1st non-blank character of what we hope is a number. */
1892 if (c == '0')
1893 {
6efd877d
KR
1894 c = *++input_line_pointer;
1895 if (c == 'x' || c == 'X')
fecd2382 1896 {
6efd877d 1897 c = *++input_line_pointer;
f8701a3f 1898 radix = 16;
fecd2382 1899 }
f8701a3f 1900 else
fecd2382 1901 {
f8701a3f 1902 radix = 8;
fecd2382 1903 }
f8701a3f
SC
1904 }
1905 else
1906 {
1907 radix = 10;
1908 }
1909 /*
1910 * This feature (?) is here to stop people worrying about
1911 * mysterious zero constants: which is what they get when
1912 * they completely omit digits.
1913 */
6efd877d
KR
1914 if (hex_value[c] >= radix)
1915 {
1916 as_bad ("Missing digits. 0 assumed.");
1917 }
1918 bignum_high = bignum_low - 1; /* Start constant with 0 chars. */
1919 for (; (digit = hex_value[c]) < radix; c = *++input_line_pointer)
f8701a3f
SC
1920 {
1921 /* Multiply existing number by radix, then add digit. */
1922 carry = digit;
6efd877d 1923 for (p = bignum_low; p <= bignum_high; p++)
fecd2382 1924 {
f8701a3f
SC
1925 work = (*p & MASK_CHAR) * radix + carry;
1926 *p = work & MASK_CHAR;
1927 carry = work >> BITS_PER_CHAR;
fecd2382 1928 }
f8701a3f
SC
1929 if (carry)
1930 {
6efd877d
KR
1931 grow_bignum ();
1932 *bignum_high = carry & MASK_CHAR;
1933 know ((carry & ~MASK_CHAR) == 0);
f8701a3f
SC
1934 }
1935 }
1936 length = bignum_high - bignum_low + 1;
1937 if (length > nbytes)
1938 {
6efd877d 1939 as_warn ("Most significant bits truncated in integer constant.");
f8701a3f
SC
1940 }
1941 else
1942 {
1943 register long leading_zeroes;
fecd2382 1944
6efd877d
KR
1945 for (leading_zeroes = nbytes - length;
1946 leading_zeroes;
1947 leading_zeroes--)
a39116f1 1948 {
6efd877d
KR
1949 grow_bignum ();
1950 *bignum_high = 0;
a39116f1 1951 }
f8701a3f 1952 }
6efd877d 1953 if (!need_pass_2)
f8701a3f
SC
1954 {
1955 p = frag_more (nbytes);
6efd877d 1956 bcopy (bignum_low, p, (int) nbytes);
f8701a3f
SC
1957 }
1958 /* C contains character after number. */
6efd877d
KR
1959 SKIP_WHITESPACE ();
1960 c = *input_line_pointer;
f8701a3f
SC
1961 /* C contains 1st non-blank character after number. */
1962 }
6efd877d
KR
1963 demand_empty_rest_of_line ();
1964} /* big_cons() */
f8701a3f 1965
6efd877d
KR
1966/* Extend bignum by 1 char. */
1967static void
1968grow_bignum ()
1969{
f8701a3f
SC
1970 register long length;
1971
6efd877d 1972 bignum_high++;
f8701a3f
SC
1973 if (bignum_high >= bignum_limit)
1974 {
1975 length = bignum_limit - bignum_low;
6efd877d 1976 bignum_low = xrealloc (bignum_low, length + length);
f8701a3f
SC
1977 bignum_high = bignum_low + length;
1978 bignum_limit = bignum_low + length + length;
1979 }
6efd877d 1980} /* grow_bignum(); */
fecd2382
RP
1981\f
1982/*
1983 * float_cons()
1984 *
1985 * CONStruct some more frag chars of .floats .ffloats etc.
1986 * Makes 0 or more new frags.
1987 * If need_pass_2 == 1, no frags are emitted.
1988 * This understands only floating literals, not expressions. Sorry.
1989 *
1990 * A floating constant is defined by atof_generic(), except it is preceded
1991 * by 0d 0f 0g or 0h. After observing the STRANGE way my BSD AS does its
1992 * reading, I decided to be incompatible. This always tries to give you
1993 * rounded bits to the precision of the pseudo-op. Former AS did premature
1994 * truncatation, restored noisy bits instead of trailing 0s AND gave you
1995 * a choice of 2 flavours of noise according to which of 2 floating-point
1996 * scanners you directed AS to use.
1997 *
1998 * In: input_line_pointer->whitespace before, or '0' of flonum.
1999 *
2000 */
2001
6efd877d
KR
2002void /* JF was static, but can't be if VAX.C is goning to use it */
2003float_cons (float_type) /* Worker to do .float etc statements. */
2004 /* Clobbers input_line-pointer, checks end-of-line. */
f8701a3f 2005 register int float_type; /* 'f':.ffloat ... 'F':.float ... */
fecd2382 2006{
6efd877d 2007 register char *p;
f8701a3f 2008 register char c;
6efd877d
KR
2009 int length; /* Number of chars in an object. */
2010 register char *err; /* Error from scanning floating literal. */
2011 char temp[MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT];
f8701a3f
SC
2012
2013 /*
2014 * The following awkward logic is to parse ZERO or more strings,
2015 * comma seperated. Recall an expression includes its leading &
2016 * trailing blanks. We fake a leading ',' if there is (supposed to
2017 * be) a 1st expression, and keep demanding 1 expression for each ','.
2018 */
6efd877d 2019 if (is_it_end_of_statement ())
f8701a3f
SC
2020 {
2021 c = 0; /* Skip loop. */
6efd877d 2022 ++input_line_pointer; /*->past termintor. */
f8701a3f
SC
2023 }
2024 else
2025 {
2026 c = ','; /* Do loop. */
2027 }
2028 while (c == ',')
2029 {
2030 /* input_line_pointer->1st char of a flonum (we hope!). */
6efd877d 2031 SKIP_WHITESPACE ();
f8701a3f
SC
2032 /* Skip any 0{letter} that may be present. Don't even check if the
2033 * letter is legal. Someone may invent a "z" format and this routine
2034 * has no use for such information. Lusers beware: you get
2035 * diagnostics if your input is ill-conditioned.
2036 */
2037
6efd877d
KR
2038 if (input_line_pointer[0] == '0' && isalpha (input_line_pointer[1]))
2039 input_line_pointer += 2;
f8701a3f
SC
2040
2041 err = md_atof (float_type, temp, &length);
6efd877d
KR
2042 know (length <= MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT);
2043 know (length > 0);
2044 if (*err)
f8701a3f 2045 {
6efd877d
KR
2046 as_bad ("Bad floating literal: %s", err);
2047 ignore_rest_of_line ();
f8701a3f
SC
2048 /* Input_line_pointer->just after end-of-line. */
2049 c = 0; /* Break out of loop. */
2050 }
2051 else
2052 {
6efd877d 2053 if (!need_pass_2)
a39116f1 2054 {
f8701a3f
SC
2055 p = frag_more (length);
2056 bcopy (temp, p, length);
a39116f1 2057 }
6efd877d
KR
2058 SKIP_WHITESPACE ();
2059 c = *input_line_pointer++;
f8701a3f
SC
2060 /* C contains 1st non-white character after number. */
2061 /* input_line_pointer->just after terminator (c). */
542e1629 2062 }
f8701a3f 2063 }
6efd877d
KR
2064 --input_line_pointer; /*->terminator (is not ','). */
2065 demand_empty_rest_of_line ();
f8701a3f 2066} /* float_cons() */
fecd2382
RP
2067\f
2068/*
2069 * stringer()
2070 *
2071 * We read 0 or more ',' seperated, double-quoted strings.
2072 *
2073 * Caller should have checked need_pass_2 is FALSE because we don't check it.
2074 */
a39116f1
RP
2075
2076
6efd877d
KR
2077void
2078stringer (append_zero) /* Worker to do .ascii etc statements. */
2079 /* Checks end-of-line. */
f8701a3f 2080 register int append_zero; /* 0: don't append '\0', else 1 */
fecd2382 2081{
f8701a3f 2082 register unsigned int c;
6efd877d 2083
f8701a3f
SC
2084 /*
2085 * The following awkward logic is to parse ZERO or more strings,
2086 * comma seperated. Recall a string expression includes spaces
2087 * before the opening '\"' and spaces after the closing '\"'.
2088 * We fake a leading ',' if there is (supposed to be)
2089 * a 1st, expression. We keep demanding expressions for each
2090 * ','.
2091 */
6efd877d
KR
2092 if (is_it_end_of_statement ())
2093 {
2094 c = 0; /* Skip loop. */
2095 ++input_line_pointer; /* Compensate for end of loop. */
2096 }
f8701a3f 2097 else
6efd877d
KR
2098 {
2099 c = ','; /* Do loop. */
2100 }
2101 while (c == ',' || c == '<' || c == '"')
2102 {
2103 SKIP_WHITESPACE ();
2104 switch (*input_line_pointer)
2105 {
2106 case '\"':
2107 ++input_line_pointer; /*->1st char of string. */
2108 while (is_a_char (c = next_char_of_string ()))
2109 {
2110 FRAG_APPEND_1_CHAR (c);
2111 }
2112 if (append_zero)
2113 {
2114 FRAG_APPEND_1_CHAR (0);
2115 }
2116 know (input_line_pointer[-1] == '\"');
2117 break;
2118 case '<':
2119 input_line_pointer++;
2120 c = get_single_number ();
2121 FRAG_APPEND_1_CHAR (c);
2122 if (*input_line_pointer != '>')
2123 {
2124 as_bad ("Expected <nn>");
2125 }
2126 input_line_pointer++;
2127 break;
2128 case ',':
2129 input_line_pointer++;
2130 break;
2131 }
2132 SKIP_WHITESPACE ();
2133 c = *input_line_pointer;
f8701a3f 2134 }
f8701a3f 2135
6efd877d
KR
2136 demand_empty_rest_of_line ();
2137} /* stringer() */
fecd2382 2138\f
6efd877d 2139/* FIXME-SOMEDAY: I had trouble here on characters with the
f8701a3f
SC
2140 high bits set. We'll probably also have trouble with
2141 multibyte chars, wide chars, etc. Also be careful about
2142 returning values bigger than 1 byte. xoxorich. */
fecd2382 2143
6efd877d
KR
2144unsigned int
2145next_char_of_string ()
2146{
2147 register unsigned int c;
2148
2149 c = *input_line_pointer++ & CHAR_MASK;
2150 switch (c)
2151 {
2152 case '\"':
2153 c = NOT_A_CHAR;
2154 break;
2155
2156 case '\\':
2157 switch (c = *input_line_pointer++)
2158 {
2159 case 'b':
2160 c = '\b';
2161 break;
2162
2163 case 'f':
2164 c = '\f';
2165 break;
2166
2167 case 'n':
2168 c = '\n';
2169 break;
2170
2171 case 'r':
2172 c = '\r';
2173 break;
2174
2175 case 't':
2176 c = '\t';
2177 break;
2178
fecd2382 2179#ifdef BACKSLASH_V
6efd877d
KR
2180 case 'v':
2181 c = '\013';
2182 break;
fecd2382 2183#endif
6efd877d
KR
2184
2185 case '\\':
2186 case '"':
2187 break; /* As itself. */
2188
2189 case '0':
2190 case '1':
2191 case '2':
2192 case '3':
2193 case '4':
2194 case '5':
2195 case '6':
2196 case '7':
2197 case '8':
2198 case '9':
2199 {
2200 long number;
2201
2202 for (number = 0; isdigit (c); c = *input_line_pointer++)
2203 {
2204 number = number * 8 + c - '0';
2205 }
2206 c = number & 0xff;
2207 }
2208 --input_line_pointer;
2209 break;
2210
2211 case '\n':
2212 /* To be compatible with BSD 4.2 as: give the luser a linefeed!! */
2213 as_warn ("Unterminated string: Newline inserted.");
2214 c = '\n';
2215 break;
2216
2217 default:
2218
fecd2382 2219#ifdef ONLY_STANDARD_ESCAPES
6efd877d
KR
2220 as_bad ("Bad escaped character in string, '?' assumed");
2221 c = '?';
fecd2382 2222#endif /* ONLY_STANDARD_ESCAPES */
6efd877d
KR
2223
2224 break;
2225 } /* switch on escaped char */
2226 break;
2227
2228 default:
2229 break;
2230 } /* switch on char */
2231 return (c);
2232} /* next_char_of_string() */
fecd2382
RP
2233\f
2234static segT
f8701a3f 2235get_segmented_expression (expP)
6efd877d 2236 register expressionS *expP;
fecd2382 2237{
6efd877d 2238 register segT retval;
f8701a3f 2239
9471a360
KR
2240 retval = expression (expP);
2241 if (retval == pass1_section
2242 || retval == absent_section
2243 || retval == big_section)
f8701a3f 2244 {
6efd877d 2245 as_bad ("Expected address expression: absolute 0 assumed");
9471a360 2246 retval = expP->X_seg = absolute_section;
6efd877d
KR
2247 expP->X_add_number = 0;
2248 expP->X_add_symbol = expP->X_subtract_symbol = 0;
f8701a3f
SC
2249 }
2250 return (retval); /* SEG_ ABSOLUTE,UNKNOWN,DATA,TEXT,BSS */
fecd2382
RP
2251}
2252
6efd877d
KR
2253static segT
2254get_known_segmented_expression (expP)
2255 register expressionS *expP;
fecd2382 2256{
6efd877d 2257 register segT retval;
9471a360
KR
2258 register CONST char *name1;
2259 register CONST char *name2;
f8701a3f 2260
9471a360 2261 if ((retval = get_segmented_expression (expP)) == undefined_section)
f8701a3f 2262 {
6efd877d 2263 name1 = expP->X_add_symbol ? S_GET_NAME (expP->X_add_symbol) : "";
f8701a3f 2264 name2 = expP->X_subtract_symbol ?
6efd877d
KR
2265 S_GET_NAME (expP->X_subtract_symbol) :
2266 "";
f8701a3f
SC
2267 if (name1 && name2)
2268 {
6efd877d
KR
2269 as_warn ("Symbols \"%s\" \"%s\" are undefined: absolute 0 assumed.",
2270 name1, name2);
f8701a3f
SC
2271 }
2272 else
2273 {
6efd877d
KR
2274 as_warn ("Symbol \"%s\" undefined: absolute 0 assumed.",
2275 name1 ? name1 : name2);
f8701a3f 2276 }
9471a360 2277 retval = expP->X_seg = absolute_section;
6efd877d
KR
2278 expP->X_add_number = 0;
2279 expP->X_add_symbol = expP->X_subtract_symbol = NULL;
f8701a3f 2280 }
9471a360
KR
2281 know (retval == absolute_section
2282 || retval == diff_section
2283 || SEG_NORMAL (retval));
f8701a3f
SC
2284 return (retval);
2285
fecd2382
RP
2286} /* get_known_segmented_expression() */
2287
2288
2289
6efd877d 2290/* static */ long /* JF was static, but can't be if the MD pseudos are to use it */
f8701a3f 2291get_absolute_expression ()
fecd2382 2292{
6efd877d 2293 expressionS exp;
f8701a3f
SC
2294 register segT s;
2295
9471a360 2296 if ((s = expression (&exp)) != absolute_section)
f8701a3f 2297 {
9471a360 2298 if (s != absent_section)
f8701a3f 2299 {
6efd877d 2300 as_bad ("Bad Absolute Expression, absolute 0 assumed.");
f8701a3f 2301 }
6efd877d 2302 exp.X_add_number = 0;
f8701a3f 2303 }
6efd877d 2304 return (exp.X_add_number);
fecd2382
RP
2305}
2306
6efd877d
KR
2307char /* return terminator */
2308get_absolute_expression_and_terminator (val_pointer)
2309 long *val_pointer; /* return value of expression */
fecd2382 2310{
6efd877d
KR
2311 *val_pointer = get_absolute_expression ();
2312 return (*input_line_pointer++);
fecd2382
RP
2313}
2314\f
2315/*
2316 * demand_copy_C_string()
2317 *
2318 * Like demand_copy_string, but return NULL if the string contains any '\0's.
2319 * Give a warning if that happens.
2320 */
2321char *
f8701a3f 2322demand_copy_C_string (len_pointer)
6efd877d 2323 int *len_pointer;
fecd2382 2324{
6efd877d 2325 register char *s;
f8701a3f 2326
6efd877d 2327 if ((s = demand_copy_string (len_pointer)) != 0)
f8701a3f
SC
2328 {
2329 register int len;
2330
6efd877d 2331 for (len = *len_pointer;
f8701a3f
SC
2332 len > 0;
2333 len--)
2334 {
6efd877d 2335 if (*s == 0)
fecd2382 2336 {
f8701a3f
SC
2337 s = 0;
2338 len = 1;
6efd877d
KR
2339 *len_pointer = 0;
2340 as_bad ("This string may not contain \'\\0\'");
fecd2382 2341 }
f8701a3f
SC
2342 }
2343 }
2344 return (s);
fecd2382
RP
2345}
2346\f
2347/*
2348 * demand_copy_string()
2349 *
2350 * Demand string, but return a safe (=private) copy of the string.
2351 * Return NULL if we can't read a string here.
2352 */
6efd877d
KR
2353static char *
2354demand_copy_string (lenP)
2355 int *lenP;
fecd2382 2356{
6efd877d
KR
2357 register unsigned int c;
2358 register int len;
2359 char *retval;
2360
2361 len = 0;
2362 SKIP_WHITESPACE ();
2363 if (*input_line_pointer == '\"')
2364 {
2365 input_line_pointer++; /* Skip opening quote. */
2366
2367 while (is_a_char (c = next_char_of_string ()))
2368 {
2369 obstack_1grow (&notes, c);
2370 len++;
fecd2382 2371 }
6efd877d
KR
2372 /* JF this next line is so demand_copy_C_string will return a null
2373 termanated string. */
2374 obstack_1grow (&notes, '\0');
2375 retval = obstack_finish (&notes);
2376 }
2377 else
2378 {
2379 as_warn ("Missing string");
2380 retval = NULL;
2381 ignore_rest_of_line ();
2382 }
2383 *lenP = len;
2384 return (retval);
2385} /* demand_copy_string() */
fecd2382
RP
2386\f
2387/*
2388 * is_it_end_of_statement()
2389 *
2390 * In: Input_line_pointer->next character.
2391 *
2392 * Do: Skip input_line_pointer over all whitespace.
2393 *
2394 * Out: 1 if input_line_pointer->end-of-line.
f8701a3f 2395*/
6efd877d
KR
2396int
2397is_it_end_of_statement ()
2398{
2399 SKIP_WHITESPACE ();
2400 return (is_end_of_line[*input_line_pointer]);
2401} /* is_it_end_of_statement() */
fecd2382 2402
6efd877d
KR
2403void
2404equals (sym_name)
2405 char *sym_name;
fecd2382 2406{
6efd877d 2407 register symbolS *symbolP; /* symbol we are working with */
f8701a3f
SC
2408
2409 input_line_pointer++;
6efd877d 2410 if (*input_line_pointer == '=')
f8701a3f
SC
2411 input_line_pointer++;
2412
6efd877d 2413 while (*input_line_pointer == ' ' || *input_line_pointer == '\t')
f8701a3f
SC
2414 input_line_pointer++;
2415
6efd877d
KR
2416 if (sym_name[0] == '.' && sym_name[1] == '\0')
2417 {
2418 /* Turn '. = mumble' into a .org mumble */
2419 register segT segment;
2420 expressionS exp;
2421 register char *p;
f8701a3f 2422
6efd877d
KR
2423 segment = get_known_segmented_expression (&exp);
2424 if (!need_pass_2)
2425 {
9471a360 2426 if (segment != now_seg && segment != absolute_section)
6efd877d
KR
2427 as_warn ("Illegal segment \"%s\". Segment \"%s\" assumed.",
2428 segment_name (segment),
2429 segment_name (now_seg));
2430 p = frag_var (rs_org, 1, 1, (relax_substateT) 0, exp.X_add_symbol,
2431 exp.X_add_number, (char *) 0);
2432 *p = 0;
2433 } /* if (ok to make frag) */
2434 }
2435 else
2436 {
2437 symbolP = symbol_find_or_make (sym_name);
2438 pseudo_set (symbolP);
2439 }
2440} /* equals() */
fecd2382
RP
2441
2442/* .include -- include a file at this point. */
2443
2444/* ARGSUSED */
6efd877d
KR
2445void
2446s_include (arg)
2447 int arg;
fecd2382 2448{
f8701a3f
SC
2449 char *newbuf;
2450 char *filename;
2451 int i;
2452 FILE *try;
2453 char *path;
2454
6efd877d
KR
2455 filename = demand_copy_string (&i);
2456 demand_empty_rest_of_line ();
2457 path = xmalloc (i + include_dir_maxlen + 5 /* slop */ );
2458 for (i = 0; i < include_dir_count; i++)
2459 {
2460 strcpy (path, include_dirs[i]);
2461 strcat (path, "/");
2462 strcat (path, filename);
2463 if (0 != (try = fopen (path, "r")))
2464 {
2465 fclose (try);
2466 goto gotit;
2467 }
2468 }
2469 free (path);
f8701a3f
SC
2470 path = filename;
2471gotit:
2472 /* malloc Storage leak when file is found on path. FIXME-SOMEDAY. */
2473 newbuf = input_scrub_include_file (path, input_line_pointer);
2474 buffer_limit = input_scrub_next_buffer (&input_line_pointer);
6efd877d 2475} /* s_include() */
fecd2382 2476
6efd877d
KR
2477void
2478add_include_dir (path)
2479 char *path;
fecd2382 2480{
f8701a3f
SC
2481 int i;
2482
2483 if (include_dir_count == 0)
2484 {
6efd877d 2485 include_dirs = (char **) xmalloc (2 * sizeof (*include_dirs));
f8701a3f
SC
2486 include_dirs[0] = "."; /* Current dir */
2487 include_dir_count = 2;
2488 }
2489 else
2490 {
2491 include_dir_count++;
6efd877d
KR
2492 include_dirs = (char **) realloc (include_dirs,
2493 include_dir_count * sizeof (*include_dirs));
f8701a3f
SC
2494 }
2495
6efd877d 2496 include_dirs[include_dir_count - 1] = path; /* New one */
f8701a3f 2497
6efd877d
KR
2498 i = strlen (path);
2499 if (i > include_dir_maxlen)
2500 include_dir_maxlen = i;
2501} /* add_include_dir() */
fecd2382 2502
6efd877d
KR
2503void
2504s_ignore (arg)
2505 int arg;
fecd2382 2506{
6efd877d 2507 extern char is_end_of_line[];
f8701a3f 2508
6efd877d
KR
2509 while (!is_end_of_line[*input_line_pointer])
2510 {
2511 ++input_line_pointer;
2512 }
2513 ++input_line_pointer;
fecd2382 2514
6efd877d
KR
2515 return;
2516} /* s_ignore() */
fecd2382
RP
2517
2518/* end of read.c */
This page took 0.184366 seconds and 4 git commands to generate.