err not getting set early enough
[unix-history] / usr / src / contrib / gas-1.38 / read.c
CommitLineData
8ad4ec4f
DS
1/* @(#)read.c 6.2 (Berkeley) %G%
2
3Modified for Berkeley Unix by Donn Seeley, donn@okeeffe.berkeley.edu */
4
7808ad96
DS
5/* read.c - read a source file -
6 Copyright (C) 1986,1987 Free Software Foundation, Inc.
7
8This file is part of GAS, the GNU Assembler.
9
10GAS is free software; you can redistribute it and/or modify
11it under the terms of the GNU General Public License as published by
12the Free Software Foundation; either version 1, or (at your option)
13any later version.
14
15GAS is distributed in the hope that it will be useful,
16but WITHOUT ANY WARRANTY; without even the implied warranty of
17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18GNU General Public License for more details.
19
20You should have received a copy of the GNU General Public License
21along with GAS; see the file COPYING. If not, write to
22the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
23
24#define MASK_CHAR (0xFF) /* If your chars aren't 8 bits, you will
25 change this a bit. But then, GNU isn't
26 spozed to run on your machine anyway.
27 (RMS is so shortsighted sometimes.)
28 */
29
30#define MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT (16)
31 /* This is the largest known floating point */
32 /* format (for now). It will grow when we */
33 /* do 4361 style flonums. */
34
35
36/* Routines that read assembler source text to build spagetti in memory. */
37/* Another group of these functions is in the as-expr.c module */
38
39#include <ctype.h>
40#include <sys/types.h>
41#include <sys/stat.h>
42#include "as.h"
43#include "read.h"
44#include "md.h"
45#include "hash.h"
46#include "obstack.h"
47#include "frags.h"
48#include "flonum.h"
49#include "struc-symbol.h"
50#include "expr.h"
51#include "symbols.h"
52
53#ifdef SPARC
54#include "sparc.h"
55#define OTHER_ALIGN
56#endif
57#ifdef I860
58#include "i860.h"
59#endif
60
61char * input_line_pointer; /* -> next char of source file to parse. */
62
63
64#if BITS_PER_CHAR != 8
65The following table is indexed by [ (char) ] and will break if
66a char does not have exactly 256 states (hopefully 0:255!) !
67#endif
68
69const char /* used by is_... macros. our ctype[] */
70lex_type [256] = {
71 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ABCDEFGHIJKLMNO */
72 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* PQRSTUVWXYZ[\]^_ */
73 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, /* _!"#$%&'()*+,-./ */
74 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0123456789:;<=>? */
75 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* @ABCDEFGHIJKLMNO */
76 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, /* PQRSTUVWXYZ[\]^_ */
77 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* `abcdefghijklmno */
78 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, /* pqrstuvwxyz{|}~. */
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 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
83 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
84 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
85 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
86};
87
88
89/*
90 * In: a character.
91 * Out: TRUE if this character ends a line.
92 */
93#define _ (0)
94const char is_end_of_line [256] = {
95 _, _, _, _, _, _, _, _, _, _,99, _, _, _, _, _, /* @abcdefghijklmno */
96 _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
97 _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
98 _, _, _, _, _, _, _, _, _, _, _,99, _, _, _, _, /* 0123456789:;<=>? */
99 _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
100 _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
101 _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
102 _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
103 _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
104 _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
105 _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
106 _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
107 _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ /* */
108};
109#undef _
110
111 /* Functions private to this file. */
112void equals();
113void big_cons();
114void cons();
115static char* demand_copy_C_string();
116static char* demand_copy_string();
117void demand_empty_rest_of_line();
118void float_cons();
119long int get_absolute_expression();
120static char get_absolute_expression_and_terminator();
121static segT get_known_segmented_expression();
122void ignore_rest_of_line();
123static int is_it_end_of_statement();
124static void pobegin();
125static void pseudo_set();
126static void stab();
127static void stringer();
128
129extern char line_comment_chars[];
130
131static char * buffer_limit; /* -> 1 + last char in buffer. */
132
133static char * bignum_low; /* Lowest char of bignum. */
134static char * bignum_limit; /* 1st illegal address of bignum. */
135static char * bignum_high; /* Highest char of bignum. */
136 /* May point to (bignum_start-1). */
137 /* Never >= bignum_limit. */
138static char *old_buffer = 0; /* JF a hack */
139static char *old_input;
140static char *old_limit;
141
142#ifndef WORKING_DOT_WORD
143struct broken_word *broken_words;
144int new_broken_words = 0;
145#endif
146
147static void grow_bignum ();
148static int next_char_of_string ();
149\f
150void
151read_begin()
152{
153 pobegin();
154 obstack_begin( &notes, 5000 );
155#define BIGNUM_BEGIN_SIZE (16)
156 bignum_low = xmalloc((long)BIGNUM_BEGIN_SIZE);
157 bignum_limit = bignum_low + BIGNUM_BEGIN_SIZE;
158}
159\f
160/* set up pseudo-op tables */
161
162static struct hash_control *
163po_hash = NULL; /* use before set up: NULL-> address error */
164
165
166void s_abort(), s_align(), s_comm(), s_data();
167void s_desc(), s_even(), s_file(), s_fill();
168void s_globl(), s_lcomm(), s_line(), s_lsym();
169void s_org(), s_set(), s_space(), s_text();
170#ifdef VMS
171char const_flag = 0;
172void s_const();
173#endif
174
175#ifdef DONTDEF
176void s_gdbline(), s_gdblinetab();
177void s_gdbbeg(), s_gdbblock(), s_gdbend(), s_gdbsym();
178#endif
179
180void stringer();
181void cons();
182void float_cons();
183void big_cons();
184void stab();
185
186static const pseudo_typeS
187potable[] =
188{
189 { "abort", s_abort, 0 },
190 { "align", s_align, 0 },
191 { "ascii", stringer, 0 },
192 { "asciz", stringer, 1 },
193 { "byte", cons, 1 },
194 { "comm", s_comm, 0 },
195#ifdef VMS
196 { "const", s_const, 0 },
197#endif
198 { "data", s_data, 0 },
199 { "desc", s_desc, 0 },
200 { "double", float_cons, 'd' },
201 { "file", s_file, 0 },
202 { "fill", s_fill, 0 },
203 { "float", float_cons, 'f' },
204#ifdef DONTDEF
205 { "gdbbeg", s_gdbbeg, 0 },
206 { "gdbblock", s_gdbblock, 0 },
207 { "gdbend", s_gdbend, 0 },
208 { "gdbsym", s_gdbsym, 0 },
209 { "gdbline", s_gdbline, 0 },
210 { "gdblinetab",s_gdblinetab, 0 },
211#endif
212 { "globl", s_globl, 0 },
213 { "int", cons, 4 },
214 { "lcomm", s_lcomm, 0 },
215 { "line", s_line, 0 },
216 { "long", cons, 4 },
217 { "lsym", s_lsym, 0 },
218 { "octa", big_cons, 16 },
219 { "org", s_org, 0 },
220 { "quad", big_cons, 8 },
221 { "set", s_set, 0 },
222 { "short", cons, 2 },
223 { "single", float_cons, 'f' },
224 { "space", s_space, 0 },
225 { "stabd", stab, 'd' },
226 { "stabn", stab, 'n' },
227 { "stabs", stab, 's' },
228 { "text", s_text, 0 },
229#ifndef SPARC
230 { "word", cons, 2 },
231#endif
232 { NULL} /* end sentinel */
233};
234
235static void
236pobegin()
237{
238 char * errtxt; /* error text */
239 const pseudo_typeS * pop;
240
241 po_hash = hash_new();
242 errtxt = ""; /* OK so far */
243 for (pop=potable; pop->poc_name && !*errtxt; pop++)
244 {
245 errtxt = hash_insert (po_hash, pop->poc_name, (char *)pop);
246 }
247
248 for(pop=md_pseudo_table; pop->poc_name && !*errtxt; pop++)
249 errtxt = hash_insert (po_hash, pop->poc_name, (char *)pop);
250
251 if (*errtxt)
252 {
253 as_fatal ("error constructing pseudo-op table");
254 }
255} /* pobegin() */
256\f
257/* read_a_source_file()
258 *
259 * File has already been opened, and will be closed by our caller.
260 *
261 * We read the file, putting things into a web that
262 * represents what we have been reading.
263 */
264void
265read_a_source_file (buffer)
266 char * buffer; /* 1st character of each buffer of lines is here. */
267{
268 register char c;
269 register char * s; /* string of symbol, '\0' appended */
270 register int temp;
271 /* register struct frag * fragP; JF unused */ /* a frag we just made */
272 pseudo_typeS *pop;
273#ifdef DONTDEF
274 void gdb_block_beg();
275 void gdb_block_position();
276 void gdb_block_end();
277 void gdb_symbols_fixup();
278#endif
279
280 subseg_new (SEG_TEXT, 0);
281 while ( buffer_limit = input_scrub_next_buffer (&buffer) )
282 { /* We have another line to parse. */
283 know( buffer_limit [-1] == '\n' ); /* Must have a sentinel. */
284 input_line_pointer = buffer;
285 contin: /* JF this goto is my fault I admit it. Someone brave please re-write
286 the whole input section here? Pleeze??? */
287 while ( input_line_pointer < buffer_limit )
288 { /* We have more of this buffer to parse. */
289 /*
290 * We now have input_line_pointer -> 1st char of next line.
291 * If input_line_pointer [-1] == '\n' then we just
292 * scanned another line: so bump line counters.
293 */
294 if (input_line_pointer [-1] == '\n')
295 {
296 bump_line_counters ();
297 }
298 /*
299 * We are at the begining of a line, or similar place.
300 * We expect a well-formed assembler statement.
301 * A "symbol-name:" is a statement.
302 *
303 * Depending on what compiler is used, the order of these tests
304 * may vary to catch most common case 1st.
305 * Each test is independent of all other tests at the (top) level.
306 * PLEASE make a compiler that doesn't use this assembler.
307 * It is crufty to waste a compiler's time encoding things for this
308 * assembler, which then wastes more time decoding it.
309 * (And communicating via (linear) files is silly!
310 * If you must pass stuff, please pass a tree!)
311 */
312 if ( (c= * input_line_pointer ++) == '\t' || c == ' ' || c=='\f')
313 {
314 c = * input_line_pointer ++;
315 }
316 know( c != ' ' ); /* No further leading whitespace. */
317 /*
318 * C is the 1st significant character.
319 * Input_line_pointer points after that character.
320 */
321 if ( is_name_beginner(c) )
322 { /* want user-defined label or pseudo/opcode */
323 s = -- input_line_pointer;
324 c = get_symbol_end(); /* name's delimiter */
325 /*
326 * C is character after symbol.
327 * That character's place in the input line is now '\0'.
328 * S points to the beginning of the symbol.
329 * [In case of pseudo-op, s -> '.'.]
330 * Input_line_pointer -> '\0' where c was.
331 */
332 if ( c == ':' )
333 {
334 colon(s); /* user-defined label */
8ad4ec4f
DS
335 if (flagseen['g'])
336 stabf(s); /* set line number for function definition */
7808ad96
DS
337 * input_line_pointer ++ = ':'; /* Put ':' back for error messages' sake. */
338 /* Input_line_pointer -> after ':'. */
339 SKIP_WHITESPACE();
340 }
341 else if(c=='=' || input_line_pointer[1]=='=') /* JF deal with FOO=BAR */
342 {
343 equals(s);
344 demand_empty_rest_of_line();
345 }
346 else
347 { /* expect pseudo-op or machine instruction */
348 if ( *s=='.' )
349 {
350 /*
351 * PSEUDO - OP.
352 *
353 * WARNING: c has next char, which may be end-of-line.
354 * We lookup the pseudo-op table with s+1 because we
355 * already know that the pseudo-op begins with a '.'.
356 */
357
358 pop= (pseudo_typeS *) hash_find (po_hash, s+1);
359
360 /* Print the error msg now, while we still can */
361 if(!pop)
362 as_bad("Unknown pseudo-op: '%s'",s);
363
364 /* Put it back for error messages etc. */
365 * input_line_pointer = c;
366 /* The following skip of whitespace is compulsory. */
367 /* A well shaped space is sometimes all that seperates keyword from operands. */
368 if ( c == ' ' || c == '\t' )
369 { /* Skip seperator after keyword. */
370 input_line_pointer ++;
371 }
372 /*
373 * Input_line is restored.
374 * Input_line_pointer -> 1st non-blank char
375 * after pseudo-operation.
376 */
377 if(!pop) {
378 ignore_rest_of_line();
379 break;
380 }
381 else
382 (*pop->poc_handler)(pop->poc_val);
383 }
384 else
385 { /* machine instruction */
8ad4ec4f
DS
386 /* If source file debugging, emit a stab. */
387 if (flagseen['g'])
388 linestab();
389
7808ad96
DS
390 /* WARNING: c has char, which may be end-of-line. */
391 /* Also: input_line_pointer -> `\0` where c was. */
392 * input_line_pointer = c;
393 while ( ! is_end_of_line [* input_line_pointer] )
394 {
395 input_line_pointer ++;
396 }
397 c = * input_line_pointer;
398 * input_line_pointer = '\0';
399 md_assemble (s); /* Assemble 1 instruction. */
400 * input_line_pointer ++ = c;
401 /* We resume loop AFTER the end-of-line from this instruction */
402 } /* if (*s=='.') */
403 } /* if c==':' */
404 continue;
405 } /* if (is_name_beginner(c) */
406
407
408 if ( is_end_of_line [c] )
409 { /* empty statement */
410 continue;
411 }
412
413 if ( isdigit(c) )
414 { /* local label ("4:") */
415 temp = c - '0';
416#ifdef SUN_ASM_SYNTAX
417 if( *input_line_pointer=='$')
418 input_line_pointer++;
419#endif
420 if ( * input_line_pointer ++ == ':' )
421 {
422 local_colon (temp);
423 }
424 else
425 {
426 as_bad( "Spurious digit %d.", temp);
427 input_line_pointer -- ;
428 ignore_rest_of_line();
429 }
430 continue;
431 }
432 if(c && index(line_comment_chars,c)) { /* Its a comment. Better say APP or NO_APP */
433 char *ends;
434 char *strstr();
435 char *new_buf;
436 char *new_tmp;
437 int new_length;
438 char *tmp_buf = 0;
439 extern char *scrub_string,*scrub_last_string;
440 int scrub_from_string();
441 void scrub_to_string();
442
443 bump_line_counters();
444 s=input_line_pointer;
445 if(strncmp(s,"APP\n",4))
446 continue; /* We ignore it */
447 s+=4;
448
449 ends=strstr(s,"#NO_APP\n");
450
451 if(!ends) {
452 int tmp_len;
453 int num;
454
455 /* The end of the #APP wasn't in this buffer. We
456 keep reading in buffers until we find the #NO_APP
457 that goes with this #APP There is one. The specs
458 guarentee it. . .*/
459 tmp_len=buffer_limit-s;
460 tmp_buf=xmalloc(tmp_len);
461 bcopy(s,tmp_buf,tmp_len);
462 do {
463 new_tmp = input_scrub_next_buffer(&buffer);
464 if(!new_tmp)
465 break;
466 else
467 buffer_limit = new_tmp;
468 input_line_pointer = buffer;
469 ends = strstr(buffer,"#NO_APP\n");
470 if(ends)
471 num=ends-buffer;
472 else
473 num=buffer_limit-buffer;
474
475 tmp_buf=xrealloc(tmp_buf,tmp_len+num);
476 bcopy(buffer,tmp_buf+tmp_len,num);
477 tmp_len+=num;
478 } while(!ends);
479
480 input_line_pointer= ends ? ends+8 : NULL;
481
482 s=tmp_buf;
483 ends=s+tmp_len;
484
485 } else {
486 input_line_pointer=ends+8;
487 }
488 new_buf=xmalloc(100);
489 new_length=100;
490 new_tmp=new_buf;
491
492 scrub_string=s;
493 scrub_last_string = ends;
494 for(;;) {
495 int ch;
496
497 ch=do_scrub_next_char(scrub_from_string,scrub_to_string);
498 if(ch==EOF) break;
499 *new_tmp++=ch;
500 if(new_tmp==new_buf+new_length) {
501 new_buf=xrealloc(new_buf,new_length+100);
502 new_tmp=new_buf+new_length;
503 new_length+=100;
504 }
505 }
506
507 if(tmp_buf)
508 free(tmp_buf);
509 old_buffer=buffer;
510 old_input=input_line_pointer;
511 old_limit=buffer_limit;
512 buffer=new_buf;
513 input_line_pointer=new_buf;
514 buffer_limit=new_tmp;
515 continue;
516 }
517
518 as_bad("Junk character %d.",c);
519 ignore_rest_of_line();
520 } /* while (input_line_pointer<buffer_limit )*/
521 if(old_buffer) {
522 bump_line_counters();
523 if(old_input == 0)
524 return;
525 buffer=old_buffer;
526 input_line_pointer=old_input;
527 buffer_limit=old_limit;
528 old_buffer = 0;
529 goto contin;
530 }
531 } /* while (more bufrers to scan) */
532} /* read_a_source_file() */
533
534void
535s_abort()
536{
537 as_fatal(".abort detected. Abandoning ship.");
538}
539
540#ifdef OTHER_ALIGN
541static void
542s_align()
543{
544 register unsigned int temp;
545 register long int temp_fill;
546 unsigned int i;
547
548 temp = get_absolute_expression ();
549#define MAX_ALIGNMENT (1 << 15)
550 if ( temp > MAX_ALIGNMENT ) {
551 as_bad("Alignment too large: %d. assumed.", temp = MAX_ALIGNMENT);
552 }
553
554 /*
555 * For the sparc, `.align (1<<n)' actually means `.align n'
556 * so we have to convert it.
557 */
558 if (temp != 0) {
559 for (i = 0; (temp & 1) == 0; temp >>= 1, ++i)
560 ;
561 }
562 if (temp != 1)
563 as_bad("Alignment not a power of 2");
564
565 temp = i;
566 if (*input_line_pointer == ',') {
567 input_line_pointer ++;
568 temp_fill = get_absolute_expression ();
569 } else {
570 temp_fill = 0;
571 }
572 /* Only make a frag if we HAVE to. . . */
573 if (temp && ! need_pass_2)
574 frag_align (temp, (int)temp_fill);
575
576 demand_empty_rest_of_line();
577}
578#else
579
580void
581s_align()
582{
583 register int temp;
584 register long int temp_fill;
585
586 temp = get_absolute_expression ();
587#define MAX_ALIGNMENT (15)
588 if ( temp > MAX_ALIGNMENT )
589 as_bad("Alignment too large: %d. assumed.", temp = MAX_ALIGNMENT);
590 else if ( temp < 0 ) {
591 as_bad("Alignment negative. 0 assumed.");
592 temp = 0;
593 }
594 if ( *input_line_pointer == ',' ) {
595 input_line_pointer ++;
596 temp_fill = get_absolute_expression ();
597 } else
598 temp_fill = 0;
599 /* Only make a frag if we HAVE to. . . */
600 if ( temp && ! need_pass_2 )
601 frag_align (temp, (int)temp_fill);
602 demand_empty_rest_of_line();
603}
604#endif
605
606void
607s_comm()
608{
609 register char *name;
610 register char c;
611 register char *p;
612 register int temp;
613 register symbolS * symbolP;
614
615 name = input_line_pointer;
616 c = get_symbol_end();
617 /* just after name is now '\0' */
618 p = input_line_pointer;
619 *p = c;
620 SKIP_WHITESPACE();
621 if ( * input_line_pointer != ',' ) {
622 as_bad("Expected comma after symbol-name");
623 ignore_rest_of_line();
624 return;
625 }
626 input_line_pointer ++; /* skip ',' */
627 if ( (temp = get_absolute_expression ()) < 0 ) {
628 as_warn(".COMMon length (%d.) <0! Ignored.", temp);
629 ignore_rest_of_line();
630 return;
631 }
632 *p = 0;
633 symbolP = symbol_find_or_make (name);
634 *p = c;
635 if ( (symbolP -> sy_type & N_TYPE) != N_UNDF ||
636 symbolP -> sy_other != 0 || symbolP -> sy_desc != 0) {
637 as_warn( "Ignoring attempt to re-define symbol");
638 ignore_rest_of_line();
639 return;
640 }
641 if (symbolP -> sy_value) {
642 if (symbolP -> sy_value != temp)
643 as_warn( "Length of .comm \"%s\" is already %d. Not changed to %d.",
644 symbolP -> sy_name, symbolP -> sy_value, temp);
645 } else {
646 symbolP -> sy_value = temp;
647 symbolP -> sy_type |= N_EXT;
648 }
649#ifdef VMS
650 if(!temp)
651 symbolP->sy_other = const_flag;
652#endif
653 know( symbolP -> sy_frag == &zero_address_frag );
654 demand_empty_rest_of_line();
655}
656
657#ifdef VMS
658void
659s_const()
660{
661 register int temp;
662
663 temp = get_absolute_expression ();
664 subseg_new (SEG_DATA, (subsegT)temp);
665 const_flag = 1;
666 demand_empty_rest_of_line();
667}
668#endif
669
670void
671s_data()
672{
673 register int temp;
674
675 temp = get_absolute_expression ();
676 subseg_new (SEG_DATA, (subsegT)temp);
677#ifdef VMS
678 const_flag = 0;
679#endif
680 demand_empty_rest_of_line();
681}
682
683void
684s_desc()
685{
686 register char *name;
687 register char c;
688 register char *p;
689 register symbolS * symbolP;
690 register int temp;
691
692 /*
693 * Frob invented at RMS' request. Set the n_desc of a symbol.
694 */
695 name = input_line_pointer;
696 c = get_symbol_end();
697 p = input_line_pointer;
698 symbolP = symbol_table_lookup (name);
699 * p = c;
700 SKIP_WHITESPACE();
701 if ( * input_line_pointer != ',' ) {
702 *p = 0;
703 as_bad("Expected comma after name \"%s\"", name);
704 *p = c;
705 ignore_rest_of_line();
706 } else {
707 input_line_pointer ++;
708 temp = get_absolute_expression ();
709 *p = 0;
710 symbolP = symbol_find_or_make (name);
711 *p = c;
712 symbolP -> sy_desc = temp;
713 }
714 demand_empty_rest_of_line();
715}
716
717void
718s_file()
719{
720 register char *s;
721 int length;
722
723 /* Some assemblers tolerate immediately following '"' */
724 if ( s = demand_copy_string( & length ) ) {
725 new_logical_line (s, -1);
726 demand_empty_rest_of_line();
727 }
728}
729
730void
731s_fill()
732{
733 long int temp_repeat;
734 long int temp_size;
735 register long int temp_fill;
736 char *p;
737
738 if ( get_absolute_expression_and_terminator(& temp_repeat) != ',' ) {
739 input_line_pointer --; /* Backup over what was not a ','. */
740 as_warn("Expect comma after rep-size in .fill");
741 ignore_rest_of_line();
742 return;
743 }
744 if ( get_absolute_expression_and_terminator( & temp_size) != ',' ) {
745 input_line_pointer --; /* Backup over what was not a ','. */
746 as_warn("Expected comma after size in .fill");
747 ignore_rest_of_line();
748 return;
749 }
750 /*
751 * This is to be compatible with BSD 4.2 AS, not for any rational reason.
752 */
753#define BSD_FILL_SIZE_CROCK_8 (8)
754 if ( temp_size > BSD_FILL_SIZE_CROCK_8 ) {
755 as_bad(".fill size clamped to %d.", BSD_FILL_SIZE_CROCK_8);
756 temp_size = BSD_FILL_SIZE_CROCK_8 ;
757 } if ( temp_size < 0 ) {
758 as_warn("Size negative: .fill ignored.");
759 temp_size = 0;
760 } else if ( temp_repeat <= 0 ) {
761 as_warn("Repeat < 0, .fill ignored");
762 temp_size = 0;
763 }
764 temp_fill = get_absolute_expression ();
765 if ( temp_size && !need_pass_2 ) {
766 p = frag_var (rs_fill, (int)temp_size, (int)temp_size, (relax_substateT)0, (symbolS *)0, temp_repeat, (char *)0);
767 bzero (p, (int)temp_size);
768/*
769 * The magic number BSD_FILL_SIZE_CROCK_4 is from BSD 4.2 VAX flavoured AS.
770 * The following bizzare behaviour is to be compatible with above.
771 * I guess they tried to take up to 8 bytes from a 4-byte expression
772 * and they forgot to sign extend. Un*x Sux.
773 */
774#define BSD_FILL_SIZE_CROCK_4 (4)
775 md_number_to_chars (p, temp_fill, temp_size > BSD_FILL_SIZE_CROCK_4 ? BSD_FILL_SIZE_CROCK_4 : (int)temp_size);
776/*
777 * Note: .fill (),0 emits no frag (since we are asked to .fill 0 bytes)
778 * but emits no error message because it seems a legal thing to do.
779 * It is a degenerate case of .fill but could be emitted by a compiler.
780 */
781 }
782 demand_empty_rest_of_line();
783}
784
785#ifdef DONTDEF
786void
787s_gdbbeg()
788{
789 register int temp;
790
791 temp = get_absolute_expression ();
792 if (temp < 0)
793 as_warn( "Block number <0. Ignored." );
794 else if (flagseen ['G'])
795 gdb_block_beg ( (long int) temp, frag_now, (long int)(obstack_next_free(& frags) - frag_now -> fr_literal));
796 demand_empty_rest_of_line ();
797}
798
799void
800s_gdbblock()
801{
802 register int position;
803 int temp;
804
805 if (get_absolute_expression_and_terminator (&temp) != ',') {
806 as_warn( "expected comma before position in .gdbblock");
807 --input_line_pointer;
808 ignore_rest_of_line ();
809 return;
810 }
811 position = get_absolute_expression ();
812 if (flagseen ['G'])
813 gdb_block_position ((long int) temp, (long int) position);
814 demand_empty_rest_of_line ();
815}
816
817void
818s_gdbend()
819{
820 register int temp;
821
822 temp = get_absolute_expression ();
823 if (temp < 0)
824 as_warn( "Block number <0. Ignored." );
825 else if (flagseen ['G'])
826 gdb_block_end ( (long int) temp, frag_now, (long int)(obstack_next_free(& frags) - frag_now -> fr_literal));
827 demand_empty_rest_of_line ();
828}
829
830void
831s_gdbsym()
832{
833 register char *name,
834 *p;
835 register char c;
836 register symbolS * symbolP;
837 register int temp;
838
839 name = input_line_pointer;
840 c = get_symbol_end();
841 p = input_line_pointer;
842 symbolP = symbol_find_or_make (name);
843 *p = c;
844 SKIP_WHITESPACE();
845 if ( * input_line_pointer != ',' ) {
846 as_warn("Expected comma after name");
847 ignore_rest_of_line();
848 return;
849 }
850 input_line_pointer ++;
851 if ( (temp = get_absolute_expression ()) < 0 ) {
852 as_warn("Bad GDB symbol file offset (%d.) <0! Ignored.", temp);
853 ignore_rest_of_line();
854 return;
855 }
856 if (flagseen ['G'])
857 gdb_symbols_fixup (symbolP, (long int)temp);
858 demand_empty_rest_of_line ();
859}
860
861void
862s_gdbline()
863{
864 int file_number,
865 lineno;
866
867 if(get_absolute_expression_and_terminator(&file_number) != ',') {
868 as_warn("expected comman after filenum in .gdbline");
869 ignore_rest_of_line();
870 return;
871 }
872 lineno=get_absolute_expression();
873 if(flagseen['G'])
874 gdb_line(file_number,lineno);
875 demand_empty_rest_of_line();
876}
877
878
879void
880s_gdblinetab()
881{
882 int file_number,
883 offset;
884
885 if(get_absolute_expression_and_terminator(&file_number) != ',') {
886 as_warn("expected comman after filenum in .gdblinetab");
887 ignore_rest_of_line();
888 return;
889 }
890 offset=get_absolute_expression();
891 if(flagseen['G'])
892 gdb_line_tab(file_number,offset);
893 demand_empty_rest_of_line();
894}
895#endif
896
897void
898s_globl()
899{
900 register char *name;
901 register int c;
902 register symbolS * symbolP;
903
904 do {
905 name = input_line_pointer;
906 c = get_symbol_end();
907 symbolP = symbol_find_or_make (name);
908 * input_line_pointer = c;
909 SKIP_WHITESPACE();
910 symbolP -> sy_type |= N_EXT;
911 if(c==',') {
912 input_line_pointer++;
913 SKIP_WHITESPACE();
914 if(*input_line_pointer=='\n')
915 c='\n';
916 }
917 } while(c==',');
918 demand_empty_rest_of_line();
919}
920
921void
922s_lcomm()
923{
924 register char *name;
925 register char c;
926 register char *p;
927 register int temp;
928 register symbolS * symbolP;
929
930 name = input_line_pointer;
931 c = get_symbol_end();
932 p = input_line_pointer;
933 *p = c;
934 SKIP_WHITESPACE();
935 if ( * input_line_pointer != ',' ) {
936 as_warn("Expected comma after name");
937 ignore_rest_of_line();
938 return;
939 }
940 input_line_pointer ++;
941 if ( (temp = get_absolute_expression ()) < 0 ) {
942 as_warn("BSS length (%d.) <0! Ignored.", temp);
943 ignore_rest_of_line();
944 return;
945 }
946 *p = 0;
947 symbolP = symbol_find_or_make (name);
948 *p = c;
949 if ( symbolP -> sy_other == 0
950 && symbolP -> sy_desc == 0
951 && ( ( symbolP -> sy_type == N_BSS
952 && symbolP -> sy_value == local_bss_counter)
953 || ( (symbolP -> sy_type & N_TYPE) == N_UNDF
954 && symbolP -> sy_value == 0))) {
955 symbolP -> sy_value = local_bss_counter;
956 symbolP -> sy_type = N_BSS;
957 symbolP -> sy_frag = & bss_address_frag;
958 local_bss_counter += temp;
959 } else
960 as_warn( "Ignoring attempt to re-define symbol from %d. to %d.",
961 symbolP -> sy_value, local_bss_counter );
962 demand_empty_rest_of_line();
963}
964
965void
966s_line()
967{
968 /* Assume delimiter is part of expression. */
969 /* BSD4.2 as fails with delightful bug, so we */
970 /* are not being incompatible here. */
971 new_logical_line ((char *)NULL, (int)(get_absolute_expression ()));
972 demand_empty_rest_of_line();
973}
974
975void
976s_long()
977{
978 cons(4);
979}
980
981void
982s_int()
983{
984 cons(4);
985}
986
987void
988s_lsym()
989{
990 register char *name;
991 register char c;
992 register char *p;
993 register segT segment;
994 expressionS exp;
995 register symbolS *symbolP;
996
997 /* we permit ANY expression: BSD4.2 demands constants */
998 name = input_line_pointer;
999 c = get_symbol_end();
1000 p = input_line_pointer;
1001 *p = c;
1002 SKIP_WHITESPACE();
1003 if ( * input_line_pointer != ',' ) {
1004 *p = 0;
1005 as_warn("Expected comma after name \"%s\"", name);
1006 *p = c;
1007 ignore_rest_of_line();
1008 return;
1009 }
1010 input_line_pointer ++;
1011 segment = expression (& exp);
1012 if ( segment != SEG_ABSOLUTE && segment != SEG_DATA &&
1013 segment != SEG_TEXT && segment != SEG_BSS) {
1014 as_bad("Bad expression: %s", seg_name [(int)segment]);
1015 ignore_rest_of_line();
1016 return;
1017 }
1018 know( segment == SEG_ABSOLUTE || segment == SEG_DATA || segment == SEG_TEXT || segment == SEG_BSS );
1019 *p = 0;
1020 symbolP = symbol_new (name,(unsigned char)(seg_N_TYPE [(int) segment]),
1021 0, 0, (valueT)(exp . X_add_number), & zero_address_frag);
1022 *p = c;
1023 demand_empty_rest_of_line();
1024}
1025
1026void
1027s_org()
1028{
1029 register segT segment;
1030 expressionS exp;
1031 register long int temp_fill;
1032 register char *p;
1033/*
1034 * Don't believe the documentation of BSD 4.2 AS.
1035 * There is no such thing as a sub-segment-relative origin.
1036 * Any absolute origin is given a warning, then assumed to be segment-relative.
1037 * Any segmented origin expression ("foo+42") had better be in the right
1038 * segment or the .org is ignored.
1039 *
1040 * BSD 4.2 AS warns if you try to .org backwards. We cannot because we
1041 * never know sub-segment sizes when we are reading code.
1042 * BSD will crash trying to emit -ve numbers of filler bytes in certain
1043 * .orgs. We don't crash, but see as-write for that code.
1044 */
1045/*
1046 * Don't make frag if need_pass_2==TRUE.
1047 */
1048 segment = get_known_segmented_expression(& exp);
1049 if ( *input_line_pointer == ',' ) {
1050 input_line_pointer ++;
1051 temp_fill = get_absolute_expression ();
1052 } else
1053 temp_fill = 0;
1054 if ( ! need_pass_2 ) {
1055 if (segment != now_seg && segment != SEG_ABSOLUTE)
1056 as_warn("Illegal segment \"%s\". Segment \"%s\" assumed.",
1057 seg_name [(int) segment], seg_name [(int) now_seg]);
1058 p = frag_var (rs_org, 1, 1, (relax_substateT)0, exp . X_add_symbol,
1059 exp . X_add_number, (char *)0);
1060 * p = temp_fill;
1061 } /* if (ok to make frag) */
1062 demand_empty_rest_of_line();
1063}
1064
1065void
1066s_set()
1067{
1068 register char *name;
1069 register char delim;
1070 register char *end_name;
1071 register symbolS *symbolP;
1072
1073 /*
1074 * Especial apologies for the random logic:
1075 * this just grew, and could be parsed much more simply!
1076 * Dean in haste.
1077 */
1078 name = input_line_pointer;
1079 delim = get_symbol_end();
1080 end_name = input_line_pointer;
1081 *end_name = delim;
1082 SKIP_WHITESPACE();
1083 if ( * input_line_pointer != ',' ) {
1084 *end_name = 0;
1085 as_warn("Expected comma after name \"%s\"", name);
1086 *end_name = delim;
1087 ignore_rest_of_line();
1088 return;
1089 }
1090 input_line_pointer ++;
1091 *end_name = 0;
1092 if(name[0]=='.' && name[1]=='\0') {
1093 /* Turn '. = mumble' into a .org mumble */
1094 register segT segment;
1095 expressionS exp;
1096 register char *ptr;
1097
1098 segment = get_known_segmented_expression(& exp);
1099 if ( ! need_pass_2 ) {
1100 if (segment != now_seg && segment != SEG_ABSOLUTE)
1101 as_warn("Illegal segment \"%s\". Segment \"%s\" assumed.",
1102 seg_name [(int) segment], seg_name [(int) now_seg]);
1103 ptr = frag_var (rs_org, 1, 1, (relax_substateT)0, exp.X_add_symbol,
1104 exp.X_add_number, (char *)0);
1105 *ptr= 0;
1106 } /* if (ok to make frag) */
1107 *end_name = delim;
1108 return;
1109 }
1110 symbolP = symbol_find_or_make (name);
1111 *end_name = delim;
1112 pseudo_set (symbolP);
1113 demand_empty_rest_of_line ();
1114}
1115
1116void
1117s_space()
1118{
1119 long int temp_repeat;
1120 register long int temp_fill;
1121 register char *p;
1122
1123 /* Just like .fill, but temp_size = 1 */
1124 if ( get_absolute_expression_and_terminator( & temp_repeat) == ',' ) {
1125 temp_fill = get_absolute_expression ();
1126 } else {
1127 input_line_pointer --; /* Backup over what was not a ','. */
1128 temp_fill = 0;
1129 }
1130 if ( temp_repeat <= 0 ) {
1131 as_warn("Repeat < 0, .space ignored");
1132 ignore_rest_of_line();
1133 return;
1134 }
1135 if ( ! need_pass_2 ) {
1136 p = frag_var (rs_fill, 1, 1, (relax_substateT)0, (symbolS *)0,
1137 temp_repeat, (char *)0);
1138 * p = temp_fill;
1139 }
1140 demand_empty_rest_of_line();
1141}
1142
1143void
1144s_text()
1145{
1146 register int temp;
1147
1148 temp = get_absolute_expression ();
1149 subseg_new (SEG_TEXT, (subsegT)temp);
1150 demand_empty_rest_of_line();
1151}
1152
1153\f
1154/*( JF was static, but can't be if machine dependent pseudo-ops are to use it */
1155
1156void
1157demand_empty_rest_of_line()
1158{
1159 SKIP_WHITESPACE();
1160 if ( is_end_of_line [* input_line_pointer] )
1161 {
1162 input_line_pointer ++;
1163 }
1164 else
1165 {
1166 ignore_rest_of_line();
1167 }
1168 /* Return having already swallowed end-of-line. */
1169} /* Return pointing just after end-of-line. */
1170
1171
1172void
1173ignore_rest_of_line() /* For suspect lines: gives warning. */
1174{
1175 if ( ! is_end_of_line [* input_line_pointer])
1176 {
1177 as_warn("Rest of line ignored. 1st junk character valued %d (%c)."
1178 , * input_line_pointer, *input_line_pointer);
1179 while ( input_line_pointer < buffer_limit
1180 && ! is_end_of_line [* input_line_pointer] )
1181 {
1182 input_line_pointer ++;
1183 }
1184 }
1185 input_line_pointer ++; /* Return pointing just after end-of-line. */
1186 know( is_end_of_line [input_line_pointer [-1]] );
1187}
1188\f
1189/*
1190 * stab()
1191 *
1192 * Handle .stabX directives, which used to be open-coded.
1193 * So much creeping featurism overloaded the semantics that we decided
1194 * to put all .stabX thinking in one place. Here.
1195 *
1196 * We try to make any .stabX directive legal. Other people's AS will often
1197 * do assembly-time consistency checks: eg assigning meaning to n_type bits
1198 * and "protecting" you from setting them to certain values. (They also zero
1199 * certain bits before emitting symbols. Tut tut.)
1200 *
1201 * If an expression is not absolute we either gripe or use the relocation
1202 * information. Other people's assemblers silently forget information they
1203 * don't need and invent information they need that you didn't supply.
1204 *
1205 * .stabX directives always make a symbol table entry. It may be junk if
1206 * the rest of your .stabX directive is malformed.
1207 */
1208static void
1209stab (what)
1210int what;
1211{
1212 register symbolS * symbolP;
1213 register char * string;
1214 int saved_type;
1215 int length;
1216 int goof; /* TRUE if we have aborted. */
1217 long int longint;
1218
1219/*
1220 * Enter with input_line_pointer pointing past .stabX and any following
1221 * whitespace.
1222 */
1223 goof = FALSE; /* JF who forgot this?? */
1224 if (what == 's') {
1225 string = demand_copy_C_string (& length);
1226 SKIP_WHITESPACE();
1227 if (* input_line_pointer == ',')
1228 input_line_pointer ++;
1229 else {
1230 as_warn( "I need a comma after symbol's name" );
1231 goof = TRUE;
1232 }
1233 } else
1234 string = "";
1235
1236/*
1237 * Input_line_pointer->after ','. String -> symbol name.
1238 */
1239 if (! goof) {
1240 symbolP = symbol_new (string, 0,0,0,0,(struct frag *)0);
1241 switch (what) {
1242 case 'd':
1243 symbolP->sy_name = NULL; /* .stabd feature. */
1244 symbolP->sy_value = obstack_next_free(& frags) - frag_now->fr_literal;
1245 symbolP->sy_frag = frag_now;
1246 break;
1247
1248 case 'n':
1249 symbolP->sy_frag = &zero_address_frag;
1250 break;
1251
1252 case 's':
1253 symbolP->sy_frag = & zero_address_frag;
1254 break;
1255
1256 default:
1257 BAD_CASE( what );
1258 break;
1259 }
1260 if (get_absolute_expression_and_terminator (& longint) == ',')
1261 symbolP->sy_type = saved_type = longint;
1262 else {
1263 as_warn( "I want a comma after the n_type expression" );
1264 goof = TRUE;
1265 input_line_pointer --; /* Backup over a non-',' char. */
1266 }
1267 }
1268 if (! goof) {
1269 if (get_absolute_expression_and_terminator (& longint) == ',')
1270 symbolP->sy_other = longint;
1271 else {
1272 as_warn( "I want a comma after the n_other expression" );
1273 goof = TRUE;
1274 input_line_pointer --; /* Backup over a non-',' char. */
1275 }
1276 }
1277 if (! goof) {
1278 symbolP->sy_desc = get_absolute_expression ();
1279 if (what == 's' || what == 'n') {
1280 if (* input_line_pointer != ',') {
1281 as_warn( "I want a comma after the n_desc expression" );
1282 goof = TRUE;
1283 } else {
1284 input_line_pointer ++;
1285 }
1286 }
1287 }
1288 if ((! goof) && (what=='s' || what=='n')) {
1289 pseudo_set (symbolP);
1290 symbolP->sy_type = saved_type;
1291 }
1292 if (goof)
1293 ignore_rest_of_line ();
1294 else
1295 demand_empty_rest_of_line ();
1296}
1297\f
1298/*
1299 * pseudo_set()
1300 *
1301 * In: Pointer to a symbol.
1302 * Input_line_pointer -> expression.
1303 *
1304 * Out: Input_line_pointer -> just after any whitespace after expression.
1305 * Tried to set symbol to value of expression.
1306 * Will change sy_type, sy_value, sy_frag;
1307 * May set need_pass_2 == TRUE.
1308 */
1309static void
1310pseudo_set (symbolP)
1311 symbolS * symbolP;
1312{
1313 expressionS exp;
1314 register segT segment;
1315 int ext;
1316
1317 know( symbolP ); /* NULL pointer is logic error. */
1318 ext=(symbolP->sy_type&N_EXT);
1319 if ((segment = expression( & exp )) == SEG_NONE)
1320 {
1321 as_warn( "Missing expression: absolute 0 assumed" );
1322 exp . X_seg = SEG_ABSOLUTE;
1323 exp . X_add_number = 0;
1324 }
1325 switch (segment)
1326 {
1327 case SEG_BIG:
1328 as_warn( "%s number illegal. Absolute 0 assumed.",
1329 exp . X_add_number > 0 ? "Bignum" : "Floating-Point" );
1330 symbolP -> sy_type = N_ABS | ext;
1331 symbolP -> sy_value = 0;
1332 symbolP -> sy_frag = & zero_address_frag;
1333 break;
1334
1335 case SEG_NONE:
1336 as_warn("No expression: Using absolute 0");
1337 symbolP -> sy_type = N_ABS | ext;
1338 symbolP -> sy_value = 0;
1339 symbolP -> sy_frag = & zero_address_frag;
1340 break;
1341
1342 case SEG_DIFFERENCE:
1343 if (exp.X_add_symbol && exp.X_subtract_symbol
1344 && (exp.X_add_symbol->sy_type & N_TYPE)
1345 == (exp.X_subtract_symbol->sy_type & N_TYPE)) {
1346 if(exp.X_add_symbol->sy_frag != exp.X_subtract_symbol->sy_frag) {
1347 as_bad("Unknown expression: symbols %s and %s are in different frags.",exp.X_add_symbol->sy_name, exp.X_subtract_symbol->sy_name);
1348 need_pass_2++;
1349 }
1350 exp.X_add_number+=exp.X_add_symbol->sy_value - exp.X_subtract_symbol->sy_value;
1351 } else
1352 as_warn( "Complex expression. Absolute segment assumed." );
1353 case SEG_ABSOLUTE:
1354 symbolP -> sy_type = N_ABS | ext;
1355 symbolP -> sy_value = exp . X_add_number;
1356 symbolP -> sy_frag = & zero_address_frag;
1357 break;
1358
1359 case SEG_DATA:
1360 case SEG_TEXT:
1361 case SEG_BSS:
1362 symbolP -> sy_type = seg_N_TYPE [(int) segment] | ext;
1363 symbolP -> sy_value= exp . X_add_number + exp . X_add_symbol -> sy_value;
1364 symbolP -> sy_frag = exp . X_add_symbol -> sy_frag;
1365 break;
1366
1367 case SEG_PASS1: /* Not an error. Just try another pass. */
1368 symbolP->sy_forward=exp.X_add_symbol;
1369 as_warn("Unknown expression");
1370 know( need_pass_2 == TRUE );
1371 break;
1372
1373 case SEG_UNKNOWN:
1374 symbolP->sy_forward=exp.X_add_symbol;
1375 /* as_warn("unknown symbol"); */
1376 /* need_pass_2 = TRUE; */
1377 break;
1378
1379 default:
1380 BAD_CASE( segment );
1381 break;
1382 }
1383}
1384\f
8ad4ec4f
DS
1385/*
1386 * stabs(file), stabf(func) and stabd(line) -- for the purpose of
1387 * source file debugging of assembly files, generate file,
1388 * function and line number stabs, respectively.
1389 * stabs() and stabd() are normally called through a function linestab()
1390 * in input-scrub.c which understands about logical line numbers.
1391 */
1392
1393#include <stab.h>
1394
1395static int stabs_done;
1396
1397stabs(file)
1398 char *file;
1399{
1400 /* .stabs "file",100,0,0,. */
1401 (void) symbol_new(file,
1402 N_SO,
1403 0,
1404 0,
1405 obstack_next_free(& frags) - frag_now->fr_literal,
1406 frag_now);
1407 stabs_done = 1;
1408}
1409
1410stabf(func)
1411 char *func;
1412{
1413 symbolS *symbolP;
1414 static int void_undefined = 1;
1415
1416 /* crudely filter uninteresting labels: require an initial '_' */
1417 if (now_seg != SEG_TEXT || *func++ != '_')
1418 return;
1419
1420 /* don't emit a function stab until a file stab has been seen */
1421 if (!stabs_done)
1422 linestab();
1423
1424 /* assembly functions are assumed to have void type */
1425 if (void_undefined)
1426 {
1427 /* .stabs "void:t15=15",128,0,0,0 */
1428 (void) symbol_new("void:t1=1",
1429 N_LSYM,
1430 0,
1431 0,
1432 0,
1433 &zero_address_frag);
1434 void_undefined = 0;
1435 }
1436
1437 /* .stabs "func:F1",36,0,0,. */
1438 symbolP = symbol_new((char *) 0,
1439 N_FUN,
1440 0,
1441 0,
1442 obstack_next_free(& frags) - frag_now->fr_literal,
1443 frag_now);
1444 obstack_grow(&notes, func, strlen(func));
1445 obstack_1grow(&notes, ':');
1446 obstack_1grow(&notes, 'F');
1447 obstack_1grow(&notes, '1');
1448 obstack_1grow(&notes, '\0');
1449 symbolP->sy_name = obstack_finish(&notes);
1450}
1451
1452stabd(line)
1453 unsigned line;
1454{
1455 /* .stabd 68,0,line */
1456 (void) symbol_new((char *)0,
1457 N_SLINE,
1458 0,
1459 line,
1460 obstack_next_free(& frags) - frag_now->fr_literal,
1461 frag_now);
1462}
1463\f
7808ad96
DS
1464/*
1465 * cons()
1466 *
1467 * CONStruct more frag of .bytes, or .words etc.
1468 * Should need_pass_2 be TRUE then emit no frag(s).
1469 * This understands EXPRESSIONS, as opposed to big_cons().
1470 *
1471 * Bug (?)
1472 *
1473 * This has a split personality. We use expression() to read the
1474 * value. We can detect if the value won't fit in a byte or word.
1475 * But we can't detect if expression() discarded significant digits
1476 * in the case of a long. Not worth the crocks required to fix it.
1477 */
1478void
1479cons(nbytes) /* worker to do .byte etc statements */
1480 /* clobbers input_line_pointer, checks */
1481 /* end-of-line. */
1482 register int nbytes; /* 1=.byte, 2=.word, 4=.long */
1483{
1484 register char c;
1485 register long int mask; /* High-order bits we will left-truncate, */
1486 /* but includes sign bit also. */
1487 register long int get; /* what we get */
1488 register long int use; /* get after truncation. */
1489 register long int unmask; /* what bits we will store */
1490 register char * p;
1491 register segT segment;
1492 expressionS exp;
1493#ifdef NS32K
1494 void fix_new_ns32k();
1495#else
1496 void fix_new();
1497#endif
1498
1499 /*
1500 * Input_line_pointer -> 1st char after pseudo-op-code and could legally
1501 * be a end-of-line. (Or, less legally an eof - which we cope with.)
1502 */
1503 /* JF << of >= number of bits in the object is undefined. In particular
1504 SPARC (Sun 4) has problems */
1505 if(nbytes>=sizeof(long int))
1506 mask = 0;
1507 else
1508 mask = ~0 << (BITS_PER_CHAR * nbytes); /* Don't store these bits. */
1509 unmask = ~ mask; /* Do store these bits. */
1510#ifdef NEVER
1511 "Do this mod if you want every overflow check to assume SIGNED 2's complement data.";
1512 mask = ~ (unmask >> 1); /* Includes sign bit now. */
1513#endif
1514 /*
1515 * The following awkward logic is to parse ZERO or more expressions,
1516 * comma seperated. Recall an expression includes its leading &
1517 * trailing blanks. We fake a leading ',' if there is (supposed to
1518 * be) a 1st expression, and keep demanding 1 expression for each ','.
1519 */
1520 if (is_it_end_of_statement())
1521 {
1522 c = 0; /* Skip loop. */
1523 input_line_pointer ++; /* Matches end-of-loop 'correction'. */
1524 }
1525 else
1526 c = ','; /* Do loop. */
1527 while ( c == ',' )
1528 {
1529 segment = expression( &exp ); /* At least scan over the expression. */
1530 if ( ! need_pass_2 )
1531 { /* Still worthwhile making frags. */
1532
1533 /* Don't call this if we are going to junk this pass anyway! */
1534 know( segment != SEG_PASS1 );
1535
1536 if ( segment == SEG_DIFFERENCE && exp . X_add_symbol == NULL )
1537 {
1538 as_warn( "Subtracting symbol \"%s\"(segment\"%s\") is too hard. Absolute segment assumed.",
1539 exp . X_subtract_symbol -> sy_name,
1540 seg_name [(int) N_TYPE_seg [exp . X_subtract_symbol -> sy_type & N_TYPE]]);
1541 segment = SEG_ABSOLUTE;
1542 /* Leave exp . X_add_number alone. */
1543 }
1544 p = frag_more (nbytes);
1545 switch (segment)
1546 {
1547 case SEG_BIG:
1548 as_warn( "%s number illegal. Absolute 0 assumed.",
1549 exp . X_add_number > 0 ? "Bignum" : "Floating-Point");
1550 md_number_to_chars (p, (long)0, nbytes);
1551 break;
1552
1553 case SEG_NONE:
1554 as_warn( "0 assumed for missing expression" );
1555 exp . X_add_number = 0;
1556 know( exp . X_add_symbol == NULL );
1557 /* fall into SEG_ABSOLUTE */
1558 case SEG_ABSOLUTE:
1559 get = exp . X_add_number;
1560 use = get & unmask;
1561 if ( (get & mask) && (get & mask) != mask )
1562 { /* Leading bits contain both 0s & 1s. */
1563 as_warn("Value x%x truncated to x%x.", get, use);
1564 }
1565 md_number_to_chars (p, use, nbytes); /* put bytes in right order. */
1566 break;
1567
1568 case SEG_DIFFERENCE:
1569#ifndef WORKING_DOT_WORD
1570 if(nbytes==2) {
1571 struct broken_word *x;
1572
1573 x=(struct broken_word *)xmalloc(sizeof(struct broken_word));
1574 x->next_broken_word=broken_words;
1575 broken_words=x;
1576 x->frag=frag_now;
1577 x->word_goes_here=p;
1578 x->dispfrag=0;
1579 x->add=exp.X_add_symbol;
1580 x->sub=exp.X_subtract_symbol;
1581 x->addnum=exp.X_add_number;
1582 x->added=0;
1583 new_broken_words++;
1584 break;
1585 }
1586 /* Else Fall through into. . . */
1587#endif
1588 case SEG_BSS:
1589 case SEG_UNKNOWN:
1590 case SEG_TEXT:
1591 case SEG_DATA:
1592#if defined(SPARC) || defined(I860)
1593 fix_new (frag_now, p - frag_now -> fr_literal, nbytes,
1594 exp . X_add_symbol, exp . X_subtract_symbol,
1595 exp . X_add_number, 0, RELOC_32);
1596#endif
1597#ifdef NS32K
1598 fix_new_ns32k (frag_now, p - frag_now -> fr_literal, nbytes,
1599 exp . X_add_symbol, exp . X_subtract_symbol,
1600 exp . X_add_number, 0, 0, 2, 0, 0);
1601#endif
1602#if !defined(SPARC) && !defined(NS32K) && !defined(I860)
1603 fix_new (frag_now, p - frag_now -> fr_literal, nbytes,
1604 exp . X_add_symbol, exp . X_subtract_symbol,
1605 exp . X_add_number, 0);
1606#endif
1607 break;
1608
1609 default:
1610 BAD_CASE( segment );
1611 break;
1612 } /* switch(segment) */
1613 } /* if(!need_pass_2) */
1614 c = * input_line_pointer ++;
1615 } /* while(c==',') */
1616 input_line_pointer --; /* Put terminator back into stream. */
1617 demand_empty_rest_of_line();
1618} /* cons() */
1619\f
1620/*
1621 * big_cons()
1622 *
1623 * CONStruct more frag(s) of .quads, or .octa etc.
1624 * Makes 0 or more new frags.
1625 * If need_pass_2 == TRUE, generate no frag.
1626 * This understands only bignums, not expressions. Cons() understands
1627 * expressions.
1628 *
1629 * Constants recognised are '0...'(octal) '0x...'(hex) '...'(decimal).
1630 *
1631 * This creates objects with struct obstack_control objs, destroying
1632 * any context objs held about a partially completed object. Beware!
1633 *
1634 *
1635 * I think it sucks to have 2 different types of integers, with 2
1636 * routines to read them, store them etc.
1637 * It would be nicer to permit bignums in expressions and only
1638 * complain if the result overflowed. However, due to "efficiency"...
1639 */
1640void
1641big_cons(nbytes) /* worker to do .quad etc statements */
1642 /* clobbers input_line_pointer, checks */
1643 /* end-of-line. */
1644 register int nbytes; /* 8=.quad 16=.octa ... */
1645{
1646 register char c; /* input_line_pointer -> c. */
1647 register int radix;
1648 register long int length; /* Number of chars in an object. */
1649 register int digit; /* Value of 1 digit. */
1650 register int carry; /* For multi-precision arithmetic. */
1651 register int work; /* For multi-precision arithmetic. */
1652 register char * p; /* For multi-precision arithmetic. */
1653
1654 extern char hex_value[]; /* In hex_value.c. */
1655
1656 /*
1657 * The following awkward logic is to parse ZERO or more strings,
1658 * comma seperated. Recall an expression includes its leading &
1659 * trailing blanks. We fake a leading ',' if there is (supposed to
1660 * be) a 1st expression, and keep demanding 1 expression for each ','.
1661 */
1662 if (is_it_end_of_statement())
1663 {
1664 c = 0; /* Skip loop. */
1665 }
1666 else
1667 {
1668 c = ','; /* Do loop. */
1669 -- input_line_pointer;
1670 }
1671 while (c == ',')
1672 {
1673 ++ input_line_pointer;
1674 SKIP_WHITESPACE();
1675 c = * input_line_pointer;
1676 /* C contains 1st non-blank character of what we hope is a number. */
1677 if (c == '0')
1678 {
1679 c = * ++ input_line_pointer;
1680 if (c == 'x' || c=='X')
1681 {
1682 c = * ++ input_line_pointer;
1683 radix = 16;
1684 }
1685 else
1686 {
1687 radix = 8;
1688 }
1689 }
1690 else
1691 {
1692 radix = 10;
1693 }
1694 /*
1695 * This feature (?) is here to stop people worrying about
1696 * mysterious zero constants: which is what they get when
1697 * they completely omit digits.
1698 */
1699 if (hex_value[c] >= radix)
1700 {
1701 as_warn( "Missing digits. 0 assumed." );
1702 }
1703 bignum_high = bignum_low - 1; /* Start constant with 0 chars. */
1704 for( ; (digit = hex_value [c]) < radix; c = * ++ input_line_pointer)
1705 {
1706 /* Multiply existing number by radix, then add digit. */
1707 carry = digit;
1708 for (p=bignum_low; p <= bignum_high; p++)
1709 {
1710 work = (*p & MASK_CHAR) * radix + carry;
1711 *p = work & MASK_CHAR;
1712 carry = work >> BITS_PER_CHAR;
1713 }
1714 if (carry)
1715 {
1716 grow_bignum();
1717 * bignum_high = carry & MASK_CHAR;
1718 know( (carry & ~ MASK_CHAR) == 0);
1719 }
1720 }
1721 length = bignum_high - bignum_low + 1;
1722 if (length > nbytes)
1723 {
1724 as_warn( "Most significant bits truncated in integer constant." );
1725 }
1726 else
1727 {
1728 register long int leading_zeroes;
1729
1730 for(leading_zeroes = nbytes - length;
1731 leading_zeroes;
1732 leading_zeroes --)
1733 {
1734 grow_bignum();
1735 * bignum_high = 0;
1736 }
1737 }
1738 if (! need_pass_2)
1739 {
1740 p = frag_more (nbytes);
1741 bcopy (bignum_low, p, (int)nbytes);
1742 }
1743 /* C contains character after number. */
1744 SKIP_WHITESPACE();
1745 c = * input_line_pointer;
1746 /* C contains 1st non-blank character after number. */
1747 }
1748 demand_empty_rest_of_line();
1749} /* big_cons() */
1750
1751static void
1752grow_bignum() /* Extend bignum by 1 char. */
1753{
1754 register long int length;
1755
1756 bignum_high ++;
1757 if (bignum_high >= bignum_limit)
1758 {
1759 length = bignum_limit - bignum_low;
1760 bignum_low = xrealloc (bignum_low, length + length);
1761 bignum_high = bignum_low + length;
1762 bignum_limit = bignum_low + length + length;
1763 }
1764} /* grow_bignum(); */
1765\f
1766/*
1767 * float_cons()
1768 *
1769 * CONStruct some more frag chars of .floats .ffloats etc.
1770 * Makes 0 or more new frags.
1771 * If need_pass_2 == TRUE, no frags are emitted.
1772 * This understands only floating literals, not expressions. Sorry.
1773 *
1774 * A floating constant is defined by atof_generic(), except it is preceded
1775 * by 0d 0f 0g or 0h. After observing the STRANGE way my BSD AS does its
1776 * reading, I decided to be incompatible. This always tries to give you
1777 * rounded bits to the precision of the pseudo-op. Former AS did premature
1778 * truncatation, restored noisy bits instead of trailing 0s AND gave you
1779 * a choice of 2 flavours of noise according to which of 2 floating-point
1780 * scanners you directed AS to use.
1781 *
1782 * In: input_line_pointer -> whitespace before, or '0' of flonum.
1783 *
1784 */
1785
1786void /* JF was static, but can't be if VAX.C is goning to use it */
1787float_cons(float_type) /* Worker to do .float etc statements. */
1788 /* Clobbers input_line-pointer, checks end-of-line. */
1789 register float_type; /* 'f':.ffloat ... 'F':.float ... */
1790{
1791 register char * p;
1792 register char c;
1793 int length; /* Number of chars in an object. */
1794 register char * err; /* Error from scanning floating literal. */
1795 char temp [MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT];
1796
1797 /*
1798 * The following awkward logic is to parse ZERO or more strings,
1799 * comma seperated. Recall an expression includes its leading &
1800 * trailing blanks. We fake a leading ',' if there is (supposed to
1801 * be) a 1st expression, and keep demanding 1 expression for each ','.
1802 */
1803 if (is_it_end_of_statement())
1804 {
1805 c = 0; /* Skip loop. */
1806 ++ input_line_pointer; /* -> past termintor. */
1807 }
1808 else
1809 {
1810 c = ','; /* Do loop. */
1811 }
1812 while (c == ',')
1813 {
1814 /* input_line_pointer -> 1st char of a flonum (we hope!). */
1815 SKIP_WHITESPACE();
1816 /* Skip any 0{letter} that may be present. Don't even check if the
1817 * letter is legal. Someone may invent a "z" format and this routine
1818 * has no use for such information. Lusers beware: you get
1819 * diagnostics if your input is ill-conditioned.
1820 */
1821
1822 if(input_line_pointer[0]=='0' && isalpha(input_line_pointer[1]))
1823 input_line_pointer+=2;
1824
1825 err = md_atof (float_type, temp, &length);
1826 know( length <= MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT);
1827 know( length > 0 );
1828 if (* err)
1829 {
1830 as_warn( "Bad floating literal: %s", err);
1831 ignore_rest_of_line();
1832 /* Input_line_pointer -> just after end-of-line. */
1833 c = 0; /* Break out of loop. */
1834 }
1835 else
1836 {
1837 if ( ! need_pass_2)
1838 {
1839 p = frag_more (length);
1840 bcopy (temp, p, length);
1841 }
1842 SKIP_WHITESPACE();
1843 c = * input_line_pointer ++;
1844 /* C contains 1st non-white character after number. */
1845 /* input_line_pointer -> just after terminator (c). */
1846 }
1847 }
1848 -- input_line_pointer; /* -> terminator (is not ','). */
1849 demand_empty_rest_of_line();
1850} /* float_cons() */
1851\f
1852/*
1853 * stringer()
1854 *
1855 * We read 0 or more ',' seperated, double-quoted strings.
1856 *
1857 * Caller should have checked need_pass_2 is FALSE because we don't check it.
1858 */
1859static void
1860stringer(append_zero) /* Worker to do .ascii etc statements. */
1861 /* Checks end-of-line. */
1862 register int append_zero; /* 0: don't append '\0', else 1 */
1863{
1864 /* register char * p; JF unused */
1865 /* register int length; JF unused */ /* Length of string we read, excluding */
1866 /* trailing '\0' implied by closing quote. */
1867 /* register char * where; JF unused */
1868 /* register fragS * fragP; JF unused */
1869 register int c;
1870
1871 /*
1872 * The following awkward logic is to parse ZERO or more strings,
1873 * comma seperated. Recall a string expression includes spaces
1874 * before the opening '\"' and spaces after the closing '\"'.
1875 * We fake a leading ',' if there is (supposed to be)
1876 * a 1st, expression. We keep demanding expressions for each
1877 * ','.
1878 */
1879 if (is_it_end_of_statement())
1880 {
1881 c = 0; /* Skip loop. */
1882 ++ input_line_pointer; /* Compensate for end of loop. */
1883 }
1884 else
1885 {
1886 c = ','; /* Do loop. */
1887 }
1888 for ( ; c == ','; c = *input_line_pointer ++)
1889 {
1890 SKIP_WHITESPACE();
1891 if (* input_line_pointer == '\"')
1892 {
1893 ++ input_line_pointer; /* -> 1st char of string. */
1894 while ( (c = next_char_of_string()) >= 0)
1895 {
1896 FRAG_APPEND_1_CHAR( c );
1897 }
1898 if (append_zero)
1899 {
1900 FRAG_APPEND_1_CHAR( 0 );
1901 }
1902 know( input_line_pointer [-1] == '\"' );
1903 }
1904 else
1905 {
1906 as_warn( "Expected \"-ed string" );
1907 }
1908 SKIP_WHITESPACE();
1909 }
1910 -- input_line_pointer;
1911 demand_empty_rest_of_line();
1912} /* stringer() */
1913\f
1914static int
1915next_char_of_string ()
1916{
1917 register int c;
1918
1919 c = * input_line_pointer ++;
1920 switch (c)
1921 {
1922 case '\"':
1923 c = -1;
1924 break;
1925
1926 case '\\':
1927 switch (c = * input_line_pointer ++)
1928 {
1929 case 'b':
1930 c = '\b';
1931 break;
1932
1933 case 'f':
1934 c = '\f';
1935 break;
1936
1937 case 'n':
1938 c = '\n';
1939 break;
1940
1941 case 'r':
1942 c = '\r';
1943 break;
1944
1945 case 't':
1946 c = '\t';
1947 break;
1948
1949 case '\\':
1950 case '"':
1951 break; /* As itself. */
1952
1953 case '0':
1954 case '1':
1955 case '2':
1956 case '3':
1957 case '4':
1958 case '5':
1959 case '6':
1960 case '7':
1961 case '8':
1962 case '9':
1963 {
1964 long int number;
1965
1966 for (number = 0; isdigit(c); c = * input_line_pointer ++)
1967 {
1968 number = number * 8 + c - '0';
1969 }
1970 c = number;
1971 }
1972 -- input_line_pointer;
1973 break;
1974
1975 case '\n':
1976/* as_fatal( "Unterminated string - use app!" ); */
1977/* To be compatible with BSD 4.2 as: give the luser a linefeed!! */
1978 c = '\n';
1979 break;
1980
1981 default:
1982 as_warn( "Bad escaped character in string, '?' assumed" );
1983 c = '?';
1984 break;
1985 }
1986 break;
1987
1988 default:
1989 break;
1990 }
1991 return (c);
1992}
1993\f
1994static segT
1995get_segmented_expression ( expP )
1996 register expressionS * expP;
1997{
1998 register segT retval;
1999
2000 if ( (retval = expression( expP )) == SEG_PASS1 || retval == SEG_NONE || retval == SEG_BIG )
2001 {
2002 as_warn("Expected address expression: absolute 0 assumed");
2003 retval = expP -> X_seg = SEG_ABSOLUTE;
2004 expP -> X_add_number = 0;
2005 expP -> X_add_symbol = expP -> X_subtract_symbol = 0;
2006 }
2007 return (retval); /* SEG_ ABSOLUTE,UNKNOWN,DATA,TEXT,BSS */
2008}
2009
2010static segT
2011get_known_segmented_expression ( expP )
2012 register expressionS * expP;
2013{
2014 register segT retval;
2015 register char * name1;
2016 register char * name2;
2017
2018 if ( (retval = get_segmented_expression (expP)) == SEG_UNKNOWN
2019 )
2020 {
2021 name1 = expP -> X_add_symbol ? expP -> X_add_symbol -> sy_name : "";
2022 name2 = expP -> X_subtract_symbol ? expP -> X_subtract_symbol -> sy_name : "";
2023 if ( name1 && name2 )
2024 {
2025 as_warn("Symbols \"%s\" \"%s\" are undefined: absolute 0 assumed.",
2026 name1, name2);
2027 }
2028 else
2029 {
2030 as_warn("Symbol \"%s\" undefined: absolute 0 assumed.",
2031 name1 ? name1 : name2);
2032 }
2033 retval = expP -> X_seg = SEG_ABSOLUTE;
2034 expP -> X_add_number = 0;
2035 expP -> X_add_symbol = expP -> X_subtract_symbol = NULL;
2036 }
2037 know( retval == SEG_ABSOLUTE || retval == SEG_DATA || retval == SEG_TEXT || retval == SEG_BSS || retval == SEG_DIFFERENCE );
2038 return (retval);
2039} /* get_known_segmented_expression() */
2040
2041
2042
2043/* static */ long int /* JF was static, but can't be if the MD pseudos are to use it */
2044get_absolute_expression ()
2045{
2046 expressionS exp;
2047 register segT s;
2048
2049 if ( (s = expression(& exp)) != SEG_ABSOLUTE )
2050 {
2051 if ( s != SEG_NONE )
2052 {
2053 as_warn( "Bad Absolute Expression, absolute 0 assumed.");
2054 }
2055 exp . X_add_number = 0;
2056 }
2057 return (exp . X_add_number);
2058}
2059
2060static char /* return terminator */
2061get_absolute_expression_and_terminator( val_pointer)
2062 long int * val_pointer; /* return value of expression */
2063{
2064 * val_pointer = get_absolute_expression ();
2065 return ( * input_line_pointer ++ );
2066}
2067\f
2068/*
2069 * demand_copy_C_string()
2070 *
2071 * Like demand_copy_string, but return NULL if the string contains any '\0's.
2072 * Give a warning if that happens.
2073 */
2074static char *
2075demand_copy_C_string (len_pointer)
2076 int * len_pointer;
2077{
2078 register char * s;
2079
2080 if (s = demand_copy_string (len_pointer))
2081 {
2082 register int len;
2083
2084 for (len = * len_pointer;
2085 len > 0;
2086 len--)
2087 {
2088 if (* s == 0)
2089 {
2090 s = 0;
2091 len = 1;
2092 * len_pointer = 0;
2093 as_warn( "This string may not contain \'\\0\'" );
2094 }
2095 }
2096 }
2097 return (s);
2098}
2099\f
2100/*
2101 * demand_copy_string()
2102 *
2103 * Demand string, but return a safe (=private) copy of the string.
2104 * Return NULL if we can't read a string here.
2105 */
2106static char *
2107demand_copy_string (lenP)
2108 int * lenP;
2109{
2110 register int c;
2111 register int len;
2112 char * retval;
2113
2114 len = 0;
2115 SKIP_WHITESPACE();
2116 if (* input_line_pointer == '\"')
2117 {
2118 input_line_pointer ++; /* Skip opening quote. */
2119 while ( (c = next_char_of_string()) >= 0 ) {
2120 obstack_1grow ( &notes, c );
2121 len ++;
2122 }
2123 /* JF this next line is so demand_copy_C_string will return a null
2124 termanated string. */
2125 obstack_1grow(&notes,'\0');
2126 retval=obstack_finish( &notes);
2127 } else {
2128 as_warn( "Missing string" );
2129 retval = NULL;
2130 ignore_rest_of_line ();
2131 }
2132 * lenP = len;
2133 return (retval);
2134}
2135\f
2136/*
2137 * is_it_end_of_statement()
2138 *
2139 * In: Input_line_pointer -> next character.
2140 *
2141 * Do: Skip input_line_pointer over all whitespace.
2142 *
2143 * Out: TRUE if input_line_pointer -> end-of-line.
2144 */
2145static int
2146is_it_end_of_statement()
2147{
2148 SKIP_WHITESPACE();
2149 return (is_end_of_line [* input_line_pointer]);
2150}
2151
2152void
2153equals(sym_name)
2154char *sym_name;
2155{
2156 register struct symbol * symbolP; /* symbol we are working with */
2157
2158 input_line_pointer++;
2159 if(*input_line_pointer=='=')
2160 input_line_pointer++;
2161
2162 while(*input_line_pointer==' ' || *input_line_pointer=='\t')
2163 input_line_pointer++;
2164
2165 if(sym_name[0]=='.' && sym_name[1]=='\0') {
2166 /* Turn '. = mumble' into a .org mumble */
2167 register segT segment;
2168 expressionS exp;
2169 register char *p;
2170
2171 segment = get_known_segmented_expression(& exp);
2172 if ( ! need_pass_2 ) {
2173 if (segment != now_seg && segment != SEG_ABSOLUTE)
2174 as_warn("Illegal segment \"%s\". Segment \"%s\" assumed.",
2175 seg_name [(int) segment], seg_name [(int) now_seg]);
2176 p = frag_var (rs_org, 1, 1, (relax_substateT)0, exp.X_add_symbol,
2177 exp.X_add_number, (char *)0);
2178 * p = 0;
2179 } /* if (ok to make frag) */
2180 } else {
2181 symbolP=symbol_find_or_make(sym_name);
2182 pseudo_set(symbolP);
2183 }
2184}
2185
2186/* end: read.c */