home *** CD-ROM | disk | FTP | other *** search
- /* read.c - read a source file -
- Copyright (C) 1986,1987 Free Software Foundation, Inc.
-
- This file is part of GAS, the GNU Assembler.
-
- GAS is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 1, or (at your option)
- any later version.
-
- GAS is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GAS; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- #define MASK_CHAR (0xFF) /* If your chars aren't 8 bits, you will
- change this a bit. But then, GNU isn't
- spozed to run on your machine anyway.
- (RMS is so shortsighted sometimes.)
- */
-
- #define MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT (16)
- /* This is the largest known floating point */
- /* format (for now). It will grow when we */
- /* do 4361 style flonums. */
-
-
- /* Routines that read assembler source text to build spagetti in memory. */
- /* Another group of these functions is in the as-expr.c module */
-
- #include <ctype.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include "as.h"
- #include "read.h"
- #include "md.h"
- #include "hash.h"
- #include "obstack.h"
- #include "frags.h"
- #include "flonum.h"
- #include "struc-symbol.h"
- #include "expr.h"
- #include "symbols.h"
-
- #ifdef SPARC
- #include "sparc.h"
- #endif
-
- #ifdef M88K
- #include "m88k.h"
- #endif
-
- #ifdef M98K
- #include "m98k.h"
- #endif
-
- #ifdef I860
- #include "i860.h"
- #endif I860
-
- char * input_line_pointer; /* -> next char of source file to parse. */
-
-
- #if BITS_PER_CHAR != 8
- The following table is indexed by [ (char) ] and will break if
- a char does not have exactly 256 states (hopefully 0:255!) !
- #endif
-
- const
- char /* used by is_... macros. our ctype[] */
- lex_type [256] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ABCDEFGHIJKLMNO */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* PQRSTUVWXYZ[\]^_ */
- 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, /* _!"#$%&'()*+,-./ */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0123456789:;<=>? */
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* @ABCDEFGHIJKLMNO */
- #ifdef NeXT
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, /* PQRSTUVWXYZ[\]^_ */
- #else !defined(NeXT)
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, /* PQRSTUVWXYZ[\]^_ */
- #endif NeXT
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* `abcdefghijklmno */
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, /* pqrstuvwxyz{|}~. */
- #ifdef NeXT
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* allow all chars */
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* with the high bit */
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* set in names */
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
- #else !defined(NeXT)
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- #endif NeXT
- };
-
-
- /*
- * In: a character.
- * Out: TRUE if this character ends a line.
- */
- #define _ (0)
- const
- char is_end_of_line [256] = {
- _, _, _, _, _, _, _, _, _, _,99, _, _, _, _, _, /* @abcdefghijklmno */
- _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
- _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
- _, _, _, _, _, _, _, _, _, _, _,99, _, _, _, _, /* 0123456789:;<=>? */
- #if defined(M88K) || defined(M98K)
- 99, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* @ABCDEFGHIJKLMNO */
- #else
- _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
- #endif
- _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
- _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
- _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
- _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
- _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
- _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
- _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
- _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ /* */
- };
- #undef _
-
- #ifdef NeXT /* the conditional assembly feature (.if, .else, and .endif) */
- /* DJA -- added conditionals. cond_state tells us what we are in
- * the middle of processing. ignore can be either TRUE or FALSE. When
- * TRUE we are ignoring the block of code in the middle of a conditional.
- * MAX_IF_DEPTH is the maximum depth that if's can be nested.
- */
-
- #define MAX_IF_DEPTH 20
- typedef enum
- {
- no_cond, /* no conditional is being processed */
- if_cond, /* inside if conditional */
- elseif_cond, /* inside elseif conditional */
- else_cond /* inside else conditional */
- } cond_type;
- struct cond_state
- {
- cond_type the_cond;
- int cond_met;
- int ignore;
- };
- typedef struct cond_state cond_stateS;
- static cond_stateS the_cond_state = {no_cond, FALSE, FALSE};
- static cond_stateS last_states[MAX_IF_DEPTH];
- static int if_depth = 0;
- void totally_ignore_line();
- #endif NeXT /* the conditional assembly feature (.if, .else, and .endif) */
-
- #ifdef NeXT /* the .macro feature */
- static struct hash_control
- *ma_hash = NULL; /* use before set up: NULL-> address error */
- static struct obstack macros; /* obstack for macro text */
- static char *macro_name = NULL; /* name of macro we are defining */
- static int count_lines = TRUE; /* turns line number counting on and off */
- extern void add_to_macro_definition();
- static void expand_macro();
- static void ma_begin();
- static int macros_on = TRUE; /* .macros_on and .macros_off toggles this to
- allow macros to be turned off, which allows
- macros to override a machine instruction and
- still use it. */
- #define MAX_MACRO_DEPTH 20
- static int macro_depth = 0;
- #endif NeXT /* the .macro feature */
-
- #ifdef NeXT /* the .dump/.load feature */
- /*
- * DJA -- Used for .dump and .load
- */
- static FILE * dump_fp;
- extern struct hash_control * sy_hash;
- #endif NeXT /* the .dump/.load feature */
-
- /* Functions private to this file. */
- #ifdef NeXT
- static void parse_a_buffer();
- static void parse_line_comment();
- #endif NeXT
- void equals();
- void big_cons();
- void cons();
- static char* demand_copy_C_string();
- static char* demand_copy_string();
- void demand_empty_rest_of_line();
- void float_cons();
- long int get_absolute_expression();
- static char get_absolute_expression_and_terminator();
- #ifdef I860
- segT get_known_segmented_expression();
- #else !defined(I860)
- static segT get_known_segmented_expression();
- #endif I860
- void ignore_rest_of_line();
- static int is_it_end_of_statement();
- static void pobegin();
- static void pseudo_set();
- static void stab();
- #ifdef I860
- void stringer();
- #else !defined(I860)
- static void stringer();
- #endif I860
-
- extern char line_comment_chars[];
-
- #ifdef NeXT /* .include feature */
- extern int doing_include;
- /*
- * DJA -- This variable is not static so read_an_include_file can save
- * and restore it.
- */
- char * buffer_limit; /* -> 1 + last char in buffer. */
- #else NeXT /* .include feature */
- static char * buffer_limit; /* -> 1 + last char in buffer. */
- #endif NeXT /* .include feature */
-
- static char * bignum_low; /* Lowest char of bignum. */
- static char * bignum_limit; /* 1st illegal address of bignum. */
- static char * bignum_high; /* Highest char of bignum. */
- /* May point to (bignum_start-1). */
- /* Never >= bignum_limit. */
- #ifndef NeXT /* hack cleaned up see parse_line_comment() */
- static char *old_buffer = 0; /* JF a hack */
- static char *old_input;
- static char *old_limit;
- #endif NeXT /* hack cleaned up see parse_line_comment() */
-
- #ifndef WORKING_DOT_WORD
- struct broken_word *broken_words;
- int new_broken_words = 0;
- #endif
-
- static void grow_bignum ();
- static int next_char_of_string ();
-
- void
- read_begin()
- {
- pobegin();
- #ifdef NeXT /* the .macro feature */
- ma_begin();
- #endif NeXT /* the .macro feature */
- obstack_begin( ¬es, 5000 );
- #define BIGNUM_BEGIN_SIZE (16)
- bignum_low = xmalloc((long)BIGNUM_BEGIN_SIZE);
- bignum_limit = bignum_low + BIGNUM_BEGIN_SIZE;
- }
-
- /* set up pseudo-op tables */
-
- static struct hash_control *
- po_hash = NULL; /* use before set up: NULL-> address error */
-
-
- void s_abort(), s_align(), s_comm(), s_data();
- void s_desc(), s_even(), s_file(), s_fill();
- void s_globl(), s_lcomm(), s_line(), s_lsym();
- void s_org(), s_set(), s_space(), s_text();
- #ifdef NeXT
- void s_reference(), s_include(), s_dump(), s_load();
- void s_if(), s_elseif(), s_else(), s_endif();
- void s_macro(), s_endmacro(), s_macros_on(), s_macros_off();
- void s_abs();
- #endif NeXT
-
- #ifdef DONTDEF
- void s_gdbline(), s_gdblinetab();
- void s_gdbbeg(), s_gdbblock(), s_gdbend(), s_gdbsym();
- #endif
-
- void stringer();
- void cons();
- void float_cons();
- void big_cons();
- void stab();
-
- #ifdef Mach_O
- void s_text_Mach_O(),s_data_Mach_O();
- #endif Mach_O
-
- const
- static pseudo_typeS
- potable[] =
- {
- { "abort", s_abort, 0 },
- #if !defined(I860) /* i860 has it's own align syntax */
- { "align", s_align, 0 },
- #endif !defined(I860)
- { "ascii", stringer, 0 },
- { "asciz", stringer, 1 },
- { "byte", cons, 1 },
- { "comm", s_comm, 0 },
- { "data", s_data, 0 },
- { "desc", s_desc, 0 },
- { "double", float_cons, 'd' },
- { "file", s_file, 0 },
- { "fill", s_fill, 0 },
- #ifdef NeXT
- /* At NeXT we allow .float only on the 68k machines and the i860 */
- #if defined(M68K) || defined(I860)
- { "float", float_cons, 'f' },
- #endif defined(M68K) || defined(I860)
- #endif NeXT
- #ifdef DONTDEF
- { "gdbbeg", s_gdbbeg, 0 },
- { "gdbblock", s_gdbblock, 0 },
- { "gdbend", s_gdbend, 0 },
- { "gdbsym", s_gdbsym, 0 },
- { "gdbline", s_gdbline, 0 },
- { "gdblinetab",s_gdblinetab, 0 },
- #endif
- { "globl", s_globl, 0 },
- #ifdef NeXT
- /* At NeXT we allow .int only on the 68k and i860 machines */
- #if defined(M68K) || defined(I860)
- { "int", cons, 4 },
- #endif defined(M68K) || defined(I860)
- #endif NeXT
- { "lcomm", s_lcomm, 0 },
- { "line", s_line, 0 },
- { "long", cons, 4 },
- #ifdef NeXT
- /* At NeXT we allow .quad and .octa only on the 68k machines */
- #ifdef M68K
- { "quad", big_cons, 8 },
- { "octa", big_cons, 16 },
- #endif M68K
- #endif NeXT
- { "lsym", s_lsym, 0 },
- #if !defined(I860)
- { "org", s_org, 0 },
- #endif !defined(I860)
- { "set", s_set, 0 },
- { "short", cons, 2 },
- { "single", float_cons, 'f' },
- { "space", s_space, 0 },
- { "stabd", stab, 'd' },
- { "stabn", stab, 'n' },
- { "stabs", stab, 's' },
- { "text", s_text, 0 },
- #ifdef NeXT
- /* At NeXT we allow .word only on the 68k machines, i386 machines, and the
- i860 where we don't ship the assembler */
- #if defined(M68K) || defined(I386)
- #ifndef RISC
- /* A "word" according to 386, 68k, and 32k is just 16 bits.
- On 88k and sparc it's 32 bits. */
- { "word", cons, 2 },
- #endif RISC
- #endif defined(M68K) || defined(I386)
- #endif NeXT
-
- #ifdef NeXT
- { "reference",s_reference, 0 },
- { "include", s_include, 0 },
- { "macro", s_macro, 0 },
- { "endmacro", s_endmacro, 0 },
- { "if", s_if, 0 },
- { "elseif", s_elseif, 0 },
- { "else", s_else, 0 },
- { "endif", s_endif, 0 },
- { "dump", s_dump, 0 },
- { "load", s_load, 0 },
- #ifndef M88K
- { "abs", s_abs, 0 },
- #endif !defined(M88K)
- { "macros_on", s_macros_on, 0 },
- { "macros_off", s_macros_off, 0 },
- #endif NeXT
- #ifdef Mach_O
- /*
- * The sub-segment numbers here must agree with what is in Mach-O.c .
- * I see no easy way to avoid this and of course I would rather have
- * arbitrary Mach-O sections.
- */
- /* text sub-segments */
- { "const", s_text_Mach_O, 1 },
- { "static_const", s_text_Mach_O, 2 },
- { "cstring", s_text_Mach_O, 3 },
- { "literal4", s_text_Mach_O, 4 },
- { "literal8", s_text_Mach_O, 5 },
- { "constructor", s_text_Mach_O, 6 },
- { "destructor", s_text_Mach_O, 7 },
- { "fvmlib_init0", s_text_Mach_O, 8 },
- { "fvmlib_init1", s_text_Mach_O, 9 },
- /* data sub-segments */
- { "static_data", s_data_Mach_O, 1 },
- { "objc_class", s_data_Mach_O, 2 },
- { "objc_meta_class", s_data_Mach_O, 3 },
- { "objc_string_object", s_data_Mach_O, 4 },
- { "objc_protocol", s_data_Mach_O, 5 },
- { "objc_cat_cls_meth", s_data_Mach_O, 6 },
- { "objc_cat_inst_meth", s_data_Mach_O, 7 },
- { "objc_cls_meth", s_data_Mach_O, 8 },
- { "objc_inst_meth", s_data_Mach_O, 9 },
- { "objc_message_refs", s_data_Mach_O, 10 },
- { "objc_selector_refs", s_data_Mach_O, 10 },
- { "objc_cls_refs", s_data_Mach_O, 11 },
- { "objc_class_names", s_data_Mach_O, 12 },
- { "objc_module_info", s_data_Mach_O, 13 },
- { "objc_symbols", s_data_Mach_O, 14 },
- { "objc_category", s_data_Mach_O, 15 },
- { "objc_meth_var_types", s_data_Mach_O, 16 },
- { "objc_class_vars", s_data_Mach_O, 17 },
- { "objc_instance_vars", s_data_Mach_O, 18 },
- { "objc_meth_var_names", s_data_Mach_O, 19 },
- { "objc_selector_strs", s_data_Mach_O, 20 },
- #endif
- { NULL} /* end sentinel */
- };
-
- static void
- pobegin()
- {
- char * errtxt; /* error text */
- const pseudo_typeS * pop;
-
- po_hash = hash_new();
- errtxt = ""; /* OK so far */
- for (pop=(pseudo_typeS *)potable; pop->poc_name && !*errtxt; pop++)
- {
- errtxt = hash_insert (po_hash, pop->poc_name, (char *)pop);
- }
-
- for(pop=md_pseudo_table; pop->poc_name && !*errtxt; pop++)
- errtxt = hash_insert (po_hash, pop->poc_name, (char *)pop);
-
- if (*errtxt)
- {
- #ifdef NeXT
- as_fatal ("error constructing pseudo-op table (%s)", errtxt);
- #else !defined(NeXT)
- as_fatal ("error constructing pseudo-op table");
- #endif NeXT
- }
- } /* pobegin() */
-
- /*
- * The NeXT version of: read_a_source_file()
- *
- * This differs from the GNU version by taking the guts of the GNU
- * read_a_source_file() (with the outer most loop removed) and renaming it
- * parse_a_buffer(). With the NeXT version of read_a_source file simply
- * containing that outer loop and a call to parse_a_buffer(). This is done
- * So that expand_macro() and parse_line_comment() can call parse_a_buffer()
- * with the buffers they create.
- */
- void
- read_a_source_file (buffer)
- char *buffer; /* 1st character of each buffer of lines is here. */
- {
- cond_stateS starting_cond_state;
- short starting_if_depth;
-
- extern char *physical_input_file;
- symbolS *symbolP;
-
- starting_cond_state = the_cond_state;
- starting_if_depth = if_depth;
-
- /* Do not change segments or subsegments if this is a .include */
- if(doing_include == FALSE){
- subseg_new(SEG_TEXT, 0);
- /*
- * If the -g flag is present generate the lead stabs for this
- * physical file that is not an include file. Each physical file's
- * stabs are enclosed by a pair of source name stabs, N_SO, (one at
- * the begining of the file with the name of the file and one at the
- * end with the name ""). This is seen by nm(1) as:
- * 00000000 - 01 0000 SO {standard input}
- * ...
- * 00000020 - 01 0000 SO
- * To make the debugger work line numbers stabs, N_SLINE, must be
- * contained "in a function" (after a function stab, N_FUN). To
- * make a function stab work it must have a type number. Since type
- * numbers 1 and 2 (the 1 in "int:t1=..." and the 2 in "char:t2=..."
- * are "magic" to the debugger we use type 3 for the types of the
- * function stabs we generate for each text label (see the routine
- * make_stab_for_symbol() in symbols.c). So at lead stabs at the
- * begining of each physical file include three type stabs, L_LSYM
- * with the correct symbol name. The since we must have the types
- * 1 and 2 they are just what the 'C' would produce but we don't
- * use them. Type 3 is the void type like the 'C' compiler would
- * produce which we use for the function stabs' type. These three
- * look like this to nm(1):
- * 00000000 - 00 0000 LSYM int:t1=r1;-2147483648;2147483647;
- * 00000000 - 00 0000 LSYM char:t2=r2;0;127;
- * 00000000 - 00 0000 LSYM void:t3=3
- *
- * Then for each text label we see, make_stab_for_symbol() will
- * generate a stab like this (for the example lable _main):
- * 00000000 - 01 0007 FUN _main:F3
- * where the 'F' in F3 is an upper case 'F' for global labels and
- * a lower case 'f' for non globals.
- *
- * Then for each instruction we assemble in the text we generate
- * a line number, S_LINE, stab (see md_assembler in m68k.c, m88k.c
- * etc). These look like:
- * 00000000 - 01 0008 SLINE
- * where the 0008 is the line number.
- */
- if(flagseen['g']){
- symbolP = symbol_new(
- physical_input_file,
- 100 /* N_SO */,
- seg_n_sect(now_seg, now_subseg),
- 0,
- obstack_next_free(&frags) - frag_now->fr_literal,
- frag_now);
- symbolP = symbol_new(
- "int:t1=r1;-2147483648;2147483647;",
- 128 /* N_LSYM */,
- 0,0,0,
- &zero_address_frag);
- symbolP = symbol_new(
- "char:t2=r2;0;127;",
- 128 /* N_LSYM */,
- 0,0,0,
- &zero_address_frag);
- symbolP = symbol_new(
- "void:t3=3",
- 128 /* N_LSYM */,
- 0,0,0,
- &zero_address_frag);
- }
- }
- else{
- /*
- * If we are now reading an include file we will bracket it's
- * stabs with a pair of:
- * 00000010 - 01 0000 SOL include_file
- * ...
- * 0000001c - 01 0000 SOL previous_file
- * We generate the first N_SOL here and the one for the
- * previous_file in s_include() in read.c.
- *
- * CAVAT: This will only work if the include file starts off in the
- * (__TEXT,__text) sections and ends in the (__TEXT,__text) section.
- */
- if(flagseen['g'] && now_seg == SEG_TEXT && now_subseg == 0){
- symbolP = symbol_new(
- physical_input_file,
- 132 /* N_SOL */,
- seg_n_sect(now_seg, now_subseg),
- 0,
- obstack_next_free(&frags) - frag_now->fr_literal,
- frag_now);
- }
- }
-
- while((buffer_limit = input_scrub_next_buffer(&buffer)) != NULL)
- parse_a_buffer(buffer);
-
- if(the_cond_state.the_cond != starting_cond_state.the_cond ||
- the_cond_state.ignore != starting_cond_state.ignore||
- if_depth != starting_if_depth)
- as_warn("file contains unmatched .ifs or .elses");
-
- if(doing_include == FALSE){
- /* See the comment at the top of this routine for a description of
- what is going on here */
- subseg_new(SEG_TEXT, 0);
- if(flagseen['g']){
- (void)symbol_new(
- "",
- 100 /* N_SO */,
- seg_n_sect(now_seg, now_subseg),
- 0,
- obstack_next_free(&frags) - frag_now->fr_literal,
- frag_now);
- }
- }
- }
-
- /*
- * NeXT verion of parse_a_buffer() operates on a buffer of lines. It drives the
- * parsing of lines of assembly code. The lines are assumed to be "well formed"
- * assembly so the syntax recognized in here is that produced by the output of
- * the assembly preprocessor (app) or by the compiler when it produces a file
- * that starts with "#NO_APP\n". A "well formed" assembly is lines with exactly
- * zero or one leading "well formed space character" (' ', '\t' or '\f')
- * followed by lines of:
- * zero or more lables (a name or a digit followed by a colon)
- * each followed by zero or one "well formed space character"
- * exactly one of the following followed by a logicial end of line:
- * a pseudo opcode
- * followed by zero or one space (' ') characters and it's
- * arguments (the space is required when the first
- * character of the first argument could be part of a name)
- * a macro to be expanded
- * a machine opcode
- * a null statement
- * an assignment to a symbol
- * a full line comment (in the case of "well formed" assembly it
- * must be "#APP\n" of a collection of lines
- * wrapped in "#APP\n ... #NO_APP\n")
- *
- * input:
- * buffer pointer to the start of the buffer of lines
- * (passed as an argument)
- * buffer_limit pointer to the end of the buffer of lines, that is the
- * the character it points to is NOT part of the buffer
- * (buffer_limit is declared as a static to this file)
- *
- * Assumptions about the buffer of lines:
- * buffer[-1] == '\n' as done in input-scrub.c with the cpp macro
- * BEFORE_STRING ("\n")
- * buffer_limit[-1] == '\n' also as done in input-scrub.c which handles
- * partial lines internally to itself and always
- * passes back a buffer of complete lines.
- *
- * input/output: (for other parsing routines)
- * input_line_pointer pointer to the next thing in the buffer after
- * what has been recognized (a global)
- */
- static
- void
- parse_a_buffer(buffer)
- char *buffer;
- {
- char c; /* contains the first non-space character the current
- word used to figure out what it is */
- char *s; /* points to a name with character after the name
- replaced with a '\0' so it is a 'C' string */
- char after_name; /* contains that first character after a name that
- got replaced with a '\0' */
- char *after_name_pointer;/* points to the end of the name where the '\0' is
- for error use only */
- char end_of_line; /* contains an end of line character that got replaced
- with a '\0' */
- char *start_of_line;/* points to the locical start of line we're parsing,
- used only for macro expansion */
- pseudo_typeS *pop; /* pointer to a pseudo op stucture returned by
- hash_find(po_hash, s+1) to determine if it is one */
- char *the_macro; /* pointer to a macro name returned by
- hash_find(ma_hash, s) to determine if it is one */
- int digit_value; /* the value of a digit label as an integer, 1: == 1 */
-
- /* since this is a buffer of full lines it must end in a new line */
- know(buffer_limit[-1] == '\n');
-
- input_line_pointer = buffer;
-
- /* while we have more of this buffer to parse keep parsing */
- while(input_line_pointer < buffer_limit){
- /*
- * At the top of this loop we know that we just parsed a label or we
- * are at the beginning of a logical line (since their can be more
- * than one label on a line). start_of_line is only used by
- * expand_macro()
- */
- start_of_line = input_line_pointer;
-
- /*
- * If we are not counting lines (as in the case when called by
- * expand_macro() ) and we just previously scaned over a newline
- * (a physical end of line) bump the line counters (see the comments
- * at the head of this routine about "assumptions about the buffer"
- * and why it is safe to index input_line_pointer by -1.
- */
- if(count_lines == TRUE && input_line_pointer[-1] == '\n')
- bump_line_counters ();
-
- /*
- * We expect a "well-formed" assembler statement. This means it was
- * processed by app or produced by a compiler where the file started
- * with a leading "#APP\n". A "well-formed" statement allows zero
- * or one leading white space characters.
- */
- c = *input_line_pointer;
- input_line_pointer++;
- if(c == '\t' || c == ' ' || c=='\f'){
- c = *input_line_pointer;
- input_line_pointer++;
- }
- know(c != ' '); /* No further leading whitespace. */
- /*
- * c contains the 1st significant character, *input_line_pointer
- * points after that character.
- */
-
- /*
- * look for the begining of a name which could be one of the
- * following assembly statements:
- * A pseudo opcode and locical end of line
- * A macro to be expanded and locical end of line
- * A machine opcode and locical end of line
- * A user-defined label (name not digit)(no end of line needed)
- * At NeXT labels can be enclosed in ""'s so that Objective-C like
- * names (with spaces and colons) can be part of a name, the
- * routine get_symbol_end() know about this.
- */
- if(is_name_beginner(c) || c == '"'){
- if( c == '"')
- s = input_line_pointer -- ;
- else
- s = -- input_line_pointer;
- after_name = get_symbol_end(); /* name's delimiter */
- after_name_pointer = input_line_pointer;
- /*
- * after_name is the character after symbol. That character's
- * place in the input line is now '\0',done by get_symbol_end().
- * s points to the beginning of the symbol (in the case of a
- * pseudo-op, *s == '.'). *input_line_pointer == '\0' where
- * after_name was. after_name_pointer is recorded so it their
- * is an error after the line has been restored the '\0' can
- * be reset and the name printed.
- */
-
- /*
- * Look for a name that should be a pseudo op. That is it is
- * not a user defined label or an assignment to a symbol name.
- * This must be done so such thing as ".foo:" and ".bar=1" are
- * not mistaken for illegal pseudo ops and that something like
- * ".long: .long 1" creates a symbol named ".long".
- */
- if(*s == '.' &&
- (after_name != ':' &&
- (after_name != '=' && input_line_pointer[1] != '=') ) ){
- /*
- * Lookup what should be a pseudo op and then restore the
- * line.
- */
- pop = (pseudo_typeS *)hash_find(po_hash, s+1);
- *input_line_pointer = after_name;
-
- /*
- * A pseudo op must be followed by character that is not
- * part of a name so it can be parsed. If their is a first
- * argument that could start with a character in a name then
- * one "well formed space" (space or a tab) must follow the
- * pseudo op (otherwise the space is optional).
- */
- if(after_name == ' ' || after_name == '\t')
- input_line_pointer++;
-
- /*
- * Now the current state of the line is the after_name has
- * been placed back in the line (the line is restored) and
- * input_line_pointer is at the start of the first argument
- * of the pseudo op (if any).
- */
- if(the_cond_state.ignore){
- /*
- * When ignoring a block of code during conditional
- * assembly we can't ignore .if, .else, and .endif
- * pseudo ops.
- */
- if(pop != NULL &&
- ( ((int *)pop->poc_handler == (int *)s_if) ||
- ((int *)pop->poc_handler == (int *)s_elseif) ||
- ((int *)pop->poc_handler == (int *)s_else) ||
- ((int *)pop->poc_handler == (int *)s_endif) ) )
- (*pop->poc_handler)(pop->poc_val);
- else
- totally_ignore_line();
- }
- else if(macro_name){
- /*
- * When defining a macro we can't ignore .endmacro
- * pseudo ops.
- */
- if(pop != NULL &&
- (int *)pop->poc_handler == (int *)s_endmacro)
- (*pop->poc_handler)(pop->poc_val);
- else
- add_to_macro_definition(start_of_line);
- }
- else{
- if(pop != NULL)
- (*pop->poc_handler)(pop->poc_val);
- else{
- after_name = *after_name_pointer;
- *after_name_pointer = '\0';
- /*
- * If macros are on see if this is a use of a macro
- * otherwise it is an unknown pseudo op.
- */
- if(macros_on == TRUE &&
- (the_macro = hash_find(ma_hash, s)) != NULL){
- *after_name_pointer = after_name;
- expand_macro(the_macro);
- }
- else{
- as_warn ("Unknown pseudo-op: %s", s);
- *after_name_pointer = after_name;
- ignore_rest_of_line();
- }
- }
- }
- continue;
-
- } /* if(*s == '.' && ... ) */
-
- /*
- * If we are in a conditional and the state is that we are now
- * not including lines to be assembled then ignore the line.
- */
- if(the_cond_state.ignore){
- *input_line_pointer = after_name;
- totally_ignore_line();
- }
- /*
- * If we are in the state of defining a macro then take the line
- * for the macro definition.
- */
- else if(macro_name != NULL){
- *input_line_pointer = after_name;
- add_to_macro_definition(start_of_line);
- }
- /*
- * Look for a user defined label.
- */
- else if(after_name == ':'){
- colon(s);
- #ifdef I860
- /*
- * Intel :: feature, which makes the label global if
- * followed by two "::"'s . This is ifdef'ed in so their
- * is no else cause thus the slightly odd logic.
- */
- if(input_line_pointer[1] == ':'){
- struct symbol *symbolP;
-
- symbolP = symbol_find_or_make(s);
- symbolP->sy_type |= N_EXT; /* make symbol name global */
- *input_line_pointer = ':'; /* Restore first ':' */
- input_line_pointer++; /* step over first ':' */
- }
- #endif I860
- /* put ':' back for error messages and step over it */
- *input_line_pointer = ':';
- input_line_pointer++;
- SKIP_WHITESPACE();
- }
- /*
- * Parse the assignment to a symbol. The syntax for this is
- * <symbol><equal><expression> where <equal> is either "=" or
- * "?=" where '?' is any character that is not part of a symbol.
- * This allows things like: "x=1" "x =1" "x==1" "x+=1" "x!=1"
- * "x@=1" which all set x to one. This should be cleaned up.
- */
- else if(after_name == '=' || input_line_pointer[1] == '='){
- equals(s);
- demand_empty_rest_of_line();
- }
- /*
- * If macros are on see if this is a use of a macro.
- */
- else if(macros_on == TRUE &&
- (the_macro = hash_find(ma_hash, s)) != NULL){
- *input_line_pointer = after_name;
- expand_macro(the_macro);
- }
- /*
- * Now assume it is a machine instruction and if not it
- * will be handled as an error. Machine instructions must be
- * one to a line.
- */
- else{
- *input_line_pointer = after_name;
- while(is_end_of_line[*input_line_pointer] == FALSE)
- input_line_pointer ++;
- end_of_line = *input_line_pointer;
- *input_line_pointer = '\0';
- md_assemble(s);
- *input_line_pointer = end_of_line;
- input_line_pointer++;
- }
- /*
- * At this point we have parsed all things that could have
- * started with a name. Since one of these things (user defined
- * lables could appear more than once on a line we do a continue
- * here and start parsing as if at the begining of another
- * logicial line.
- */
- continue;
-
- } /* if(is_name_beginner(c) || c == '"') */
-
- /* empty statement */
- if(is_end_of_line[c])
- continue;
-
- /*
- * If we are in a conditional and the state is that we are now
- * not including lines to be assembled then ignore the line.
- */
- if(the_cond_state.ignore){
- totally_ignore_line();
- continue;
- }
-
- /*
- * If we are in the state of defining a macro then take the line
- * for the macro definition.
- */
- if(macro_name != NULL){
- add_to_macro_definition(start_of_line);
- continue;
- }
-
- /* local label ("4:") */
- if(isdigit(c)){
- digit_value = c - '0';
- #ifdef SUN_ASM_SYNTAX
- if(*input_line_pointer == '$')
- input_line_pointer++;
- #endif SUN_ASM_SYNTAX
- if(*input_line_pointer++ == ':' ){
- local_colon(digit_value);
- }
- else{
- as_warn("Spurious digit %d.", digit_value);
- input_line_pointer--;
- ignore_rest_of_line();
- }
- continue;
- }
-
- /*
- * The only full line comment that should make it here is the first
- * of the pair of "#APP\n ... #NO_APP\n" that the compiler uses to
- * wrap around asm() statements. If that is the case then
- * parse_line_comment() creates a buffer with those lines in it and
- * calls parse_a_buffer() with that buffer. Then returns here
- * skiping over that part of the current buffer.
- */
- if(c != '\0' && index(line_comment_chars, c) != NULL){
- parse_line_comment(&buffer);
- continue;
- }
-
- as_warn("Junk character %d.",c);
- ignore_rest_of_line();
-
- } /* while(input_line_pointer < buffer_limit) */
- }
-
- /*
- * parse_line_comment() parses a line comment for parse_a_buffer(). Since
- * parse_a_buffer() only operates on "well formed" assembly the only legal
- * line comment that should appear is a "#APP\n ... #NO_APP\n" pair which
- * tells us to scrub the characters between them and then parse them.
- */
- void
- parse_line_comment(buffer)
- char **buffer;
- {
- char *s;
- char *ends;
-
- char *new_buf;
- char *new_tmp;
- int new_length;
-
- char *tmp_buf;
- char *old_input_line_pointer;
- char *old_buffer_limit;
-
- extern char *strstr();
- extern char *scrub_string, *scrub_last_string;
- extern int scrub_from_string();
- extern void scrub_to_string();
-
- /* parse_a_buffer should never see any line comment if app is on */
- know(preprocess == FALSE);
-
- s = input_line_pointer;
- /* This must be a #APP\n line comment if not ignore it */
- if(strncmp(s,"APP\n",4) != 0)
- return;
-
- if(count_lines == TRUE)
- bump_line_counters();
- s += sizeof("APP\n") - 1;
-
- /*
- * Search for the matching #NO_APP\n in this buffer, if it is found
- * in this buffer the un-scrubed characters between the "#APP\n" and
- * "#NO_APP\n" start where s is pointing to and end where ends is
- * pointing to.
- */
- ends = strstr(s, "#NO_APP\n");
-
- tmp_buf = NULL;
- if(ends == NULL){
- /* The matching #NO_APP\n for the #APP\n wasn't in this buffer. */
- int tmp_len;
- int num;
-
- /*
- * First create a temporary place (tmp_buf of size tmp_len) to
- * collect the un-scrubbed characters between the "#APP\n" and the
- * "#NO_APP\n" (or end of file) when we find it in some buffer.
- */
- tmp_len = buffer_limit - s;
- tmp_buf = xmalloc(tmp_len);
-
- /*
- * Copy the end of the buffer that contains the first part of
- * the un-scrubbed contents starting just after the "#APP\n".
- * This is so the the current buffer (buffer) can be used to
- * collect the the rest of the un-scrubbed contents and to find
- * the matching "#NO_APP\n".
- */
- bcopy(s, tmp_buf, tmp_len);
-
- /*
- * This loop collects the remaining un-scrubed contents between
- * "#APP\n" and the "#NO_APP\n" into tmp_buf (adjusting tmp_len)
- * and looks for the matching "#NO_APP\n".
- */
- do{
- buffer_limit = input_scrub_next_buffer(buffer);
- /*
- * We treat runing into the end of the file as if it was the
- * "#NO_APP" we were looking for.
- */
- if(buffer_limit == NULL)
- break;
-
- ends = strstr(*buffer, "#NO_APP\n");
- if(ends != NULL)
- num = ends - *buffer;
- else
- num = buffer_limit - *buffer;
-
- tmp_buf = xrealloc(tmp_buf, tmp_len + num);
- bcopy(*buffer, tmp_buf + tmp_len, num);
- tmp_len += num;
- }while(ends == NULL);
-
- /*
- * Now set up buffer, buffer_limit and input_line_pointer be past
- * all the characters of the "#APP\n ... #NO_APP\n" set so that
- * when we return parsing will be picked up from their.
- */
- if(ends != NULL)
- input_line_pointer = ends + sizeof("#NO_APP\n") - 1;
- else{
- input_line_pointer = *buffer;
- buffer_limit = *buffer;
- }
-
- /*
- * Now set s to the start, and ends to the end of the un-scrubed
- * contents of the collected characters between the "#APP\n" and
- * "#NO_APP\n" pair.
- */
- s = tmp_buf;
- ends = s + tmp_len;
- }
- else{
- /*
- * The matching "#NO_APP\n" was in the buffer as we were called so
- * s is the start, and ends is the end of the un-scrubed contents
- * of the characters between the "#APP\n" and "#NO_APP\n" pair.
- * Now to set up buffer, buffer_limit and input_line_pointer be past
- * all the characters of the "#APP\n ... #NO_APP\n" set so that
- * when we return parsing will be picked up from their all that has
- * to be done is move the input_line_pointer past the "#NO_APP\n".
- */
- input_line_pointer = ends + sizeof("#NO_APP\n") - 1;
- }
-
- /*
- * Now that we have the un-scrubed characters beween s and ends setup
- * to scrub them into a new buffer (new_buf of size new_length to
- * new_tmp).
- */
- new_length = 100;
- new_buf = xmalloc(new_length);
- new_tmp = new_buf;
- *new_tmp++ = '\n'; /* place leading \n in buffer for parse_a_buffer */
-
- scrub_string = s;
- scrub_last_string = ends;
- for(;;){
- int c;
-
- c = do_scrub_next_char(scrub_from_string, scrub_to_string);
- if(c == EOF)
- break;
- *new_tmp++ = c;
- if(new_tmp == new_buf + new_length){
- new_buf = xrealloc(new_buf, new_length + 100);
- new_tmp = new_buf + new_length;
- new_length += 100;
- }
- }
- *new_tmp = '\n'; /* place trailing \n in buffer for parse_a_buffer */
-
- /*
- * If we used a temporary buffer to collect the un-scrubbed characters
- * it is no longer needed and can be free()'ed.
- */
- if(tmp_buf != NULL)
- free(tmp_buf);
-
- /*
- * Now we are ready to recursively call parse_a_buffer() with our buffer
- * of scrubed characters. So save the state of parse_a_buffer() and set
- * it up with our buffer of scrubed characters.
- */
- old_input_line_pointer = input_line_pointer;
- old_buffer_limit = buffer_limit;
-
- input_line_pointer = new_buf;
- buffer_limit = new_tmp;
- parse_a_buffer(new_buf);
-
- /*
- * Free the buffer that held the scrubbed characters
- */
- free(new_buf);
-
- /*
- * After coming back from our recursive call parse_a_buffer() we want
- * resume parsing after the "#NO_APP\n". So bump the line counters
- * for the "#NO_APP\n" and restore the state so we can return to
- * parse_a_buffer().
- */
- if(count_lines == TRUE)
- bump_line_counters();
- input_line_pointer = old_input_line_pointer;
- buffer_limit = old_buffer_limit;
-
- return;
- }
-
- void
- s_abort()
- {
- #ifdef NeXT
- char *p;
-
- p = input_line_pointer;
- while(is_end_of_line[*p] == FALSE)
- p++;
- *p = '\0';
-
- as_fatal(".abort %s detected. Assembly stopping.", input_line_pointer);
- #else NeXT
- as_fatal(".abort detected. Abandoning ship.");
- #endif NeXT
- }
-
- void
- s_align()
- {
- register int temp;
- register long int temp_fill;
- #ifdef xRISC
- char *thisfrag;
- int dot;
- #endif
-
- temp = get_absolute_expression ();
- #define MAX_ALIGNMENT (15)
- if ( temp > MAX_ALIGNMENT )
- as_warn("Alignment too large: %d. assumed.", temp = MAX_ALIGNMENT);
- else if ( temp < 0 ) {
- as_warn("Alignment negative. 0 assumed.");
- temp = 0;
- }
- if ( *input_line_pointer == ',' ) {
- input_line_pointer ++;
- temp_fill = get_absolute_expression ();
- } else
- temp_fill = 0;
- #ifdef xRISC
- /* grow the current frag and plop in the fill as needed to the align */
- if(temp != 0){
- dot = obstack_next_free(&frags) - frag_now->fr_literal;
- while((dot & ((1 << temp) - 1)) != 0){
- thisfrag = frag_more(1);
- *thisfrag = temp_fill;
- dot = obstack_next_free(&frags) - frag_now->fr_literal;
- }
- }
- #else
- /* Only make a frag if we HAVE to. . . */
- if ( temp && ! need_pass_2 )
- frag_align (temp, (int)temp_fill);
- #endif
- #ifdef Mach_O
- set_section_align(temp);
- #endif
- demand_empty_rest_of_line();
- }
-
- void
- s_comm()
- {
- register char *name;
- register char c;
- register char *p;
- register int temp;
- register symbolS * symbolP;
-
- #ifdef NeXT
- if( * input_line_pointer == '"')
- name = input_line_pointer + 1;
- else
- name = input_line_pointer;
- #else !defined(NeXT)
- name = input_line_pointer;
- #endif NeXT
- c = get_symbol_end();
- /* just after name is now '\0' */
- p = input_line_pointer;
- *p = c;
- SKIP_WHITESPACE();
- if ( * input_line_pointer != ',' ) {
- as_warn("Expected comma after symbol-name");
- ignore_rest_of_line();
- return;
- }
- input_line_pointer ++; /* skip ',' */
- if ( (temp = get_absolute_expression ()) < 0 ) {
- as_warn(".COMMon length (%d.) <0! Ignored.", temp);
- ignore_rest_of_line();
- return;
- }
- *p = 0;
- symbolP = symbol_find_or_make (name);
- *p = c;
- if ( (symbolP -> sy_type & N_TYPE) != N_UNDF ||
- symbolP -> sy_other != 0 || symbolP -> sy_desc != 0) {
- as_warn( "Ignoring attempt to re-define symbol");
- ignore_rest_of_line();
- return;
- }
- if (symbolP -> sy_value) {
- if (symbolP -> sy_value != temp)
- as_warn( "Length of .comm \"%s\" is already %d. Not changed to %d.",
- symbolP -> sy_name, symbolP -> sy_value, temp);
- } else {
- symbolP -> sy_value = temp;
- symbolP -> sy_type |= N_EXT;
- }
- know( symbolP -> sy_frag == &zero_address_frag );
- demand_empty_rest_of_line();
- }
-
- void
- s_data()
- {
- register int temp;
-
- temp = get_absolute_expression ();
- subseg_new (SEG_DATA, (subsegT)temp);
- demand_empty_rest_of_line();
- }
-
- void
- s_desc()
- {
- register char *name;
- register char c;
- register char *p;
- register symbolS * symbolP;
- register int temp;
-
- /*
- * Frob invented at RMS' request. Set the n_desc of a symbol.
- */
- #ifdef NeXT
- if( * input_line_pointer == '"')
- name = input_line_pointer + 1;
- else
- name = input_line_pointer;
- #else !defined(NeXT)
- name = input_line_pointer;
- #endif NeXT
- c = get_symbol_end();
- p = input_line_pointer;
- symbolP = symbol_table_lookup (name);
- * p = c;
- SKIP_WHITESPACE();
- if ( * input_line_pointer != ',' ) {
- *p = 0;
- as_warn("Expected comma after name \"%s\"", name);
- *p = c;
- ignore_rest_of_line();
- } else {
- input_line_pointer ++;
- temp = get_absolute_expression ();
- *p = 0;
- symbolP = symbol_find_or_make (name);
- *p = c;
- symbolP -> sy_desc = temp;
- }
- demand_empty_rest_of_line();
- }
-
- void
- s_file()
- {
- register char *s;
- int length;
-
- /* Some assemblers tolerate immediately following '"' */
- if ( s = demand_copy_string( & length ) ) {
- #ifdef NeXT
- SKIP_WHITESPACE();
- if(*input_line_pointer >= '0' && *input_line_pointer <= '9'){
- while(*input_line_pointer >= '0' &&
- *input_line_pointer <= '9')
- input_line_pointer++;
- }
- #endif NeXT
- new_logical_line (s, -1);
- demand_empty_rest_of_line();
-
- #ifdef NeXT /* generate stabs for debugging assembly code */
- /* See the comments about stabs in read_a_source_file()
- for a description of what is going on here */
- if(flagseen['g'] && now_seg == SEG_TEXT && now_subseg == 0){
- extern unsigned int logical_input_file;
- struct symbol *symbolP;
-
- symbolP = symbol_new(
- logical_input_file,
- 132 /* N_SOL */,
- seg_n_sect(now_seg, now_subseg),
- 0,
- obstack_next_free(&frags) - frag_now->fr_literal,
- frag_now);
- }
- #endif NeXT /* generate stabs for debugging assembly code */
- }
- }
-
- void
- s_fill()
- {
- long int temp_repeat;
- long int temp_size;
- register long int temp_fill;
- char *p;
-
- if ( get_absolute_expression_and_terminator(& temp_repeat) != ',' ) {
- input_line_pointer --; /* Backup over what was not a ','. */
- as_warn("Expect comma after rep-size in .fill");
- ignore_rest_of_line();
- return;
- }
- if ( get_absolute_expression_and_terminator( & temp_size) != ',' ) {
- input_line_pointer --; /* Backup over what was not a ','. */
- as_warn("Expected comma after size in .fill");
- ignore_rest_of_line();
- return;
- }
- /*
- * This is to be compatible with BSD 4.2 AS, not for any rational reason.
- */
- #define BSD_FILL_SIZE_CROCK_8 (8)
- if ( temp_size > BSD_FILL_SIZE_CROCK_8 ) {
- as_warn(".fill size clamped to %d.", BSD_FILL_SIZE_CROCK_8);
- temp_size = BSD_FILL_SIZE_CROCK_8 ;
- } if ( temp_size < 0 ) {
- as_warn("Size negative: .fill ignored.");
- temp_size = 0;
- #ifdef NeXT
- /* bug fix, if md_number_to_chars() is called with something other than
- * 1,2 or 4 it calls abort(). So we don't let the size be something
- * like 3. Bug #13017.
- */
- } else if ( temp_size != 0 &&
- temp_size != 1 &&
- temp_size != 2 &&
- temp_size != 4 ) {
- as_warn("Repeat must be 0,1,2 or 4, .fill ignored");
- temp_size = 0;
- #endif NeXT
- } else if ( temp_repeat <= 0 ) {
- as_warn("Repeat < 0, .fill ignored");
- temp_size = 0;
- }
- temp_fill = get_absolute_expression ();
- if ( temp_size && !need_pass_2 ) {
- p = frag_var (rs_fill, (int)temp_size, (int)temp_size, (relax_substateT)0, (symbolS *)0, temp_repeat, (char *)0);
- bzero (p, (int)temp_size);
- /*
- * The magic number BSD_FILL_SIZE_CROCK_4 is from BSD 4.2 VAX flavoured AS.
- * The following bizzare behaviour is to be compatible with above.
- * I guess they tried to take up to 8 bytes from a 4-byte expression
- * and they forgot to sign extend. Un*x Sux.
- */
- #define BSD_FILL_SIZE_CROCK_4 (4)
- md_number_to_chars (p, temp_fill, temp_size > BSD_FILL_SIZE_CROCK_4 ? BSD_FILL_SIZE_CROCK_4 : (int)temp_size);
- /*
- * Note: .fill (),0 emits no frag (since we are asked to .fill 0 bytes)
- * but emits no error message because it seems a legal thing to do.
- * It is a degenerate case of .fill but could be emitted by a compiler.
- */
- }
- demand_empty_rest_of_line();
- }
-
- #ifdef DONTDEF
- void
- s_gdbbeg()
- {
- register int temp;
-
- temp = get_absolute_expression ();
- if (temp < 0)
- as_warn( "Block number <0. Ignored." );
- else if (flagseen ['G'])
- gdb_block_beg ( (long int) temp, frag_now, (long int)(obstack_next_free(& frags) - frag_now -> fr_literal));
- demand_empty_rest_of_line ();
- }
-
- void
- s_gdbblock()
- {
- register int position;
- int temp;
-
- if (get_absolute_expression_and_terminator (&temp) != ',') {
- as_warn( "expected comma before position in .gdbblock");
- --input_line_pointer;
- ignore_rest_of_line ();
- return;
- }
- position = get_absolute_expression ();
- if (flagseen ['G'])
- gdb_block_position ((long int) temp, (long int) position);
- demand_empty_rest_of_line ();
- }
-
- void
- s_gdbend()
- {
- register int temp;
-
- temp = get_absolute_expression ();
- if (temp < 0)
- as_warn( "Block number <0. Ignored." );
- else if (flagseen ['G'])
- gdb_block_end ( (long int) temp, frag_now, (long int)(obstack_next_free(& frags) - frag_now -> fr_literal));
- demand_empty_rest_of_line ();
- }
-
- void
- s_gdbsym()
- {
- register char *name,
- *p;
- register char c;
- register symbolS * symbolP;
- register int temp;
-
- name = input_line_pointer;
- c = get_symbol_end();
- p = input_line_pointer;
- symbolP = symbol_find_or_make (name);
- *p = c;
- SKIP_WHITESPACE();
- if ( * input_line_pointer != ',' ) {
- as_warn("Expected comma after name");
- ignore_rest_of_line();
- return;
- }
- input_line_pointer ++;
- if ( (temp = get_absolute_expression ()) < 0 ) {
- as_warn("Bad GDB symbol file offset (%d.) <0! Ignored.", temp);
- ignore_rest_of_line();
- return;
- }
- if (flagseen ['G'])
- gdb_symbols_fixup (symbolP, (long int)temp);
- demand_empty_rest_of_line ();
- }
-
- void
- s_gdbline()
- {
- int file_number,
- lineno;
-
- if(get_absolute_expression_and_terminator(&file_number) != ',') {
- as_warn("expected comman after filenum in .gdbline");
- ignore_rest_of_line();
- return;
- }
- lineno=get_absolute_expression();
- if(flagseen['G'])
- gdb_line(file_number,lineno);
- demand_empty_rest_of_line();
- }
-
-
- void
- s_gdblinetab()
- {
- int file_number,
- offset;
-
- if(get_absolute_expression_and_terminator(&file_number) != ',') {
- as_warn("expected comman after filenum in .gdblinetab");
- ignore_rest_of_line();
- return;
- }
- offset=get_absolute_expression();
- if(flagseen['G'])
- gdb_line_tab(file_number,offset);
- demand_empty_rest_of_line();
- }
- #endif
-
- void
- s_globl()
- {
- register char *name;
- register int c;
- register symbolS * symbolP;
-
- do {
- #ifdef NeXT
- if( * input_line_pointer == '"')
- name = input_line_pointer + 1;
- else
- name = input_line_pointer;
- #else !defined(NeXT)
- name = input_line_pointer;
- #endif NeXT
- c = get_symbol_end();
- symbolP = symbol_find_or_make (name);
- * input_line_pointer = c;
- SKIP_WHITESPACE();
- symbolP -> sy_type |= N_EXT;
- if(c==',') {
- input_line_pointer++;
- SKIP_WHITESPACE();
- if(*input_line_pointer=='\n')
- c='\n';
- }
- } while(c==',');
- demand_empty_rest_of_line();
- }
-
- void
- s_lcomm()
- {
- register char *name;
- register char c;
- register char *p;
- register int temp;
- register symbolS * symbolP;
- #ifdef NeXT
- int align;
-
- if( * input_line_pointer == '"')
- name = input_line_pointer + 1;
- else
- name = input_line_pointer;
- #else !defined(NeXT)
- name = input_line_pointer;
- #endif NeXT
- c = get_symbol_end();
- p = input_line_pointer;
- *p = c;
- SKIP_WHITESPACE();
- if ( * input_line_pointer != ',' ) {
- as_warn("Expected comma after name");
- ignore_rest_of_line();
- return;
- }
- input_line_pointer ++;
- if ( (temp = get_absolute_expression ()) < 0 ) {
- as_warn("BSS length (%d.) <0! Ignored.", temp);
- ignore_rest_of_line();
- return;
- }
- #define MAX_ALIGNMENT (15)
- #ifdef NeXT
- align = 0;
- if ( *input_line_pointer == ',' ) {
- input_line_pointer ++;
- align = get_absolute_expression ();
- if ( align > MAX_ALIGNMENT ) {
- as_warn("Alignment too large: %d. assumed.", MAX_ALIGNMENT);
- align = MAX_ALIGNMENT;
- }
- else if ( align < 0 ) {
- as_warn("Alignment negative. 0 assumed.");
- align = 0;
- }
- }
- #endif NeXT
- *p = 0;
- symbolP = symbol_find_or_make (name);
- *p = c;
- if ( symbolP -> sy_other == 0
- && symbolP -> sy_desc == 0
- && ( ( symbolP -> sy_type == N_BSS
- && symbolP -> sy_value == local_bss_counter)
- || ( (symbolP -> sy_type & N_TYPE) == N_UNDF
- && symbolP -> sy_value == 0))) {
- #ifdef NeXT
- local_bss_counter = (local_bss_counter + ((1 << align) - 1) ) &
- ~((1 << align) - 1);
- #endif NeXT
- symbolP -> sy_value = local_bss_counter;
- symbolP -> sy_type = N_BSS;
- #ifdef Mach_O
- symbolP -> sy_other = n_type_n_sect (symbolP->sy_type);
- #endif Mach_O
- symbolP -> sy_frag = & bss_address_frag;
- local_bss_counter += temp;
- } else
- as_warn( "Ignoring attempt to re-define symbol from %d. to %d.",
- symbolP -> sy_value, local_bss_counter );
- demand_empty_rest_of_line();
- }
-
- void
- s_line()
- {
- /* Assume delimiter is part of expression. */
- /* BSD4.2 as fails with delightful bug, so we */
- /* are not being incompatible here. */
- #ifdef NeXT
- /*
- * Since the assembler bumps it's line counters at the end of a line
- * and it is most allways the case that the .line is on it's own line
- * what the intent is that the line number is for the next line. Thus
- * the -1 . This is the way cpp'ed assembler files work which is the
- * common case.
- */
- new_logical_line ((char *)NULL, (int)(get_absolute_expression ())-1);
- #else NeXT
- new_logical_line ((char *)NULL, (int)(get_absolute_expression ()));
- #endif NeXT
- demand_empty_rest_of_line();
- }
-
- void
- s_long()
- {
- cons(4);
- }
-
- void
- s_int()
- {
- cons(4);
- }
-
- void
- s_lsym()
- {
- register char *name;
- register char c;
- register char *p;
- register segT segment;
- expressionS exp;
- register symbolS *symbolP;
-
- /* we permit ANY expression: BSD4.2 demands constants */
- #ifdef NeXT
- if( * input_line_pointer == '"')
- name = input_line_pointer + 1;
- else
- name = input_line_pointer;
- #else !defined(NeXT)
- name = input_line_pointer;
- #endif NeXT
- c = get_symbol_end();
- p = input_line_pointer;
- *p = c;
- SKIP_WHITESPACE();
- if ( * input_line_pointer != ',' ) {
- *p = 0;
- as_warn("Expected comma after name \"%s\"", name);
- *p = c;
- ignore_rest_of_line();
- return;
- }
- input_line_pointer ++;
- segment = expression (& exp);
- if ( segment != SEG_ABSOLUTE && segment != SEG_DATA &&
- segment != SEG_TEXT && segment != SEG_BSS) {
- as_warn("Bad expression: %s", seg_name [(int)segment]);
- ignore_rest_of_line();
- return;
- }
- know( segment == SEG_ABSOLUTE || segment == SEG_DATA || segment == SEG_TEXT || segment == SEG_BSS );
- *p = 0;
- #ifdef Mach_O
- symbolP = symbol_new (name,(unsigned char)(seg_N_TYPE [(int) segment]),
- seg_n_sect(segment, now_subseg),
- 0, (valueT)(exp . X_add_number), & zero_address_frag);
- #else !defined(Mach_O)
- symbolP = symbol_new (name,(unsigned char)(seg_N_TYPE [(int) segment]),
- 0, 0, (valueT)(exp . X_add_number), & zero_address_frag);
- #endif Mach_O
- *p = c;
- demand_empty_rest_of_line();
- }
-
- void
- s_org()
- {
- register segT segment;
- expressionS exp;
- register long int temp_fill;
- register char *p;
- /*
- * Don't believe the documentation of BSD 4.2 AS.
- * There is no such thing as a sub-segment-relative origin.
- * Any absolute origin is given a warning, then assumed to be segment-relative.
- * Any segmented origin expression ("foo+42") had better be in the right
- * segment or the .org is ignored.
- *
- * BSD 4.2 AS warns if you try to .org backwards. We cannot because we
- * never know sub-segment sizes when we are reading code.
- * BSD will crash trying to emit -ve numbers of filler bytes in certain
- * .orgs. We don't crash, but see as-write for that code.
- */
- /*
- * Don't make frag if need_pass_2==TRUE.
- */
- segment = get_known_segmented_expression(& exp);
- if ( *input_line_pointer == ',' ) {
- input_line_pointer ++;
- temp_fill = get_absolute_expression ();
- } else
- temp_fill = 0;
- if ( ! need_pass_2 ) {
- if (segment != now_seg && segment != SEG_ABSOLUTE)
- as_warn("Illegal segment \"%s\". Segment \"%s\" assumed.",
- seg_name [(int) segment], seg_name [(int) now_seg]);
- p = frag_var (rs_org, 1, 1, (relax_substateT)0, exp . X_add_symbol,
- exp . X_add_number, (char *)0);
- * p = temp_fill;
- } /* if (ok to make frag) */
- demand_empty_rest_of_line();
- }
-
- void
- s_set()
- {
- register char *name;
- register char delim;
- register char *end_name;
- register symbolS *symbolP;
-
- /*
- * Especial apologies for the random logic:
- * this just grew, and could be parsed much more simply!
- * Dean in haste.
- */
- #ifdef NeXT
- if( * input_line_pointer == '"')
- name = input_line_pointer + 1;
- else
- name = input_line_pointer;
- #else !defined(NeXT)
- name = input_line_pointer;
- #endif NeXT
- delim = get_symbol_end();
- end_name = input_line_pointer;
- *end_name = delim;
- SKIP_WHITESPACE();
- if ( * input_line_pointer != ',' ) {
- *end_name = 0;
- as_warn("Expected comma after name \"%s\"", name);
- *end_name = delim;
- ignore_rest_of_line();
- return;
- }
- input_line_pointer ++;
- *end_name = 0;
- if(name[0]=='.' && name[1]=='\0') {
- /* Turn '. = mumble' into a .org mumble */
- register segT segment;
- expressionS exp;
- register char *ptr;
-
- segment = get_known_segmented_expression(& exp);
- if ( ! need_pass_2 ) {
- if (segment != now_seg && segment != SEG_ABSOLUTE)
- as_warn("Illegal segment \"%s\". Segment \"%s\" assumed.",
- seg_name [(int) segment], seg_name [(int) now_seg]);
- ptr = frag_var (rs_org, 1, 1, (relax_substateT)0, exp.X_add_symbol,
- exp.X_add_number, (char *)0);
- *ptr= 0;
- } /* if (ok to make frag) */
- *end_name = delim;
- return;
- }
- symbolP = symbol_find_or_make (name);
- *end_name = delim;
- pseudo_set (symbolP);
- demand_empty_rest_of_line ();
- }
-
- #ifdef NeXT
- /*
- * s_abs() is used to implement ".abs symbol,exp" which set symbol to 1 or 0
- * depending on if the expression is an absolute expression. This is intended
- * for use in macros.
- */
- void
- s_abs()
- {
- register char *name;
- register char c;
- register char *p;
- register segT segment;
- expressionS exp;
- register symbolS *symbolP;
-
- #ifdef NeXT
- if( * input_line_pointer == '"')
- name = input_line_pointer + 1;
- else
- name = input_line_pointer;
- #else !defined(NeXT)
- name = input_line_pointer;
- #endif NeXT
- c = get_symbol_end();
- p = input_line_pointer;
- *p = c;
- SKIP_WHITESPACE();
- if ( * input_line_pointer != ',' ) {
- *p = 0;
- as_warn("Expected comma after name \"%s\"", name);
- *p = c;
- ignore_rest_of_line();
- return;
- }
- input_line_pointer ++;
- *p = 0;
- segment = expression (& exp);
- symbolP = symbol_find_or_make (name);
- symbolP -> sy_type = N_ABS;
- #ifdef Mach_O
- symbolP -> sy_other = 0; /* NO_SECT */
- #endif Mach_O
- symbolP -> sy_frag = & zero_address_frag;
- if (segment == SEG_ABSOLUTE)
- symbolP -> sy_value = 1;
- else
- symbolP -> sy_value = 0;
- *p = c;
- totally_ignore_line();
- }
- #endif NeXT
-
- void
- s_space()
- {
- long int temp_repeat;
- register long int temp_fill;
- register char *p;
-
- /* Just like .fill, but temp_size = 1 */
- if ( get_absolute_expression_and_terminator( & temp_repeat) == ',' ) {
- temp_fill = get_absolute_expression ();
- } else {
- input_line_pointer --; /* Backup over what was not a ','. */
- temp_fill = 0;
- }
- if ( temp_repeat <= 0 ) {
- as_warn("Repeat < 0, .space ignored");
- ignore_rest_of_line();
- return;
- }
- if ( ! need_pass_2 ) {
- p = frag_var (rs_fill, 1, 1, (relax_substateT)0, (symbolS *)0,
- temp_repeat, (char *)0);
- * p = temp_fill;
- }
- demand_empty_rest_of_line();
- }
-
- void
- s_text()
- {
- register int temp;
-
- temp = get_absolute_expression ();
- subseg_new (SEG_TEXT, (subsegT)temp);
- demand_empty_rest_of_line();
- }
-
- #ifdef NeXT
- void
- s_reference()
- {
- register char *name;
- register char c;
- register char *p;
- register symbolS * symbolP;
-
- if( * input_line_pointer == '"')
- name = input_line_pointer + 1;
- else
- name = input_line_pointer;
- c = get_symbol_end();
- p = input_line_pointer;
-
- *p = 0;
- symbolP = symbol_find_or_make (name);
- *p = c;
- demand_empty_rest_of_line();
- }
- #endif NeXT
-
- #ifdef NeXT /* .include feature */
- void
- s_include()
- /*
- * DJA -- Include files.
- */
- {
- register char *filename;
- int length;
- void read_an_include_file ();
-
- symbolS *symbolP;
- extern char *physical_input_file;
-
- /* Some assemblers tolerate immediately following '"' */
- if ( filename = demand_copy_string( & length ) ) {
- demand_empty_rest_of_line();
- read_an_include_file (filename);
- }
-
- /* See the second comment about stabs in read_a_source_file()
- for a description of what is going on here */
- if (flagseen['g'] && now_seg == SEG_TEXT && now_subseg == 0){
- symbolP = symbol_new(
- physical_input_file,
- 132 /* N_SOL */,
- seg_n_sect(now_seg, now_subseg),
- 0,
- obstack_next_free(&frags) - frag_now->fr_literal,
- frag_now);
- }
- }
- #endif NeXT /* .include feature */
-
- #ifdef Mach_O
- void
- s_text_Mach_O(subseg)
- int subseg;
- {
- subseg_new(SEG_TEXT, subseg);
- demand_empty_rest_of_line();
- }
-
- void
- s_data_Mach_O(subseg)
- int subseg;
- {
- subseg_new(SEG_DATA, subseg);
- demand_empty_rest_of_line();
- }
- #endif Mach_O
-
-
- /*( JF was static, but can't be if machine dependent pseudo-ops are to use it */
-
- void
- demand_empty_rest_of_line()
- {
- SKIP_WHITESPACE();
- if ( is_end_of_line [* input_line_pointer] )
- {
- input_line_pointer ++;
- }
- else
- {
- ignore_rest_of_line();
- }
- /* Return having already swallowed end-of-line. */
- } /* Return pointing just after end-of-line. */
-
- void
- ignore_rest_of_line() /* For suspect lines: gives warning. */
- {
- if ( ! is_end_of_line [* input_line_pointer])
- {
- as_warn("Rest of line ignored. 1st junk character valued %d (%c)."
- , * input_line_pointer, *input_line_pointer);
- while ( input_line_pointer < buffer_limit
- && ! is_end_of_line [* input_line_pointer] )
- {
- input_line_pointer ++;
- }
- }
- input_line_pointer ++; /* Return pointing just after end-of-line. */
- know( is_end_of_line [input_line_pointer [-1]] );
- }
-
- /*
- * stab()
- *
- * Handle .stabX directives, which used to be open-coded.
- * So much creeping featurism overloaded the semantics that we decided
- * to put all .stabX thinking in one place. Here.
- *
- * We try to make any .stabX directive legal. Other people's AS will often
- * do assembly-time consistency checks: eg assigning meaning to n_type bits
- * and "protecting" you from setting them to certain values. (They also zero
- * certain bits before emitting symbols. Tut tut.)
- *
- * If an expression is not absolute we either gripe or use the relocation
- * information. Other people's assemblers silently forget information they
- * don't need and invent information they need that you didn't supply.
- *
- * .stabX directives always make a symbol table entry. It may be junk if
- * the rest of your .stabX directive is malformed.
- */
- static void
- stab (what)
- int what;
- {
- register symbolS * symbolP;
- register char * string;
- int saved_type;
- int length;
- int goof; /* TRUE if we have aborted. */
- long int longint;
-
- /*
- * Enter with input_line_pointer pointing past .stabX and any following
- * whitespace.
- */
- goof = FALSE; /* JF who forgot this?? */
- if (what == 's') {
- string = demand_copy_C_string (& length);
- SKIP_WHITESPACE();
- if (* input_line_pointer == ',')
- input_line_pointer ++;
- else {
- as_warn( "I need a comma after symbol's name" );
- goof = TRUE;
- }
- } else
- string = "";
-
- /*
- * Input_line_pointer->after ','. String -> symbol name.
- */
- if (! goof) {
- symbolP = symbol_new (string, 0,0,0,0,(struct frag *)0);
- switch (what) {
- case 'd':
- symbolP->sy_name = NULL; /* .stabd feature. */
- symbolP->sy_value = obstack_next_free(& frags) - frag_now->fr_literal;
- symbolP->sy_frag = frag_now;
- break;
-
- case 'n':
- symbolP->sy_frag = &zero_address_frag;
- break;
-
- case 's':
- symbolP->sy_frag = & zero_address_frag;
- break;
-
- default:
- BAD_CASE( what );
- break;
- }
- if (get_absolute_expression_and_terminator (& longint) == ',')
- symbolP->sy_type = saved_type = longint;
- else {
- as_warn( "I want a comma after the n_type expression" );
- goof = TRUE;
- input_line_pointer --; /* Backup over a non-',' char. */
- }
- }
- if (! goof) {
- if (get_absolute_expression_and_terminator (& longint) == ',')
- symbolP->sy_other = longint;
- else {
- as_warn( "I want a comma after the n_other expression" );
- goof = TRUE;
- input_line_pointer --; /* Backup over a non-',' char. */
- }
- }
- if (! goof) {
- symbolP->sy_desc = get_absolute_expression ();
- if (what == 's' || what == 'n') {
- if (* input_line_pointer != ',') {
- as_warn( "I want a comma after the n_desc expression" );
- goof = TRUE;
- } else {
- input_line_pointer ++;
- }
- }
- }
- if ((! goof) && (what=='s' || what=='n')) {
- pseudo_set (symbolP);
- symbolP->sy_type = saved_type;
- }
- #ifdef Mach_O
- else if (! goof) {
- symbolP->sy_other = seg_n_sect(now_seg, now_subseg);
- }
- #endif Mach_O
- if (goof)
- ignore_rest_of_line ();
- else
- demand_empty_rest_of_line ();
- }
-
- /*
- * pseudo_set()
- *
- * In: Pointer to a symbol.
- * Input_line_pointer -> expression.
- *
- * Out: Input_line_pointer -> just after any whitespace after expression.
- * Tried to set symbol to value of expression.
- * Will change sy_type, sy_value, sy_frag;
- * May set need_pass_2 == TRUE.
- */
- static void
- pseudo_set (symbolP)
- symbolS * symbolP;
- {
- expressionS exp;
- register segT segment;
- int ext;
-
- know( symbolP ); /* NULL pointer is logic error. */
- ext=(symbolP->sy_type&N_EXT);
- if ((segment = expression( & exp )) == SEG_NONE)
- {
- as_warn( "Missing expression: absolute 0 assumed" );
- exp . X_seg = SEG_ABSOLUTE;
- exp . X_add_number = 0;
- }
- switch (segment)
- {
- case SEG_BIG:
- as_warn( "%s number illegal. Absolute 0 assumed.",
- exp . X_add_number > 0 ? "Bignum" : "Floating-Point" );
- symbolP -> sy_type = N_ABS | ext;
- #ifdef Mach_O
- symbolP -> sy_other = 0; /* NO_SECT */
- #endif Mach_O
- symbolP -> sy_value = 0;
- symbolP -> sy_frag = & zero_address_frag;
- break;
-
- case SEG_NONE:
- as_warn("No expression: Using absolute 0");
- symbolP -> sy_type = N_ABS | ext;
- #ifdef Mach_O
- symbolP -> sy_other = 0; /* NO_SECT */
- #endif Mach_O
- symbolP -> sy_value = 0;
- symbolP -> sy_frag = & zero_address_frag;
- break;
-
- case SEG_DIFFERENCE:
- if (exp.X_add_symbol && exp.X_subtract_symbol
- && (exp.X_add_symbol->sy_type & N_TYPE)
- == (exp.X_subtract_symbol->sy_type & N_TYPE))
- exp.X_add_number+=exp.X_add_symbol->sy_value - exp.X_subtract_symbol->sy_value;
- else
- as_warn( "Complex expression. Absolute segment assumed." );
- case SEG_ABSOLUTE:
- symbolP -> sy_type = N_ABS | ext;
- #ifdef Mach_O
- symbolP -> sy_other = 0; /* NO_SECT */
- #endif Mach_O
- symbolP -> sy_value = exp . X_add_number;
- symbolP -> sy_frag = & zero_address_frag;
- break;
-
- case SEG_DATA:
- case SEG_TEXT:
- case SEG_BSS:
- symbolP -> sy_type = seg_N_TYPE [(int) segment] | ext;
- #ifdef Mach_O
- symbolP -> sy_other = n_type_n_sect (exp . X_add_symbol -> sy_type);
- #endif Mach_O
- symbolP -> sy_value= exp . X_add_number + exp . X_add_symbol -> sy_value;
- symbolP -> sy_frag = exp . X_add_symbol -> sy_frag;
- break;
-
- case SEG_PASS1: /* Not an error. Just try another pass. */
- symbolP->sy_forward=exp.X_add_symbol;
- as_warn("Unknown expression");
- know( need_pass_2 == TRUE );
- break;
-
- case SEG_UNKNOWN:
- symbolP->sy_forward=exp.X_add_symbol;
- /* as_warn("unknown symbol"); */
- /* need_pass_2 = TRUE; */
- break;
-
- default:
- BAD_CASE( segment );
- break;
- }
- }
-
- /*
- * cons()
- *
- * CONStruct more frag of .bytes, or .words etc.
- * Should need_pass_2 be TRUE then emit no frag(s).
- * This understands EXPRESSIONS, as opposed to big_cons().
- *
- * Bug (?)
- *
- * This has a split personality. We use expression() to read the
- * value. We can detect if the value won't fit in a byte or word.
- * But we can't detect if expression() discarded significant digits
- * in the case of a long. Not worth the crocks required to fix it.
- */
- void
- cons(nbytes) /* worker to do .byte etc statements */
- /* clobbers input_line_pointer, checks */
- /* end-of-line. */
- register int nbytes; /* 1=.byte, 2=.word, 4=.long */
- {
- register char c;
- register long int mask; /* High-order bits we will left-truncate, */
- /* but includes sign bit also. */
- register long int get; /* what we get */
- register long int use; /* get after truncation. */
- register long int unmask; /* what bits we will store */
- register char * p;
- register segT segment;
- expressionS exp;
- #ifdef NS32K
- void fix_new_ns32k();
- #else
- void fix_new();
- #endif
-
- /*
- * Input_line_pointer -> 1st char after pseudo-op-code and could legally
- * be a end-of-line. (Or, less legally an eof - which we cope with.)
- */
- /* JF << of >= number of bits in the object is undefined. In particular
- SPARC (Sun 4) has problems */
- if(nbytes>=sizeof(long int))
- mask = 0;
- else
- mask = ~0 << (BITS_PER_CHAR * nbytes); /* Don't store these bits. */
- unmask = ~ mask; /* Do store these bits. */
- #ifdef NEVER
- "Do this mod if you want every overflow check to assume SIGNED 2's complement data.";
- mask = ~ (unmask >> 1); /* Includes sign bit now. */
- #endif
- /*
- * The following awkward logic is to parse ZERO or more expressions,
- * comma seperated. Recall an expression includes its leading &
- * trailing blanks. We fake a leading ',' if there is (supposed to
- * be) a 1st expression, and keep demanding 1 expression for each ','.
- */
- if (is_it_end_of_statement())
- {
- c = 0; /* Skip loop. */
- input_line_pointer ++; /* Matches end-of-loop 'correction'. */
- }
- else
- c = ','; /* Do loop. */
- while ( c == ',' )
- {
- segment = expression( &exp ); /* At least scan over the expression. */
- if ( ! need_pass_2 )
- { /* Still worthwhile making frags. */
-
- /* Don't call this if we are going to junk this pass anyway! */
- know( segment != SEG_PASS1 );
-
- if ( segment == SEG_DIFFERENCE && exp . X_add_symbol == NULL )
- {
- as_warn( "Subtracting symbol \"%s\"(segment\"%s\") is too hard. Absolute segment assumed.",
- exp . X_subtract_symbol -> sy_name,
- seg_name [(int) N_TYPE_seg [exp . X_subtract_symbol -> sy_type & N_TYPE]]);
- segment = SEG_ABSOLUTE;
- /* Leave exp . X_add_number alone. */
- }
- p = frag_more (nbytes);
- switch (segment)
- {
- case SEG_BIG:
- as_warn( "%s number illegal. Absolute 0 assumed.",
- exp . X_add_number > 0 ? "Bignum" : "Floating-Point");
- md_number_to_chars (p, (long)0, nbytes);
- break;
-
- case SEG_NONE:
- as_warn( "0 assumed for missing expression" );
- exp . X_add_number = 0;
- know( exp . X_add_symbol == NULL );
- /* fall into SEG_ABSOLUTE */
- case SEG_ABSOLUTE:
- get = exp . X_add_number;
- use = get & unmask;
- if ( (get & mask) && (get & mask) != mask )
- { /* Leading bits contain both 0s & 1s. */
- as_warn("Value x%x truncated to x%x.", get, use);
- }
- md_number_to_chars (p, use, nbytes); /* put bytes in right order. */
- break;
-
- case SEG_DIFFERENCE:
- #ifndef WORKING_DOT_WORD
- if(nbytes==2) {
- struct broken_word *x;
-
- x=(struct broken_word *)xmalloc(sizeof(struct broken_word));
- x->next_broken_word=broken_words;
- broken_words=x;
- x->frag=frag_now;
- x->word_goes_here=p;
- x->dispfrag=0;
- x->add=exp.X_add_symbol;
- x->sub=exp.X_subtract_symbol;
- x->addnum=exp.X_add_number;
- x->added=0;
- new_broken_words++;
- break;
- }
- /* Else Fall through into. . . */
- #endif
- case SEG_BSS:
- case SEG_UNKNOWN:
- case SEG_TEXT:
- case SEG_DATA:
- #ifdef RISC
- #ifdef NeXT
- fix_new (frag_now, p - frag_now -> fr_literal, nbytes,
- exp . X_add_symbol, exp . X_subtract_symbol,
- exp . X_add_number, 0, RELOC_VANILLA);
- #else !defined(NeXT)
- fix_new (frag_now, p - frag_now -> fr_literal, nbytes,
- exp . X_add_symbol, exp . X_subtract_symbol,
- exp . X_add_number, 0, RELOC_32);
- #endif NeXT
- #endif
- #ifdef NS32K
- fix_new_ns32k (frag_now, p - frag_now -> fr_literal, nbytes,
- exp . X_add_symbol, exp . X_subtract_symbol,
- exp . X_add_number, 0, 0, 2, 0, 0);
- #endif
- #if !defined(RISC) && !defined(NS32K)
- fix_new (frag_now, p - frag_now -> fr_literal, nbytes,
- exp . X_add_symbol, exp . X_subtract_symbol,
- exp . X_add_number, 0);
- #endif
- break;
-
- default:
- BAD_CASE( segment );
- break;
- } /* switch(segment) */
- } /* if(!need_pass_2) */
- c = * input_line_pointer ++;
- } /* while(c==',') */
- input_line_pointer --; /* Put terminator back into stream. */
- demand_empty_rest_of_line();
- } /* cons() */
-
- /*
- * big_cons()
- *
- * CONStruct more frag(s) of .quads, or .octa etc.
- * Makes 0 or more new frags.
- * If need_pass_2 == TRUE, generate no frag.
- * This understands only bignums, not expressions. Cons() understands
- * expressions.
- *
- * Constants recognised are '0...'(octal) '0x...'(hex) '...'(decimal).
- *
- * This creates objects with struct obstack_control objs, destroying
- * any context objs held about a partially completed object. Beware!
- *
- *
- * I think it sucks to have 2 different types of integers, with 2
- * routines to read them, store them etc.
- * It would be nicer to permit bignums in expressions and only
- * complain if the result overflowed. However, due to "efficiency"...
- */
- void
- big_cons(nbytes) /* worker to do .quad etc statements */
- /* clobbers input_line_pointer, checks */
- /* end-of-line. */
- register int nbytes; /* 8=.quad 16=.octa ... */
- {
- register char c; /* input_line_pointer -> c. */
- register int radix;
- register long int length; /* Number of chars in an object. */
- register int digit; /* Value of 1 digit. */
- register int carry; /* For multi-precision arithmetic. */
- register int work; /* For multi-precision arithmetic. */
- register char * p; /* For multi-precision arithmetic. */
-
- extern char hex_value[]; /* In hex_value.c. */
-
- /*
- * The following awkward logic is to parse ZERO or more strings,
- * comma seperated. Recall an expression includes its leading &
- * trailing blanks. We fake a leading ',' if there is (supposed to
- * be) a 1st expression, and keep demanding 1 expression for each ','.
- */
- if (is_it_end_of_statement())
- {
- c = 0; /* Skip loop. */
- }
- else
- {
- c = ','; /* Do loop. */
- -- input_line_pointer;
- }
- while (c == ',')
- {
- ++ input_line_pointer;
- SKIP_WHITESPACE();
- c = * input_line_pointer;
- /* C contains 1st non-blank character of what we hope is a number. */
- if (c == '0')
- {
- c = * ++ input_line_pointer;
- if (c == 'x' || c=='X')
- {
- c = * ++ input_line_pointer;
- radix = 16;
- }
- else
- {
- radix = 8;
- }
- }
- else
- {
- radix = 10;
- }
- /*
- * This feature (?) is here to stop people worrying about
- * mysterious zero constants: which is what they get when
- * they completely omit digits.
- */
- if (hex_value[c] >= radix)
- {
- as_warn( "Missing digits. 0 assumed." );
- }
- bignum_high = bignum_low - 1; /* Start constant with 0 chars. */
- for( ; (digit = hex_value [c]) < radix; c = * ++ input_line_pointer)
- {
- /* Multiply existing number by radix, then add digit. */
- carry = digit;
- for (p=bignum_low; p <= bignum_high; p++)
- {
- work = (*p & MASK_CHAR) * radix + carry;
- *p = work & MASK_CHAR;
- carry = work >> BITS_PER_CHAR;
- }
- if (carry)
- {
- grow_bignum();
- * bignum_high = carry & MASK_CHAR;
- know( (carry & ~ MASK_CHAR) == 0);
- }
- }
- length = bignum_high - bignum_low + 1;
- if (length > nbytes)
- {
- as_warn( "Most significant bits truncated in integer constant." );
- }
- else
- {
- register long int leading_zeroes;
-
- for(leading_zeroes = nbytes - length;
- leading_zeroes;
- leading_zeroes --)
- {
- grow_bignum();
- * bignum_high = 0;
- }
- }
- if (! need_pass_2)
- {
- p = frag_more (nbytes);
- bcopy (bignum_low, p, (int)nbytes);
- }
- /* C contains character after number. */
- SKIP_WHITESPACE();
- c = * input_line_pointer;
- /* C contains 1st non-blank character after number. */
- }
- demand_empty_rest_of_line();
- } /* big_cons() */
-
- static void
- grow_bignum() /* Extend bignum by 1 char. */
- {
- register long int length;
-
- bignum_high ++;
- if (bignum_high >= bignum_limit)
- {
- length = bignum_limit - bignum_low;
- bignum_low = xrealloc (bignum_low, length + length);
- bignum_high = bignum_low + length;
- bignum_limit = bignum_low + length + length;
- }
- } /* grow_bignum(); */
-
- /*
- * float_cons()
- *
- * CONStruct some more frag chars of .floats .ffloats etc.
- * Makes 0 or more new frags.
- * If need_pass_2 == TRUE, no frags are emitted.
- * This understands only floating literals, not expressions. Sorry.
- *
- * A floating constant is defined by atof_generic(), except it is preceded
- * by 0d 0f 0g or 0h. After observing the STRANGE way my BSD AS does its
- * reading, I decided to be incompatible. This always tries to give you
- * rounded bits to the precision of the pseudo-op. Former AS did premature
- * truncatation, restored noisy bits instead of trailing 0s AND gave you
- * a choice of 2 flavours of noise according to which of 2 floating-point
- * scanners you directed AS to use.
- *
- * In: input_line_pointer -> whitespace before, or '0' of flonum.
- *
- */
-
- void /* JF was static, but can't be if VAX.C is goning to use it */
- float_cons(float_type) /* Worker to do .float etc statements. */
- /* Clobbers input_line-pointer, checks end-of-line. */
- register float_type; /* 'f':.ffloat ... 'F':.float ... */
- {
- register char * p;
- register char c;
- int length; /* Number of chars in an object. */
- register char * err; /* Error from scanning floating literal. */
- char temp [MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT];
-
- /*
- * The following awkward logic is to parse ZERO or more strings,
- * comma seperated. Recall an expression includes its leading &
- * trailing blanks. We fake a leading ',' if there is (supposed to
- * be) a 1st expression, and keep demanding 1 expression for each ','.
- */
- if (is_it_end_of_statement())
- {
- c = 0; /* Skip loop. */
- ++ input_line_pointer; /* -> past termintor. */
- }
- else
- {
- c = ','; /* Do loop. */
- }
- while (c == ',')
- {
- /* input_line_pointer -> 1st char of a flonum (we hope!). */
- SKIP_WHITESPACE();
- /* Skip any 0{letter} that may be present. Don't even check if the
- * letter is legal. Someone may invent a "z" format and this routine
- * has no use for such information. Lusers beware: you get
- * diagnostics if your input is ill-conditioned.
- */
-
- if(input_line_pointer[0]=='0' && isalpha(input_line_pointer[1]))
- input_line_pointer+=2;
-
- err = md_atof (float_type, temp, &length);
- know( length <= MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT);
- know( length > 0 );
- if (* err)
- {
- as_warn( "Bad floating literal: %s", err);
- ignore_rest_of_line();
- /* Input_line_pointer -> just after end-of-line. */
- c = 0; /* Break out of loop. */
- }
- else
- {
- if ( ! need_pass_2)
- {
- p = frag_more (length);
- bcopy (temp, p, length);
- }
- SKIP_WHITESPACE();
- c = * input_line_pointer ++;
- /* C contains 1st non-white character after number. */
- /* input_line_pointer -> just after terminator (c). */
- }
- }
- -- input_line_pointer; /* -> terminator (is not ','). */
- demand_empty_rest_of_line();
- } /* float_cons() */
-
- /*
- * stringer()
- *
- * We read 0 or more ',' seperated, double-quoted strings.
- *
- * Caller should have checked need_pass_2 is FALSE because we don't check it.
- */
- #ifdef I860
- void
- #else !defined(I860)
- static void
- #endif I860
- stringer(append_zero) /* Worker to do .ascii etc statements. */
- /* Checks end-of-line. */
- register int append_zero; /* 0: don't append '\0', else 1 */
- {
- /* register char * p; JF unused */
- /* register int length; JF unused */ /* Length of string we read, excluding */
- /* trailing '\0' implied by closing quote. */
- /* register char * where; JF unused */
- /* register fragS * fragP; JF unused */
- register int c;
-
- /*
- * The following awkward logic is to parse ZERO or more strings,
- * comma seperated. Recall a string expression includes spaces
- * before the opening '\"' and spaces after the closing '\"'.
- * We fake a leading ',' if there is (supposed to be)
- * a 1st, expression. We keep demanding expressions for each
- * ','.
- */
- if (is_it_end_of_statement())
- {
- c = 0; /* Skip loop. */
- ++ input_line_pointer; /* Compensate for end of loop. */
- }
- else
- {
- c = ','; /* Do loop. */
- }
- for ( ; c == ','; c = *input_line_pointer ++)
- {
- SKIP_WHITESPACE();
- if (* input_line_pointer == '\"')
- {
- ++ input_line_pointer; /* -> 1st char of string. */
- while ( (c = next_char_of_string()) >= 0 )
- {
- FRAG_APPEND_1_CHAR( c );
- }
- if (append_zero)
- {
- FRAG_APPEND_1_CHAR( 0 );
- }
- know( input_line_pointer [-1] == '\"' );
- }
- else
- {
- as_warn( "Expected \"-ed string" );
- }
- SKIP_WHITESPACE();
- }
- -- input_line_pointer;
- demand_empty_rest_of_line();
- } /* stringer() */
-
- static int
- next_char_of_string ()
- {
- register int c;
-
- c = * input_line_pointer ++;
- #ifdef NeXT /* allow 8 bit chars in strings */
- c = (c & MASK_CHAR); /* to make sure the 0xff char is not returned as -1 */
- #endif NeXT
- switch (c)
- {
- case '\"':
- c = -1;
- break;
-
- case '\\':
- switch (c = * input_line_pointer ++)
- {
- case 'b':
- c = '\b';
- break;
-
- case 'f':
- c = '\f';
- break;
-
- case 'n':
- c = '\n';
- break;
-
- case 'r':
- c = '\r';
- break;
-
- case 't':
- c = '\t';
- break;
-
- case '\\':
- case '"':
- break; /* As itself. */
-
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- {
- long int number;
-
- for (number = 0; isdigit(c); c = * input_line_pointer ++)
- {
- number = number * 8 + c - '0';
- }
- c = number;
- }
- -- input_line_pointer;
- break;
-
- case '\n':
- /* as_fatal( "Unterminated string - use app!" ); */
- /* To be compatible with BSD 4.2 as: give the luser a linefeed!! */
- c = '\n';
- break;
-
- default:
- as_warn( "Bad escaped character in string, '?' assumed" );
- c = '?';
- break;
- }
- break;
-
- default:
- break;
- }
- return (c);
- }
-
- static segT
- get_segmented_expression ( expP )
- register expressionS * expP;
- {
- register segT retval;
-
- if ( (retval = expression( expP )) == SEG_PASS1 || retval == SEG_NONE || retval == SEG_BIG )
- {
- as_warn("Expected address expression: absolute 0 assumed");
- retval = expP -> X_seg = SEG_ABSOLUTE;
- expP -> X_add_number = 0;
- expP -> X_add_symbol = expP -> X_subtract_symbol = 0;
- }
- return (retval); /* SEG_ ABSOLUTE,UNKNOWN,DATA,TEXT,BSS */
- }
-
- #ifdef I860
- segT
- #else !defined(I860)
- static segT
- #endif I860
- get_known_segmented_expression ( expP )
- register expressionS * expP;
- {
- register segT retval;
- register char * name1;
- register char * name2;
-
- if ( (retval = get_segmented_expression (expP)) == SEG_UNKNOWN
- )
- {
- name1 = expP -> X_add_symbol ? expP -> X_add_symbol -> sy_name : "";
- name2 = expP -> X_subtract_symbol ? expP -> X_subtract_symbol -> sy_name : "";
- if ( name1 && name2 )
- {
- as_warn("Symbols \"%s\" \"%s\" are undefined: absolute 0 assumed.",
- name1, name2);
- }
- else
- {
- as_warn("Symbol \"%s\" undefined: absolute 0 assumed.",
- name1 ? name1 : name2);
- }
- retval = expP -> X_seg = SEG_ABSOLUTE;
- expP -> X_add_number = 0;
- expP -> X_add_symbol = expP -> X_subtract_symbol = NULL;
- }
- know( retval == SEG_ABSOLUTE || retval == SEG_DATA || retval == SEG_TEXT || retval == SEG_BSS || retval == SEG_DIFFERENCE );
- return (retval);
- } /* get_known_segmented_expression() */
-
-
-
- /* static */ long int /* JF was static, but can't be if the MD pseudos are to use it */
- get_absolute_expression ()
- {
- expressionS exp;
- register segT s;
-
- if ( (s = expression(& exp)) != SEG_ABSOLUTE )
- {
- if ( s != SEG_NONE )
- {
- as_warn( "Bad Absolute Expression, absolute 0 assumed.");
- }
- exp . X_add_number = 0;
- }
- return (exp . X_add_number);
- }
-
- static char /* return terminator */
- get_absolute_expression_and_terminator( val_pointer)
- long int * val_pointer; /* return value of expression */
- {
- * val_pointer = get_absolute_expression ();
- return ( * input_line_pointer ++ );
- }
-
- /*
- * demand_copy_C_string()
- *
- * Like demand_copy_string, but return NULL if the string contains any '\0's.
- * Give a warning if that happens.
- */
- static char *
- demand_copy_C_string (len_pointer)
- int * len_pointer;
- {
- register char * s;
-
- if (s = demand_copy_string (len_pointer))
- {
- register int len;
-
- for (len = * len_pointer;
- len > 0;
- len--)
- {
- if (* s == 0)
- {
- s = 0;
- len = 1;
- * len_pointer = 0;
- as_warn( "This string may not contain \'\\0\'" );
- }
- }
- }
- return (s);
- }
-
- /*
- * demand_copy_string()
- *
- * Demand string, but return a safe (=private) copy of the string.
- * Return NULL if we can't read a string here.
- */
- static char *
- demand_copy_string (lenP)
- int * lenP;
- {
- register int c;
- register int len;
- char * retval;
-
- len = 0;
- SKIP_WHITESPACE();
- if (* input_line_pointer == '\"')
- {
- input_line_pointer ++; /* Skip opening quote. */
- while ( (c = next_char_of_string()) >= 0 ) {
- obstack_1grow ( ¬es, c );
- len ++;
- }
- /* JF this next line is so demand_copy_C_string will return a null
- termanated string. */
- obstack_1grow(¬es,'\0');
- retval=obstack_finish( ¬es);
- } else {
- as_warn( "Missing string" );
- retval = NULL;
- ignore_rest_of_line ();
- }
- * lenP = len;
- return (retval);
- }
-
- /*
- * is_it_end_of_statement()
- *
- * In: Input_line_pointer -> next character.
- *
- * Do: Skip input_line_pointer over all whitespace.
- *
- * Out: TRUE if input_line_pointer -> end-of-line.
- */
- static int
- is_it_end_of_statement()
- {
- SKIP_WHITESPACE();
- return (is_end_of_line [* input_line_pointer]);
- }
-
- void
- equals(sym_name)
- char *sym_name;
- {
- register struct symbol * symbolP; /* symbol we are working with */
-
- if(sym_name[0]=='.' && sym_name[1]=='\0') {
- /* Turn '. = mumble' into a .org mumble */
- register segT segment;
- expressionS exp;
- register char *p;
-
- if(input_line_pointer[1]=='=')
- input_line_pointer+=2;
- else
- *input_line_pointer++='='; /* Put it back */
- if(*input_line_pointer==' ' || *input_line_pointer=='\t')
- input_line_pointer++;
- segment = get_known_segmented_expression(& exp);
- if ( ! need_pass_2 ) {
- if (segment != now_seg && segment != SEG_ABSOLUTE)
- as_warn("Illegal segment \"%s\". Segment \"%s\" assumed.",
- seg_name [(int) segment], seg_name [(int) now_seg]);
- p = frag_var (rs_org, 1, 1, (relax_substateT)0, exp.X_add_symbol,
- exp.X_add_number, (char *)0);
- * p = 0;
- } /* if (ok to make frag) */
- return;
- }
-
- symbolP=symbol_find_or_make(sym_name);
- if(input_line_pointer[1]=='=')
- input_line_pointer+=2;
- else
- *input_line_pointer++='='; /* Put it back */
- pseudo_set(symbolP);
- }
-
- #ifdef NeXT /* the conditional assembly feature (.if, .else, and .endif) */
- void
- s_if()
- /*
- * DJA -- A pseudo op that does conditional assembly using
- * assembler defined expressions.
- */
- {
- if (if_depth >= MAX_IF_DEPTH)
- as_fatal ("You can't nest if's more than %d levels deep", MAX_IF_DEPTH);
- last_states [if_depth++] = the_cond_state;
- the_cond_state.the_cond = if_cond;
- if (the_cond_state.ignore)
- totally_ignore_line ();
- else
- {
- the_cond_state.cond_met = get_absolute_expression ();
- the_cond_state.ignore = !the_cond_state.cond_met;
- demand_empty_rest_of_line();
- }
- }
-
- void
- s_elseif()
- /*
- * DJA -- A pseudo op that does conditional assembly using
- * assembler defined expressions.
- */
- {
- register int last_ignore_state;
-
- if (the_cond_state.the_cond != if_cond &&
- the_cond_state.the_cond != elseif_cond)
- as_fatal ("Encountered a .elseif that doesn't follow a .if "
- "or an .elseif");
- the_cond_state.the_cond = elseif_cond;
-
- last_ignore_state = FALSE;
- if (if_depth)
- last_ignore_state = last_states [if_depth-1].ignore;
- if (last_ignore_state || the_cond_state.cond_met)
- {
- the_cond_state.ignore = TRUE;
- totally_ignore_line ();
- }
- else
- {
- the_cond_state.cond_met = get_absolute_expression ();
- the_cond_state.ignore = !the_cond_state.cond_met;
- demand_empty_rest_of_line();
- }
- }
-
- void
- s_else()
- /*
- * DJA -- A pseudo op that does conditional assembly using
- * assembler defined expressions.
- */
- {
- register int last_ignore_state;
-
- if (the_cond_state.the_cond != if_cond &&
- the_cond_state.the_cond != elseif_cond)
- as_fatal ("Encountered a .else that doesn't follow a .if "
- " or an .elseif");
- the_cond_state.the_cond = else_cond;
- last_ignore_state = FALSE;
- if (if_depth)
- last_ignore_state = last_states [if_depth-1].ignore;
- if (last_ignore_state || the_cond_state.cond_met)
- the_cond_state.ignore = TRUE;
- else
- the_cond_state.ignore = FALSE;
- demand_empty_rest_of_line();
- }
-
- void
- s_endif()
- /*
- * DJA -- A pseudo op that does conditional assembly using
- * assembler defined expressions.
- */
- {
- if ((the_cond_state.the_cond == no_cond) || (if_depth == 0))
- as_fatal ("Encountered a .endif that doesn't follow a .if or .else");
- the_cond_state = last_states [--if_depth];
- demand_empty_rest_of_line();
- }
-
- void
- totally_ignore_line() /* Ignores lines during conditional assembly. */
- {
- if ( ! is_end_of_line [* input_line_pointer])
- {
- while ( input_line_pointer < buffer_limit
- && ! is_end_of_line [* input_line_pointer] )
- {
- input_line_pointer ++;
- }
- }
- input_line_pointer ++; /* Return pointing just after end-of-line. */
- know( is_end_of_line [input_line_pointer [-1]] );
- }
- #endif NeXT /* the conditional assembly feature (.if, .else, and .endif) */
-
- #ifdef NeXT /* the .macro feature */
- void
- s_macros_on()
- {
- macros_on = TRUE;
- demand_empty_rest_of_line();
- }
-
- void
- s_macros_off()
- {
- macros_on = FALSE;
- demand_empty_rest_of_line();
- }
-
- void
- s_macro()
- /*
- * DJA -- define macros
- */
- {
- register int c;
- pseudo_typeS *pop;
-
- if (macro_name)
- as_warn ("Can't define a macro inside another macro definition");
- else
- {
- SKIP_WHITESPACE();
- while (is_part_of_name (c = * input_line_pointer ++))
- obstack_1grow (¯os, c);
- obstack_1grow (¯os, '\0');
- -- input_line_pointer;
- macro_name = obstack_finish (¯os);
- if (macro_name == "")
- as_warn ("Missing name of macro");
- if(*macro_name == '.')
- {
- pop = (pseudo_typeS *)hash_find(po_hash, macro_name+1);
- if(pop != NULL)
- as_warn ("Pseudo-op name: %s can't be a macro name", macro_name);
- }
- }
- totally_ignore_line ();
- } /* s_macro */
-
- void
- s_endmacro()
- /*
- * DJA -- end macro definition
- */
- {
- char * errorString;
-
- if (!macro_name)
- {
- as_warn ("This .endmacro does not match with a preceeding .macro");
- ignore_rest_of_line();
- }
- else
- {
- obstack_1grow (¯os, '\0');
- errorString = hash_insert (ma_hash, macro_name, obstack_finish(¯os));
- if (* errorString)
- as_warn ("The macro named \"%s\" is already defined", macro_name);
- macro_name = FALSE;
- }
- } /* s_endmacro */
-
- static void
- ma_begin()
- /*
- * DJA -- initialize macros
- */
- {
- ma_hash = hash_new ();
- obstack_begin (¯os, 5000);
- } /* ma_begin() */
-
- void
- add_to_macro_definition (char_pointer)
- /*
- * DJA -- Store the contents of a macro into the obstack
- */
- register char * char_pointer;
- {
- register char c;
-
- do
- {
- c = * char_pointer ++;
- know (c != '\0');
- obstack_1grow (¯os, c);
- }
- while ((c != ':') && !(is_end_of_line [c]));
- if (char_pointer > input_line_pointer)
- input_line_pointer = char_pointer;
- }
-
- static
- void
- expand_macro (macro_contents)
- register char * macro_contents;
- /*
- * DJA -- expand macros
- */
- {
- char * buffer;
- register char c;
- register int index, nargs;
- char * last_buffer_limit;
- int last_count_lines;
- char * last_input_line_pointer;
- char * arguments [10]; /* at most 10 arguments, each is substituted */
-
- if (macro_depth >= MAX_MACRO_DEPTH)
- as_fatal ("You can't nest macro's more than %d levels deep",
- MAX_MACRO_DEPTH);
- macro_depth++;
-
- /* copy each argument to a object in the macro obstack */
- nargs = 0;
- for (index = 0; index < 10; index ++)
- {
- if (* input_line_pointer == ' ')
- ++ input_line_pointer;
- know (* input_line_pointer != ' ');
- if (is_end_of_line [c = * input_line_pointer])
- arguments [index] = NULL;
- else
- {
- register int parenthesis_depth = 0;
- do
- {
- c = * input_line_pointer ++;
- if (parenthesis_depth)
- {
- if (c == ')')
- parenthesis_depth --;
- }
- else
- {
- if (c == '(')
- parenthesis_depth ++;
- else
- if ( is_end_of_line [c] || (c == ' ') || (c == ',') )
- break;
- }
- know (c != '\0');
- if (is_end_of_line [c])
- as_warn ("missmatched parenthesis");
- obstack_1grow (¯os, c);
- }
- while (1);
- obstack_1grow (¯os, '\0');
- arguments [index] = obstack_finish (¯os);
- nargs++;
- if (is_end_of_line [c])
- -- input_line_pointer;
- else if (c == ' ')
- if (* input_line_pointer == ',')
- input_line_pointer++;
- }
- }
- if (!is_end_of_line [c])
- {
- as_warn ("More than 10 arguments not allowed for macros");
- ignore_rest_of_line();
- }
- /* build a buffer containing the macro contents with arguments substituted */
- obstack_1grow (¯os, '\n');
- while (c = * macro_contents ++)
- {
- if (c == '$')
- {
- if ((*macro_contents >= '0') && (*macro_contents <= '9'))
- {
- index = *macro_contents ++ - '0';
- last_input_line_pointer = macro_contents;
- macro_contents = arguments [index];
- if (macro_contents)
- {
- while (c = * macro_contents ++)
- obstack_1grow (¯os, c);
- }
- macro_contents = last_input_line_pointer;
- continue;
- }
- else if (*macro_contents == 'n')
- {
- macro_contents ++ ;
- obstack_1grow (¯os, nargs + '0');
- continue;
- }
- }
- obstack_1grow (¯os, c);
- }
- obstack_1grow (¯os, '\n');
- obstack_1grow (¯os, '\0');
- last_buffer_limit = buffer_limit;
- last_count_lines = count_lines;
- last_input_line_pointer = input_line_pointer;
- buffer_limit = obstack_next_free (¯os) - 1;
- buffer = obstack_finish (¯os);
- count_lines = FALSE;
- /*
- printf("expanded macro: %s", buffer + 1);
- */
- parse_a_buffer (buffer + 1);
- obstack_free (¯os, buffer);
- for (index = 9; index >= 0; index --)
- if (arguments [index])
- obstack_free (¯os, arguments [index]);
- buffer_limit = last_buffer_limit;
- count_lines = last_count_lines;
- input_line_pointer = last_input_line_pointer;
- macro_depth--;
- }
- #endif NeXT /* the .macro feature */
-
- #ifdef NeXT /* the .dump/.load feature */
- void
- s_dump()
- /*
- * DJA -- A pseudo op that does a quick binary dump of symbol tables.
- */
- {
- register char * filename;
- int length;
- static char null_string [] = "";
-
- char * write_macro ();
- char * write_symbol ();
-
- /* Some assemblers tolerate immediately following '"' */
- if ( filename = demand_copy_string( & length ) ) {
- demand_empty_rest_of_line();
- if (dump_fp = fopen(filename, "w+"))
- {
- hash_apply (ma_hash, write_macro);
- fwrite (null_string, 1, 1, dump_fp);
- hash_apply (sy_hash, write_symbol);
- fwrite (null_string, 1, 1, dump_fp);
- fclose (dump_fp);
- }
- else
- as_warn ("couldn't write to dump file: \"%s\"", filename);
- }
- }
-
- char *
- write_macro (string, value)
- /*
- * DJA -- Used by hash_apply to write one macro.
- */
- register char * string;
- register char * value;
- {
- know (string);
- know (value);
- know (strlen (string));
- fwrite (string, (strlen (string) + 1), 1, dump_fp);
- fwrite (value, (strlen (value) + 1), 1, dump_fp);
- return NULL;
- }
-
- char *
- write_symbol (string, symbolP)
- /*
- * DJA -- Used by hash_apply to write one N_ABS symbol and its value.
- */
- register char * string;
- register symbolS * symbolP;
- {
- know (symbolP);
- if (((symbolP -> sy_type) & N_TYPE) == N_ABS)
- {
- know (string);
- know (strlen (string));
- fwrite (string, (strlen (string) + 1), 1, dump_fp);
- fwrite (& (symbolP -> sy_value), 4, 1, dump_fp);
- }
- return NULL;
- }
-
- void
- s_load()
- /*
- * DJA -- A pseudo op that does a quick binary load of symbol tables.
- */
- {
- register char * char_pointer;
- register char * filename;
- int length;
- register char the_char;
- register symbolS * the_symbol;
- symbolS * temp_symbol_lastP;
- static symbolS * dump_symbol_lastP;
-
- extern symbolS * symbol_find_or_make ();
-
- /* Some assemblers tolerate immediately following '"' */
- if ( filename = demand_copy_string( & length ) )
- {
- demand_empty_rest_of_line();
- if (dump_fp = fopen(filename, "r+"))
- {
- do
- {
- do
- {
- the_char = getc (dump_fp);
- obstack_1grow (¯os, the_char);
- }
- while (the_char);
- char_pointer = obstack_finish (¯os);
- if (!(*char_pointer))
- break;
- do
- {
- the_char = getc (dump_fp);
- obstack_1grow (¯os, the_char);
- }
- while (the_char);
- if (* hash_insert (ma_hash, char_pointer, obstack_finish(¯os)))
- as_warn ("a macro named \"%s\" encountered in a .load is already defined", char_pointer);
- }
- while (1);
- /*
- * We don't want to link in symbols that were loaded so they don't go out in the
- * object file. Instead these symbols should go out in the object file that did
- * the .dump
- */
- temp_symbol_lastP = symbol_lastP;
- symbol_lastP = dump_symbol_lastP;
- do
- {
- do
- {
- the_char = getc (dump_fp);
- obstack_1grow (¯os, the_char);
- }
- while (the_char);
- char_pointer = obstack_base (¯os);
- obstack_next_free (¯os) = char_pointer;
- if (!(*char_pointer))
- break;
- the_symbol = symbol_find_or_make (char_pointer);
- the_symbol -> sy_type = N_ABS;
- char_pointer = (char *) &the_symbol -> sy_value;
- * char_pointer ++ = getc (dump_fp);
- * char_pointer ++ = getc (dump_fp);
- * char_pointer ++ = getc (dump_fp);
- * char_pointer ++ = getc (dump_fp);
- the_symbol -> sy_frag = & zero_address_frag;
- }
- while (1);
- dump_symbol_lastP = symbol_lastP;
- symbol_lastP = temp_symbol_lastP;
- fclose (dump_fp);
- }
- else
- as_fatal ("Couldn't find the dump file: \"%s\"", filename);
- }
- }
- #endif NeXT /* the .dump/.load feature */
- /* end: read.c */
-