Annotation of GNUtools/cctools/as/read.c, revision 1.1

1.1     ! root        1: /* read.c - read a source file -
        !             2:    Copyright (C) 1986,1987 Free Software Foundation, Inc.
        !             3: 
        !             4: This file is part of GAS, the GNU Assembler.
        !             5: 
        !             6: GAS is free software; you can redistribute it and/or modify
        !             7: it under the terms of the GNU General Public License as published by
        !             8: the Free Software Foundation; either version 1, or (at your option)
        !             9: any later version.
        !            10: 
        !            11: GAS is distributed in the hope that it will be useful,
        !            12: but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            14: GNU General Public License for more details.
        !            15: 
        !            16: You should have received a copy of the GNU General Public License
        !            17: along with GAS; see the file COPYING.  If not, write to
        !            18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
        !            19: 
        !            20: #define MASK_CHAR (0xFF)       /* If your chars aren't 8 bits, you will
        !            21:                                   change this a bit.  But then, GNU isn't
        !            22:                                   spozed to run on your machine anyway.
        !            23:                                   (RMS is so shortsighted sometimes.)
        !            24:                                 */
        !            25: 
        !            26: #define MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT (16)
        !            27:                                /* This is the largest known floating point */
        !            28:                                /* format (for now). It will grow when we */
        !            29:                                /* do 4361 style flonums. */
        !            30: 
        !            31: 
        !            32: /* Routines that read assembler source text to build spagetti in memory. */
        !            33: /* Another group of these functions is in the expr.c module */
        !            34: 
        !            35: #include <ctype.h>
        !            36: #include <string.h>
        !            37: #include <stdlib.h>
        !            38: #include <sys/types.h>
        !            39: #include <sys/stat.h>
        !            40: #include "stuff/round.h"
        !            41: #include "as.h"
        !            42: #include "flonum.h"
        !            43: #include "struc-symbol.h"
        !            44: #include "expr.h"
        !            45: #include "read.h"
        !            46: #include "hash.h"
        !            47: #include "obstack.h"
        !            48: #include "md.h"
        !            49: #include "symbols.h"
        !            50: #include "sections.h"
        !            51: #include "input-scrub.h"
        !            52: #include "input-file.h"
        !            53: #include "hex_value.h"
        !            54: #include "messages.h"
        !            55: #include "xmalloc.h"
        !            56: #include "app.h"
        !            57: 
        !            58: /*
        !            59:  * Parsing of input is done off of this pointer which points to the next char
        !            60:  * of source file to parse.
        !            61:  */
        !            62: char *input_line_pointer = NULL;
        !            63: 
        !            64: /*
        !            65:  * buffer_limit is the value returned by the input_scrub_next_buffer() in
        !            66:  * read_a_source_file() and is not static only so read_an_include_file can save
        !            67:  * and restore it.
        !            68:  */
        !            69: char *buffer_limit = NULL;     /* -> 1 + last char in buffer. */
        !            70: 
        !            71: /*
        !            72:  * This table is used by the macros is_name_beginner() and is_part_of_name()
        !            73:  * defined in read.h .
        !            74:  */
        !            75: const char lex_type[256] = {
        !            76:   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,       /* @ABCDEFGHIJKLMNO */
        !            77:   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,       /* PQRSTUVWXYZ[\]^_ */
        !            78:   0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0,       /* _!"#$%&'()*+,-./ */
        !            79:   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,       /* 0123456789:;<=>? */
        !            80:   0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,       /* @ABCDEFGHIJKLMNO */
        !            81:   3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3,       /* PQRSTUVWXYZ[\]^_ */
        !            82:   0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,       /* `abcdefghijklmno */
        !            83:   3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0,       /* pqrstuvwxyz{|}~. */
        !            84:   3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,      /* Allow all chars  */
        !            85:   3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,      /* with the high bit */
        !            86:   3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,      /* set in names */
        !            87:   3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
        !            88:   3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
        !            89:   3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
        !            90:   3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 
        !            91: };
        !            92: 
        !            93: /*
        !            94:  * In: a character.
        !            95:  * Out: TRUE if this character ends a line.
        !            96:  */
        !            97: #define _ (0)
        !            98: static const char is_end_of_line[256] = {
        !            99:   _, _, _, _, _, _, _, _, _, _,99, _, _, _, _, _, /* @abcdefghijklmno */
        !           100:   _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
        !           101:   _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
        !           102:   _, _, _, _, _, _, _, _, _, _, _,99, _, _, _, _, /* 0123456789:;<=>? */
        !           103: #if defined(M88K) || defined(M98K) || defined(HPPA)
        !           104:  99, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* @ABCDEFGHIJKLMNO */
        !           105: #else
        !           106:   _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
        !           107: #endif
        !           108:   _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
        !           109:   _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
        !           110:   _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
        !           111:   _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
        !           112:   _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
        !           113:   _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
        !           114:   _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /*                  */
        !           115:   _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _  /*                  */
        !           116: };
        !           117: #undef _
        !           118: 
        !           119: /*
        !           120:  * The conditional assembly feature (.if, .else, .elseif and .endif) is
        !           121:  * implemented with cond_state that tells us what we are in the middle of 
        !           122:  * processing.  ignore can be either TRUE or FALSE.  When TRUE we are ignoring
        !           123:  * the block of code in the middle of a conditional.  MAX_IF_DEPTH is the
        !           124:  * maximum depth that if's can be nested.
        !           125:  */
        !           126: #define MAX_IF_DEPTH 20
        !           127: typedef enum {
        !           128:     no_cond,   /* no conditional is being processed */
        !           129:     if_cond,   /* inside if conditional */
        !           130:     elseif_cond,/* inside elseif conditional */
        !           131:     else_cond  /* inside else conditional */
        !           132: }cond_type;
        !           133: 
        !           134: struct cond_state {
        !           135:     cond_type  the_cond;
        !           136:     int                cond_met;
        !           137:     int                ignore;
        !           138: };
        !           139: typedef struct cond_state cond_stateS;
        !           140: static cond_stateS the_cond_state = {no_cond, FALSE, FALSE};
        !           141: static cond_stateS last_states[MAX_IF_DEPTH];
        !           142: static int if_depth = 0;
        !           143: 
        !           144: /*
        !           145:  * Assembler macros are implemented with these variables and functions.
        !           146:  */
        !           147: #define MAX_MACRO_DEPTH 20
        !           148: static int macro_depth = 0;
        !           149: static struct hash_control
        !           150:        *ma_hash = NULL;        /* use before set up: NULL-> address error */
        !           151: static struct obstack macros;  /* obstack for macro text */
        !           152: static char *macro_name = NULL;        /* name of macro we are defining */
        !           153: static int count_lines = TRUE; /* turns line number counting on and off */
        !           154: static int macros_on = TRUE;   /* .macros_on and .macros_off toggles this to
        !           155:                                   allow macros to be turned off, which allows
        !           156:                                   macros to override a machine instruction and
        !           157:                                   still use it. */
        !           158: static void expand_macro(char *macro_contents);
        !           159: static void macro_begin(void);
        !           160: 
        !           161: 
        !           162: /*
        !           163:  * The .dump and .load feature is implemented with these variables and
        !           164:  * functions.
        !           165:  */
        !           166: static FILE *dump_fp = NULL;
        !           167: static char *write_macro(char *string, char *value);
        !           168: static char * write_symbol(char *string, char *value);
        !           169: 
        !           170: 
        !           171: /* Functions private to this file */
        !           172: static void parse_a_buffer(char *buffer);
        !           173: static void parse_line_comment(char **buffer);
        !           174: static segT get_segmented_expression(expressionS *expP);
        !           175: static void pseudo_op_begin(void);
        !           176: static void pseudo_set(symbolS *symbolP);
        !           177: static void stab(int what);
        !           178: static char get_absolute_expression_and_terminator(long *val_pointer);
        !           179: static char *demand_copy_C_string(int *len_pointer);
        !           180: static char *demand_copy_string(int *lenP);
        !           181: static int is_it_end_of_statement(void);
        !           182: static void equals(char *sym_name);
        !           183: static int next_char_of_string(void);
        !           184: 
        !           185: #ifdef M68K /* we allow big cons only on the 68k machines */
        !           186: /*
        !           187:  * This is setup by read_begin() and used by big_cons() with using grow_bignum()
        !           188:  * to make it bigger if needed.
        !           189:  */
        !           190: #define BIGNUM_BEGIN_SIZE (16)
        !           191: static char *bignum_low;  /* Lowest char of bignum. */
        !           192: static char *bignum_limit;/* 1st illegal address of bignum. */
        !           193: static char *bignum_high; /* Highest char of bignum, may point to
        !           194:                             (bignum_start-1), never >= bignum_limit. */
        !           195: static void grow_bignum(void);
        !           196: #endif /* M68K */
        !           197: /*
        !           198:  * This is set in read_a_source_file() to the section number of the text section
        !           199:  * for used by the machine dependent md_assemble() to create line number stabs
        !           200:  * for assembly instructions in the text section when -g is seen.
        !           201:  */
        !           202: unsigned long text_nsect = 0;
        !           203: 
        !           204: /*
        !           205:  * These are the names of the section types used by the .section directive.
        !           206:  */
        !           207: struct type_name {
        !           208:     char *name;
        !           209:     unsigned type;
        !           210: };
        !           211: static struct type_name type_names[] = {
        !           212:     { "regular",                 S_REGULAR },
        !           213:     { "cstring_literals",        S_CSTRING_LITERALS },
        !           214:     { "4byte_literals",                  S_4BYTE_LITERALS },
        !           215:     { "8byte_literals",                  S_8BYTE_LITERALS },
        !           216:     { "literal_pointers",        S_LITERAL_POINTERS },
        !           217:     { "non_lazy_symbol_pointers", S_NON_LAZY_SYMBOL_POINTERS },
        !           218:     { "lazy_symbol_pointers",    S_LAZY_SYMBOL_POINTERS },
        !           219:     { "symbol_stubs",            S_SYMBOL_STUBS },
        !           220:     { "mod_init_funcs",                  S_MOD_INIT_FUNC_POINTERS },
        !           221:     { NULL, 0 }
        !           222: };
        !           223: 
        !           224: /*
        !           225:  * These are the names of the section attributes used by the .section directive.
        !           226:  */
        !           227: struct attribute_name {
        !           228:     char *name;
        !           229:     unsigned attribute;
        !           230: };
        !           231: static struct attribute_name attribute_names[] = {
        !           232:     { "none",    0 },
        !           233:     { "pure_instructions", S_ATTR_PURE_INSTRUCTIONS },
        !           234:     { "reloc_at_launch",   S_ATTR_RELOC_AT_LAUNCH },
        !           235:     { NULL, 0 }
        !           236: };
        !           237: 
        !           238: /*
        !           239:  * These are the built in sections know to the assembler with a directive.
        !           240:  * They are known as which segment and section name as well as the type &
        !           241:  * attribute, and default alignment.
        !           242:  */
        !           243: struct builtin_section {
        !           244:     char *directive;
        !           245:     char *segname;
        !           246:     char *sectname;
        !           247:     unsigned long flags; /* type & attribute */
        !           248:     unsigned long default_align;
        !           249:     unsigned long sizeof_stub;
        !           250: };
        !           251: static const struct builtin_section builtin_sections[] = {
        !           252:     /*
        !           253:      * The text section must be first in this list as it is used by
        !           254:      * read_a_source_file() to do the equivalent of a .text at the start
        !           255:      * of the file and for s_builtin_section() to set S_ATTR_PURE_INSTRUCTIONS.
        !           256:      */
        !           257:     { "text",                "__TEXT", "__text" },
        !           258:     { "const",               "__TEXT", "__const" },
        !           259:     { "static_const",        "__TEXT", "__static_const" },
        !           260:     { "cstring",             "__TEXT", "__cstring", S_CSTRING_LITERALS },
        !           261:     { "literal4",            "__TEXT", "__literal4", S_4BYTE_LITERALS, 2 },
        !           262:     { "literal8",            "__TEXT", "__literal8", S_8BYTE_LITERALS, 3 },
        !           263:     { "constructor",         "__TEXT", "__constructor" },
        !           264:     { "destructor",          "__TEXT", "__destructor" },
        !           265:     { "fvmlib_init0",        "__TEXT", "__fvmlib_init0" },
        !           266:     { "fvmlib_init1",        "__TEXT", "__fvmlib_init1" },
        !           267:     { "mod_init_func",      "__TEXT", "__mod_init_func",
        !           268:                S_MOD_INIT_FUNC_POINTERS, 2 },
        !           269:     { "symbol_stub",        "__TEXT", "__symbol_stub",
        !           270:                S_SYMBOL_STUBS | S_ATTR_PURE_INSTRUCTIONS,
        !           271: #if defined(M68K)
        !           272:                1, 20
        !           273: #endif
        !           274: #if defined(I386)
        !           275:                0, 16
        !           276: #endif
        !           277: #if defined(HPPA)
        !           278:                2, 28
        !           279: #endif
        !           280: #if defined(SPARC)
        !           281:                  2, 30
        !           282: #endif
        !           283:                },
        !           284:     { "picsymbol_stub",             "__TEXT", "__picsymbol_stub",
        !           285:                S_SYMBOL_STUBS | S_ATTR_PURE_INSTRUCTIONS,
        !           286: #if defined(M68K)
        !           287:                1, 24
        !           288: #endif
        !           289: #if defined(I386)
        !           290:                0, 26
        !           291: #endif
        !           292: #if defined(HPPA)
        !           293:                2, 32
        !           294: #endif
        !           295: #if defined(SPARC)
        !           296:                  2, 40
        !           297: #endif
        !           298:                },
        !           299:     { "non_lazy_symbol_pointer","__DATA","__nl_symbol_ptr",
        !           300:                S_NON_LAZY_SYMBOL_POINTERS, 2 },
        !           301:     { "lazy_symbol_pointer", "__DATA", "__la_symbol_ptr",
        !           302:                S_LAZY_SYMBOL_POINTERS, 2 },
        !           303:     { "dyld",               "__DATA", "__dyld" },
        !           304:     { "data",                "__DATA", "__data" },
        !           305:     { "static_data",         "__DATA", "__static_data" },
        !           306:     { "objc_class",          "__OBJC", "__class" },
        !           307:     { "objc_meta_class",     "__OBJC", "__meta_class" },
        !           308:     { "objc_string_object",  "__OBJC", "__string_object" },
        !           309:     { "objc_protocol",       "__OBJC", "__protocol" },
        !           310:     { "objc_cat_cls_meth",   "__OBJC", "__cat_cls_meth" },
        !           311:     { "objc_cat_inst_meth",  "__OBJC", "__cat_inst_meth" },
        !           312:     { "objc_cls_meth",       "__OBJC", "__cls_meth" },
        !           313:     { "objc_inst_meth",      "__OBJC", "__inst_meth" },
        !           314:     { "objc_message_refs",   "__OBJC", "__message_refs", S_LITERAL_POINTERS, 2},
        !           315:     { "objc_cls_refs",       "__OBJC", "__cls_refs",     S_LITERAL_POINTERS, 2},
        !           316:     { "objc_class_names",    "__OBJC", "__class_names", S_CSTRING_LITERALS },
        !           317:     { "objc_module_info",    "__OBJC", "__module_info" },
        !           318:     { "objc_symbols",        "__OBJC", "__symbols" },
        !           319:     { "objc_category",       "__OBJC", "__category" },
        !           320:     { "objc_meth_var_types", "__OBJC", "__meth_var_types", S_CSTRING_LITERALS },
        !           321:     { "objc_class_vars",     "__OBJC", "__class_vars" },
        !           322:     { "objc_instance_vars",  "__OBJC", "__instance_vars" },
        !           323:     { "objc_meth_var_names", "__OBJC", "__meth_var_names", S_CSTRING_LITERALS },
        !           324:     { "objc_selector_strs",  "__OBJC", "__selector_strs", S_CSTRING_LITERALS },
        !           325:     { 0 }
        !           326: };
        !           327: 
        !           328: /* set up pseudo-op tables */
        !           329: static struct hash_control *po_hash = NULL;
        !           330: 
        !           331: #if !defined(I860) /* i860 has it's own align and org */
        !           332: static void s_align(int value);
        !           333: static void s_org(int value);
        !           334: #endif
        !           335: static void s_private_extern(int value);
        !           336: static void s_indirect_symbol(int value);
        !           337: static void s_abort(int value);
        !           338: static void s_comm(int value);
        !           339: static void s_desc(int value);
        !           340: static void s_file(int value);
        !           341: static void s_fill(int value);
        !           342: static void s_lcomm(int value);
        !           343: static void s_lsym(int value);
        !           344: static void s_set(int value);
        !           345: static void s_reference(int value);
        !           346: static void s_lazy_reference(int value);
        !           347: static void s_include(int value);
        !           348: static void s_dump(int value);
        !           349: static void s_load(int value);
        !           350: static void s_if(int value);
        !           351: static void s_elseif(int value);
        !           352: static void s_else(int value);
        !           353: static void s_endif(int value);
        !           354: static void s_macros_on(int value);
        !           355: static void s_macros_off(int value);
        !           356: static void s_section(int value);
        !           357: static void s_zerofill(int value);
        !           358: static unsigned long s_builtin_section(const struct builtin_section *s);
        !           359: 
        !           360: /*
        !           361:  * The machine independent pseudo op table.
        !           362:  */
        !           363: static const pseudo_typeS pseudo_table[] = {
        !           364: #if !defined(I860) /* i860 has it's own align and org */
        !           365:   { "align",   s_align,        0       },
        !           366:   { "org",     s_org,          0       },
        !           367: #endif
        !           368: #ifndef M88K /* m88k has it's own abs that uses the s_abs() in here */
        !           369:   { "abs",     s_abs,          0       },
        !           370: #endif
        !           371:   { "private_extern",  s_private_extern, 0},
        !           372:   { "indirect_symbol", s_indirect_symbol, 0},
        !           373:   { "abort",   s_abort,        0       },
        !           374:   { "ascii",   stringer,       0       },
        !           375:   { "asciz",   stringer,       1       },
        !           376:   { "byte",    cons,           1       },
        !           377:   { "comm",    s_comm,         0       },
        !           378:   { "desc",    s_desc,         0       },
        !           379:   { "double",  float_cons,     'd'     },
        !           380:   { "file",    s_file,         0       },
        !           381:   { "fill",    s_fill,         0       },
        !           382:   { "globl",   s_globl,        0       },
        !           383:   { "lcomm",   s_lcomm,        0       },
        !           384:   { "line",    s_line,         0       },
        !           385:   { "long",    cons,           4       },
        !           386:   { "lsym",    s_lsym,         0       },
        !           387:   { "section", s_section,      0       },
        !           388:   { "zerofill",        s_zerofill,     0       },
        !           389:   { "set",     s_set,          0       },
        !           390:   { "short",   cons,           2       },
        !           391:   { "single",  float_cons,     'f'     },
        !           392:   { "space",   s_space,        0       },
        !           393:   { "stabd",   stab,           'd'     },
        !           394:   { "stabn",   stab,           'n'     },
        !           395:   { "stabs",   stab,           's'     },
        !           396:   { "reference",s_reference,   0       },
        !           397:   { "lazy_reference",s_lazy_reference, 0       },
        !           398:   { "include", s_include,      0       },
        !           399:   { "macro",   s_macro,        0       },
        !           400:   { "endmacro",        s_endmacro,     0       },
        !           401:   { "macros_on",s_macros_on,   0       },
        !           402:   { "macros_off",s_macros_off, 0       },
        !           403:   { "if",      s_if,           0       },
        !           404:   { "elseif",  s_elseif,       0       },
        !           405:   { "else",    s_else,         0       },
        !           406:   { "endif",   s_endif,        0       },
        !           407:   { "dump",    s_dump,         0       },
        !           408:   { "load",    s_load,         0       },
        !           409:   { NULL }     /* end sentinel */
        !           410: };
        !           411: 
        !           412: /*
        !           413:  * read_begin() initializes the assember to read assembler source input.
        !           414:  */
        !           415: void
        !           416: read_begin(
        !           417: void)
        !           418: {
        !           419:       pseudo_op_begin();
        !           420:       macro_begin();
        !           421:       obstack_begin(&notes, 5000);
        !           422: 
        !           423: #ifdef M68K /* we allow big cons only on the 68k machines */
        !           424:       bignum_low = xmalloc((long)BIGNUM_BEGIN_SIZE);
        !           425:       bignum_limit = bignum_low + BIGNUM_BEGIN_SIZE;
        !           426: #endif
        !           427: }
        !           428: 
        !           429: /*
        !           430:  * pseudo_op_begin() creates a hash table of pseudo ops from the machine
        !           431:  * independent and machine dependent pseudo op tables.
        !           432:  */
        !           433: static
        !           434: void
        !           435: pseudo_op_begin(
        !           436: void)
        !           437: {
        !           438:     char *errtxt;
        !           439:     const pseudo_typeS *pop;
        !           440:     unsigned long i;
        !           441:     pseudo_typeS *sections_pseudo_table;
        !           442: 
        !           443:        po_hash = hash_new();
        !           444:        errtxt = "";
        !           445:        for(pop = pseudo_table; pop->poc_name && *errtxt == '\0'; pop++)
        !           446:            errtxt = hash_insert(po_hash, pop->poc_name, (char *)pop);
        !           447: 
        !           448:        for(pop = md_pseudo_table; pop->poc_name && *errtxt == '\0'; pop++)
        !           449:            errtxt = hash_insert(po_hash, pop->poc_name, (char *)pop);
        !           450: 
        !           451:        for(i = 0; builtin_sections[i].directive != NULL; i++)
        !           452:            ;
        !           453:        sections_pseudo_table = xmalloc((i + 1) * sizeof(pseudo_typeS));
        !           454:        for(i = 0; builtin_sections[i].directive != NULL; i++){
        !           455:            sections_pseudo_table[i].poc_name = builtin_sections[i].directive;
        !           456:            sections_pseudo_table[i].poc_handler =
        !           457:                                              (void (*)(int))s_builtin_section;
        !           458:            sections_pseudo_table[i].poc_val = (int)(builtin_sections + i);
        !           459:        }
        !           460:        sections_pseudo_table[i].poc_name = NULL;
        !           461:        for(pop = (const pseudo_typeS *)sections_pseudo_table;
        !           462:            pop->poc_name && *errtxt == '\0';
        !           463:            pop++)
        !           464:            errtxt = hash_insert(po_hash, pop->poc_name, (char *)pop);
        !           465: 
        !           466:        if(*errtxt != '\0'){
        !           467:            as_fatal("error constructing pseudo-op table (%s)", errtxt);
        !           468:        }
        !           469: }
        !           470: 
        !           471: /*
        !           472:  * The NeXT version of: read_a_source_file()
        !           473:  *
        !           474:  * This differs from the GNU version by taking the guts of the GNU
        !           475:  * read_a_source_file() (with the outer most loop removed) and renaming it
        !           476:  * parse_a_buffer().  With the NeXT version of read_a_source file simply
        !           477:  * containing that outer loop and a call to parse_a_buffer().  This is done
        !           478:  * So that expand_macro() and parse_line_comment() can call parse_a_buffer()
        !           479:  * with the buffers they create.
        !           480:  */
        !           481: void
        !           482: read_a_source_file(
        !           483: char *buffer)  /* 1st character of each buffer of lines is here. */
        !           484: {
        !           485:     cond_stateS        starting_cond_state;
        !           486:     short starting_if_depth;
        !           487: 
        !           488:     symbolS *symbolP;
        !           489: 
        !           490:        starting_cond_state = the_cond_state;
        !           491:        starting_if_depth = if_depth;
        !           492: 
        !           493:        /* Do not change segments or subsegments if this is a .include */
        !           494:        if(doing_include == FALSE){
        !           495:            /*
        !           496:             * This is a new file so switch start as if a .text was seen.  This
        !           497:             * call to s_builtin_section() relys on the fact that the text
        !           498:             * section is first in the built in sections list.
        !           499:             */
        !           500:            if(flagseen['n'] == FALSE)
        !           501:                text_nsect = s_builtin_section(builtin_sections);
        !           502: 
        !           503:            /*
        !           504:             * If the -g flag is present generate the lead stabs for this
        !           505:             * physical file that is not an include file.  Each physical file's
        !           506:             * stabs are enclosed by a pair of source name stabs, N_SO, (one at
        !           507:             * the begining of the file with the name of the file and one at the
        !           508:             * end with the name "").  This is seen by nm(1) as:
        !           509:             *  00000000 - 01 0000    SO {standard input}
        !           510:             *  ...
        !           511:             *  00000020 - 01 0000    SO
        !           512:             * To make the debugger work line numbers stabs, N_SLINE, must be
        !           513:             * contained "in a function" (after a function stab, N_FUN).  To
        !           514:             * make a function stab work it must have a type number.  Since type
        !           515:             * numbers 1 and 2 (the 1 in "int:t1=..." and the 2 in "char:t2=..."
        !           516:             * are "magic" to the debugger we use type 3 for the types of the
        !           517:             * function stabs we generate for each text label (see the routine
        !           518:             * make_stab_for_symbol() in symbols.c).  So at lead stabs at the
        !           519:             * begining of each physical file include three type stabs, L_LSYM
        !           520:             * with the correct symbol name.  The since we must have the types
        !           521:             * 1 and 2 they are just what the 'C' would produce but we don't
        !           522:             * use them.  Type 3 is the void type like the 'C' compiler would
        !           523:             * produce which we use for the function stabs' type.  These three
        !           524:             * look like this to nm(1):
        !           525:             *  00000000 - 00 0000  LSYM int:t1=r1;-2147483648;2147483647;
        !           526:             *  00000000 - 00 0000  LSYM char:t2=r2;0;127;
        !           527:             *  00000000 - 00 0000  LSYM void:t3=3
        !           528:             *
        !           529:             * Then for each text label we see, make_stab_for_symbol() will
        !           530:             * generate a stab like this (for the example lable _main):
        !           531:             *  00000000 - 01 0007   FUN _main:F3
        !           532:             * where the 'F' in F3 is an upper case 'F' for global labels and
        !           533:             * a lower case 'f' for non globals.
        !           534:             *
        !           535:             * Then for each instruction we assemble in the text we generate
        !           536:             * a line number, S_LINE, stab (see md_assembler in m68k.c, m88k.c
        !           537:             * etc).  These look like:
        !           538:             *  00000000 - 01 0008 SLINE
        !           539:             * where the 0008 is the line number.
        !           540:             */
        !           541:            if(flagseen['g']){
        !           542:                symbolP = symbol_new(
        !           543:                        physical_input_file,
        !           544:                        100 /* N_SO */,
        !           545:                        text_nsect,
        !           546:                        0,
        !           547:                        obstack_next_free(&frags) - frag_now->fr_literal,
        !           548:                        frag_now);
        !           549:                symbolP = symbol_new(
        !           550:                        "int:t1=r1;-2147483648;2147483647;",
        !           551:                        128 /* N_LSYM */,
        !           552:                        0,0,0,
        !           553:                        &zero_address_frag);
        !           554:                symbolP = symbol_new(
        !           555:                        "char:t2=r2;0;127;",
        !           556:                        128 /* N_LSYM */,
        !           557:                        0,0,0,
        !           558:                        &zero_address_frag);
        !           559:                symbolP = symbol_new(
        !           560:                        "void:t3=3",
        !           561:                        128 /* N_LSYM */,
        !           562:                        0,0,0,
        !           563:                        &zero_address_frag);
        !           564:            }
        !           565:        }
        !           566:        else{
        !           567:            /*
        !           568:             * If we are now reading an include file we will bracket it's
        !           569:             * stabs with a pair of:
        !           570:             *  00000010 - 01 0000   SOL include_file
        !           571:             *  ...
        !           572:             *  0000001c - 01 0000   SOL previous_file
        !           573:             * We generate the first N_SOL here and the one for the
        !           574:             * previous_file in s_include() in read.c.
        !           575:             *
        !           576:             * CAVAT: This will only work if the include file starts off in the
        !           577:             * (__TEXT,__text) sections and ends in the (__TEXT,__text) section.
        !           578:             */
        !           579:            if(flagseen['g'] && frchain_now->frch_nsect == text_nsect){
        !           580:                symbolP = symbol_new(
        !           581:                        physical_input_file,
        !           582:                        132 /* N_SOL */,
        !           583:                        text_nsect,
        !           584:                        0,
        !           585:                        obstack_next_free(&frags) - frag_now->fr_literal,
        !           586:                        frag_now);
        !           587:            }
        !           588:        }
        !           589: 
        !           590:        while((buffer_limit = input_scrub_next_buffer(&buffer)) != NULL)
        !           591:            parse_a_buffer(buffer);
        !           592: 
        !           593:        if(the_cond_state.the_cond != starting_cond_state.the_cond ||
        !           594:           the_cond_state.ignore != starting_cond_state.ignore||
        !           595:           if_depth != starting_if_depth)
        !           596:            as_warn("file contains unmatched .ifs or .elses");
        !           597: 
        !           598:        if(doing_include == FALSE){
        !           599:            /* See the comment at the top of this routine for a description of
        !           600:               what is going on here */
        !           601:            if(flagseen['n'] == FALSE)
        !           602:                text_nsect = s_builtin_section(builtin_sections);
        !           603:            if(flagseen['g']){
        !           604:                (void)symbol_new(
        !           605:                        "",
        !           606:                        100 /* N_SO */,
        !           607:                        text_nsect,
        !           608:                        0,
        !           609:                        obstack_next_free(&frags) - frag_now->fr_literal,
        !           610:                        frag_now);
        !           611:            }
        !           612:        }
        !           613: }
        !           614: 
        !           615: /*
        !           616:  * parse_a_buffer() operates on a buffer of lines.  It drives the
        !           617:  * parsing of lines of assembly code.  The lines are assumed to be "well formed"
        !           618:  * assembly so the syntax recognized in here is that produced by the output of
        !           619:  * the assembly preprocessor (app) or by the compiler when it produces a file
        !           620:  * that starts with "#NO_APP\n".  A "well formed" assembly is lines with exactly
        !           621:  * zero or one leading "well formed space character" (' ', '\t' or '\f')
        !           622:  * followed by lines of:
        !           623:  *     zero or more lables (a name or a digit followed by a colon)
        !           624:  *             each followed by zero or one "well formed space character"
        !           625:  *     exactly one of the following followed by a logicial end of line:
        !           626:  *             a pseudo opcode
        !           627:  *                     followed by zero or one space (' ') characters and it's
        !           628:  *                     arguments (the space is required when the first
        !           629:  *                     character of the first argument could be part of a name)
        !           630:  *             a macro to be expanded
        !           631:  *             a machine opcode
        !           632:  *             a null statement
        !           633:  *             an assignment to a symbol
        !           634:  *             a full line comment (in the case of "well formed" assembly it
        !           635:  *                                  must be "#APP\n" of a collection of lines
        !           636:  *                                  wrapped in "#APP\n ... #NO_APP\n")
        !           637:  * 
        !           638:  * input:
        !           639:  *     buffer          pointer to the start of the buffer of lines
        !           640:  *                     (passed as an argument)
        !           641:  *     buffer_limit    pointer to the end of the buffer of lines, that is the
        !           642:  *                     the character it points to is NOT part of the buffer
        !           643:  *                     (buffer_limit is declared in this file)
        !           644:  *
        !           645:  * Assumptions about the buffer of lines:
        !           646:  *     buffer[-1] == '\n'      as done in input-scrub.c with the cpp macro
        !           647:  *                             BEFORE_STRING ("\n")
        !           648:  *     buffer_limit[-1] == '\n' also as done in input-scrub.c which handles
        !           649:  *                             partial lines internally to itself and always
        !           650:  *                             passes back a buffer of complete lines.
        !           651:  *
        !           652:  * input/output: (for other parsing routines)
        !           653:  *     input_line_pointer      pointer to the next thing in the buffer after
        !           654:  *                             what has been recognized (a global)
        !           655:  */
        !           656: static
        !           657: void
        !           658: parse_a_buffer(
        !           659: char *buffer)
        !           660: {
        !           661:     char c;            /* contains the first non-space character the current
        !           662:                           word used to figure out what it is */
        !           663:     char *s;           /* points to a name with character after the name
        !           664:                           replaced with a '\0' so it is a 'C' string */
        !           665:     char after_name;   /* contains that first character after a name that
        !           666:                           got replaced with a '\0' */
        !           667:     char *after_name_pointer;/* points to the end of the name where the '\0' is
        !           668:                           for error use only */
        !           669:     char end_of_line;  /* contains an end of line character that got replaced
        !           670:                           with a '\0' */
        !           671:     char *start_of_line;/* points to the locical start of line we're parsing,
        !           672:                           used only for macro expansion */
        !           673:     pseudo_typeS *pop; /* pointer to a pseudo op stucture returned by
        !           674:                           hash_find(po_hash, s+1) to determine if it is one */
        !           675:     char *the_macro;   /* pointer to a macro name returned by
        !           676:                           hash_find(ma_hash, s) to determine if it is one */
        !           677:     int digit_value;   /* the value of a digit label as an integer, 1: == 1 */
        !           678: 
        !           679:        /* since this is a buffer of full lines it must end in a new line */
        !           680:        know(buffer_limit[-1] == '\n');
        !           681: 
        !           682:        input_line_pointer = buffer;
        !           683: 
        !           684:        /* while we have more of this buffer to parse keep parsing */
        !           685:        while(input_line_pointer < buffer_limit){
        !           686:            /*
        !           687:             * At the top of this loop we know that we just parsed a label or we
        !           688:             * are at the beginning of a logical line (since their can be more
        !           689:             * than one label on a line).  start_of_line is only used by
        !           690:             * expand_macro()
        !           691:             */
        !           692:            start_of_line = input_line_pointer;
        !           693: 
        !           694:            /*
        !           695:             * If we are not counting lines (as in the case when called by
        !           696:             * expand_macro() ) and we just previously scaned over a newline
        !           697:             * (a physical end of line) bump the line counters (see the comments
        !           698:             * at the head of this routine about "assumptions about the buffer"
        !           699:             * and why it is safe to index input_line_pointer by -1.
        !           700:             */
        !           701:            if(count_lines == TRUE && input_line_pointer[-1] == '\n')
        !           702:                bump_line_counters ();
        !           703: 
        !           704:            /*
        !           705:             * We expect a "well-formed" assembler statement.  This means it was
        !           706:             * processed by app or produced by a compiler where the file started
        !           707:             * with a leading "#APP\n".  A "well-formed" statement allows zero
        !           708:             * or one leading white space characters.
        !           709:             */
        !           710:            c = *input_line_pointer;
        !           711:            input_line_pointer++;
        !           712:            if(c == '\t' || c == ' ' || c=='\f'){
        !           713:                c = *input_line_pointer;
        !           714:                input_line_pointer++;
        !           715:            }
        !           716:            know(c != ' ');     /* No further leading whitespace. */
        !           717:            /*
        !           718:             * c contains the 1st significant character, *input_line_pointer
        !           719:             * points after that character.
        !           720:             */
        !           721: 
        !           722:            /*
        !           723:             * look for the begining of a name which could be one of the
        !           724:             * following assembly statements:
        !           725:             *    A pseudo opcode and locical end of line
        !           726:             *    A macro to be expanded and locical end of line
        !           727:             *    A machine opcode and locical end of line
        !           728:             *    A user-defined label (name not digit)(no end of line needed)
        !           729:             * At NeXT labels can be enclosed in ""'s so that Objective-C like
        !           730:             * names (with spaces and colons) can be part of a name, the
        !           731:             * routine get_symbol_end() knows about this.
        !           732:             */
        !           733:            if(is_name_beginner(c) || c == '"'){
        !           734:                if( c == '"')
        !           735:                    s = input_line_pointer--;
        !           736:                else
        !           737:                    s = --input_line_pointer;
        !           738:                after_name = get_symbol_end(); /* name's delimiter */
        !           739:                after_name_pointer = input_line_pointer;
        !           740:                /*
        !           741:                 * after_name is the character after symbol.  That character's
        !           742:                 * place in the input line is now '\0',done by get_symbol_end().
        !           743:                 * s points to the beginning of the symbol (in the case of a
        !           744:                 * pseudo-op, *s == '.').  *input_line_pointer == '\0' where
        !           745:                 * after_name was.  after_name_pointer is recorded so it their
        !           746:                 * is an error after the line has been restored the '\0' can
        !           747:                 * be reset and the name printed.
        !           748:                 */
        !           749: 
        !           750:                /*
        !           751:                 * Look for a name that should be a pseudo op.  That is it is
        !           752:                 * not a user defined label or an assignment to a symbol name.
        !           753:                 * This must be done so such thing as ".foo:" and ".bar=1" are
        !           754:                 * not mistaken for illegal pseudo ops and that something like
        !           755:                 * ".long: .long 1" creates a symbol named ".long".
        !           756:                 */
        !           757:                if(*s == '.' &&
        !           758:                   (after_name != ':' &&
        !           759:                    after_name != '=' &&
        !           760:                   !((after_name == ' ' || after_name == '\t') &&
        !           761:                     input_line_pointer[1] == '=') ) ){
        !           762:                    /*
        !           763:                     * Lookup what should be a pseudo op and then restore the
        !           764:                     * line.
        !           765:                     */
        !           766:                    pop = (pseudo_typeS *)hash_find(po_hash, s+1);
        !           767:                    *input_line_pointer = after_name;
        !           768: 
        !           769:                    /*
        !           770:                     * A pseudo op must be followed by character that is not
        !           771:                     * part of a name so it can be parsed.  If their is a first
        !           772:                     * argument that could start with a character in a name then
        !           773:                     * one "well formed space" (space or a tab) must follow the
        !           774:                     * pseudo op (otherwise the space is optional).
        !           775:                     */
        !           776:                    if(after_name == ' ' || after_name == '\t')
        !           777:                        input_line_pointer++;
        !           778: 
        !           779:                    /*
        !           780:                     * Now the current state of the line is the after_name has
        !           781:                     * been placed back in the line (the line is restored) and
        !           782:                     * input_line_pointer is at the start of the first argument
        !           783:                     * of the pseudo op (if any).
        !           784:                     */
        !           785:                    if(the_cond_state.ignore){
        !           786:                        /*
        !           787:                         * When ignoring a block of code during conditional
        !           788:                         * assembly we can't ignore .if, .else, and .endif
        !           789:                         * pseudo ops.
        !           790:                         */
        !           791:                        if(pop != NULL &&
        !           792:                           ( (pop->poc_handler == s_if) ||
        !           793:                             (pop->poc_handler == s_elseif) ||
        !           794:                             (pop->poc_handler == s_else) ||
        !           795:                             (pop->poc_handler == s_endif) ) )
        !           796:                            (*pop->poc_handler)(pop->poc_val);
        !           797:                        else
        !           798:                            totally_ignore_line();
        !           799:                    }
        !           800:                    else if(macro_name){
        !           801:                        /*
        !           802:                         * When defining a macro we can't ignore .endmacro
        !           803:                         * pseudo ops.
        !           804:                         */
        !           805:                        if(pop != NULL &&
        !           806:                           pop->poc_handler == s_endmacro)
        !           807:                                (*pop->poc_handler)(pop->poc_val);
        !           808:                        else
        !           809:                            add_to_macro_definition(start_of_line);
        !           810:                    }
        !           811:                    else{
        !           812:                        if(pop != NULL)
        !           813:                            (*pop->poc_handler)(pop->poc_val);
        !           814:                        else{
        !           815:                            after_name = *after_name_pointer;
        !           816:                            *after_name_pointer = '\0';
        !           817:                            /*
        !           818:                             * If macros are on see if this is a use of a macro
        !           819:                             * otherwise it is an unknown pseudo op.
        !           820:                             */
        !           821:                            if(macros_on == TRUE &&
        !           822:                               (the_macro = hash_find(ma_hash, s)) != NULL){
        !           823:                                *after_name_pointer = after_name;
        !           824:                                expand_macro(the_macro);
        !           825:                            }
        !           826:                            else{
        !           827:                                as_warn ("Unknown pseudo-op: %s", s);
        !           828:                                *after_name_pointer = after_name;
        !           829:                                ignore_rest_of_line();
        !           830:                            }
        !           831:                        }
        !           832:                    }
        !           833:                    continue;
        !           834: 
        !           835:                } /* if(*s == '.' && ... ) */
        !           836: 
        !           837:                /*
        !           838:                 * If we are in a conditional and the state is that we are now
        !           839:                 * not including lines to be assembled then ignore the line.
        !           840:                 */
        !           841:                if(the_cond_state.ignore){
        !           842:                    *input_line_pointer = after_name;
        !           843:                    totally_ignore_line();
        !           844:                }
        !           845:                /*
        !           846:                 * If we are in the state of defining a macro then take the line
        !           847:                 * for the macro definition.
        !           848:                 */
        !           849:                else if(macro_name != NULL){
        !           850:                    *input_line_pointer = after_name;
        !           851:                    add_to_macro_definition(start_of_line);
        !           852:                }
        !           853:                /*
        !           854:                 * Look for a user defined label.
        !           855:                 */
        !           856:                else if(after_name == ':'){
        !           857:                    colon(s);
        !           858: #ifdef I860
        !           859:                    /*
        !           860:                     * Intel :: feature, which makes the label global if
        !           861:                     * followed by two "::"'s  . This is ifdef'ed in so their
        !           862:                     * is no else cause thus the slightly odd logic.
        !           863:                     */
        !           864:                    if(input_line_pointer[1] == ':'){
        !           865:                        struct symbol *symbolP;
        !           866: 
        !           867:                        symbolP = symbol_find_or_make(s);
        !           868:                        symbolP->sy_type |= N_EXT; /* make symbol name global */
        !           869:                        *input_line_pointer = ':'; /* Restore first ':' */
        !           870:                        input_line_pointer++;    /* step over first ':' */
        !           871:                    }
        !           872: #endif
        !           873:                    /* put ':' back for error messages and step over it */
        !           874:                    *input_line_pointer = ':';
        !           875:                    input_line_pointer++;
        !           876:                }
        !           877:                /*
        !           878:                 * Parse the assignment to a symbol.  The syntax for this is
        !           879:                 * <symbol><equal><expression>.
        !           880:                 */
        !           881:                else if(after_name == '=' ||
        !           882:                       ((after_name == ' ' || after_name == '\t') &&
        !           883:                       input_line_pointer[1] == '=')){
        !           884:                    equals(s);
        !           885:                    demand_empty_rest_of_line();
        !           886:                }
        !           887:                /*
        !           888:                 * If macros are on see if this is a use of a macro.
        !           889:                 */
        !           890:                else if(macros_on == TRUE &&
        !           891:                        (the_macro = hash_find(ma_hash, s)) != NULL){
        !           892:                    *input_line_pointer = after_name;
        !           893:                    expand_macro(the_macro);
        !           894:                }
        !           895:                /*
        !           896:                 * Now assume it is a machine instruction and if not it
        !           897:                 * will be handled as an error.  Machine instructions must be
        !           898:                 * one to a line.
        !           899:                 */
        !           900:                else{
        !           901:                    *input_line_pointer = after_name;
        !           902:                    while(is_end_of_line[(int)*input_line_pointer] == FALSE)
        !           903:                        input_line_pointer ++;
        !           904:                    end_of_line = *input_line_pointer;
        !           905:                    *input_line_pointer = '\0';
        !           906:                    md_assemble(s);
        !           907:                    *input_line_pointer = end_of_line;
        !           908:                    input_line_pointer++;
        !           909:                }
        !           910:                /*
        !           911:                 * At this point we have parsed all things that could have
        !           912:                 * started with a name.  Since one of these things (user defined
        !           913:                 * lables could appear more than once on a line we do a continue
        !           914:                 * here and start parsing as if at the begining of another
        !           915:                 * logicial line.
        !           916:                 */
        !           917:                continue;
        !           918: 
        !           919:            } /* if(is_name_beginner(c) || c == '"') */
        !           920: 
        !           921:            /* empty statement */
        !           922:            if(is_end_of_line[(int)c])
        !           923:                continue;
        !           924: 
        !           925:            /*
        !           926:             * If we are in a conditional and the state is that we are now
        !           927:             * not including lines to be assembled then ignore the line.
        !           928:             */
        !           929:            if(the_cond_state.ignore){
        !           930:                totally_ignore_line();
        !           931:                continue;
        !           932:            }
        !           933: 
        !           934:            /*
        !           935:             * If we are in the state of defining a macro then take the line
        !           936:             * for the macro definition.
        !           937:             */
        !           938:            if(macro_name != NULL){
        !           939:                add_to_macro_definition(start_of_line);
        !           940:                continue;
        !           941:            }
        !           942: 
        !           943:            /* local label  ("4:") */
        !           944:            if(isdigit(c)){
        !           945:                digit_value = c - '0';
        !           946:                if(*input_line_pointer++ == ':' ){
        !           947:                    local_colon(digit_value);
        !           948:                }
        !           949:                else{
        !           950:                    as_warn("Spurious digit %d.", digit_value);
        !           951:                    input_line_pointer--;
        !           952:                    ignore_rest_of_line();
        !           953:                }
        !           954:                continue;
        !           955:            }
        !           956: 
        !           957:            /*
        !           958:             * The only full line comment that should make it here is the first
        !           959:             * of the pair of "#APP\n ... #NO_APP\n" that the compiler uses to
        !           960:             * wrap around asm() statements.  If that is the case then
        !           961:             * parse_line_comment() creates a buffer with those lines in it and
        !           962:             * calls parse_a_buffer() with that buffer.  Then returns here
        !           963:             * skiping over that part of the current buffer.
        !           964:             */
        !           965:            if(c != '\0' && strchr(md_line_comment_chars, c) != NULL){
        !           966:                parse_line_comment(&buffer);
        !           967:                continue;
        !           968:            }
        !           969: 
        !           970:            as_warn("Junk character %d.",c);
        !           971:            ignore_rest_of_line();
        !           972: 
        !           973:        } /* while(input_line_pointer < buffer_limit) */
        !           974: }
        !           975: 
        !           976: /*
        !           977:  * parse_line_comment() parses a line comment for parse_a_buffer().  Since
        !           978:  * parse_a_buffer() only operates on "well formed" assembly the only legal
        !           979:  * line comment that should appear is a "#APP\n ... #NO_APP\n" pair which
        !           980:  * tells us to scrub the characters between them and then parse them.
        !           981:  */
        !           982: static
        !           983: void
        !           984: parse_line_comment(
        !           985: char **buffer)
        !           986: {
        !           987:     char *s;
        !           988:     char *ends;
        !           989: 
        !           990:     char *new_buf;
        !           991:     char *new_tmp;
        !           992:     int         new_length;
        !           993: 
        !           994:     char *tmp_buf;
        !           995:     char *old_input_line_pointer;
        !           996:     char *old_buffer_limit;
        !           997: 
        !           998: 
        !           999:        /* parse_a_buffer should never see any line comment if app is on */
        !          1000:        know(preprocess == FALSE);
        !          1001: 
        !          1002:        s = input_line_pointer;
        !          1003:        /* This must be a #APP\n line comment if not ignore it */
        !          1004:        if(strncmp(s,"APP\n",4) != 0)
        !          1005:            return;
        !          1006: 
        !          1007:        if(count_lines == TRUE)
        !          1008:            bump_line_counters();
        !          1009:        s += sizeof("APP\n") - 1;
        !          1010: 
        !          1011:        /*
        !          1012:         * Search for the matching #NO_APP\n in this buffer, if it is found
        !          1013:         * in this buffer the un-scrubed characters between the "#APP\n" and
        !          1014:         * "#NO_APP\n" start where s is pointing to and end where ends is
        !          1015:         * pointing to.
        !          1016:         */
        !          1017:        ends = strstr(s, "#NO_APP\n");
        !          1018: 
        !          1019:        tmp_buf = NULL;
        !          1020:        if(ends == NULL){
        !          1021:            /* The matching #NO_APP\n for the #APP\n wasn't in this buffer. */
        !          1022:            int tmp_len;
        !          1023:            int num;
        !          1024: 
        !          1025:            /*
        !          1026:             * First create a temporary place (tmp_buf of size tmp_len) to
        !          1027:             * collect the un-scrubbed characters between the "#APP\n" and the
        !          1028:             * "#NO_APP\n" (or end of file) when we find it in some buffer.
        !          1029:             */
        !          1030:            tmp_len = buffer_limit - s;
        !          1031:            tmp_buf = xmalloc(tmp_len);
        !          1032: 
        !          1033:            /*
        !          1034:             * Copy the end of the buffer that contains the first part of
        !          1035:             * the un-scrubbed contents starting just after the "#APP\n".
        !          1036:             * This is so the the current buffer (buffer) can be used to
        !          1037:             * collect the the rest of the un-scrubbed contents and to find
        !          1038:             * the matching "#NO_APP\n".
        !          1039:             */
        !          1040:            memcpy(tmp_buf, s, tmp_len);
        !          1041: 
        !          1042:            /*
        !          1043:             * This loop collects the remaining un-scrubed contents between
        !          1044:             * "#APP\n" and the "#NO_APP\n" into tmp_buf (adjusting tmp_len)
        !          1045:             * and looks for the matching "#NO_APP\n".
        !          1046:             */
        !          1047:            do{
        !          1048:                buffer_limit = input_scrub_next_buffer(buffer);
        !          1049:                /*
        !          1050:                 * We treat runing into the end of the file as if it was the
        !          1051:                 * "#NO_APP" we were looking for.
        !          1052:                 */
        !          1053:                if(buffer_limit == NULL)
        !          1054:                    break;
        !          1055: 
        !          1056:                ends = strstr(*buffer, "#NO_APP\n");
        !          1057:                if(ends != NULL)
        !          1058:                    num = ends - *buffer;
        !          1059:                else
        !          1060:                    num = buffer_limit - *buffer;
        !          1061: 
        !          1062:                tmp_buf = xrealloc(tmp_buf, tmp_len + num);
        !          1063:                memcpy(tmp_buf + tmp_len, *buffer, num);
        !          1064:                tmp_len += num;
        !          1065:            }while(ends == NULL);
        !          1066: 
        !          1067:            /*
        !          1068:             * Now set up buffer, buffer_limit and input_line_pointer be past
        !          1069:             * all the characters of the "#APP\n ... #NO_APP\n" set so that
        !          1070:             * when we return parsing will be picked up from their.
        !          1071:             */
        !          1072:            if(ends != NULL)
        !          1073:                input_line_pointer = ends + sizeof("#NO_APP\n") - 1;
        !          1074:            else{
        !          1075:                input_line_pointer = *buffer;
        !          1076:                buffer_limit = *buffer;
        !          1077:            }
        !          1078: 
        !          1079:            /*
        !          1080:             * Now set s to the start, and ends to the end of the un-scrubed
        !          1081:             * contents of the collected characters between the "#APP\n" and
        !          1082:             * "#NO_APP\n" pair.
        !          1083:             */
        !          1084:            s = tmp_buf;
        !          1085:            ends = s + tmp_len;
        !          1086:        }
        !          1087:        else{
        !          1088:            /*
        !          1089:             * The matching "#NO_APP\n" was in the buffer as we were called so
        !          1090:             * s is the start, and ends is the end of the un-scrubed contents
        !          1091:             * of the characters between the "#APP\n" and "#NO_APP\n" pair.
        !          1092:             * Now to set up buffer, buffer_limit and input_line_pointer be past
        !          1093:             * all the characters of the "#APP\n ... #NO_APP\n" set so that
        !          1094:             * when we return parsing will be picked up from their all that has
        !          1095:             * to be done is move the input_line_pointer past the "#NO_APP\n".
        !          1096:             */
        !          1097:            input_line_pointer = ends + sizeof("#NO_APP\n") - 1;
        !          1098:        }
        !          1099: 
        !          1100:        /*
        !          1101:         * Now that we have the un-scrubed characters beween s and ends setup
        !          1102:         * to scrub them into a new buffer (new_buf of size new_length to
        !          1103:         * new_tmp).
        !          1104:         */
        !          1105:        new_length = 100;
        !          1106:        new_buf = xmalloc(new_length);
        !          1107:        new_tmp = new_buf;
        !          1108:        *new_tmp++ = '\n'; /* place leading \n in buffer for parse_a_buffer */
        !          1109: 
        !          1110:        scrub_string = s;
        !          1111:        scrub_last_string = ends;
        !          1112:        for(;;){
        !          1113:            int c;
        !          1114: 
        !          1115:            c = do_scrub_next_char(scrub_from_string, scrub_to_string);
        !          1116:            if(c == EOF)
        !          1117:                break;
        !          1118:            *new_tmp++ = c;
        !          1119:            if(new_tmp == new_buf + new_length){
        !          1120:                new_buf = xrealloc(new_buf, new_length + 100);
        !          1121:                new_tmp = new_buf + new_length;
        !          1122:                new_length += 100;
        !          1123:            }
        !          1124:        }
        !          1125:        *new_tmp = '\n'; /* place trailing \n in buffer for parse_a_buffer */
        !          1126: 
        !          1127:        /*
        !          1128:         * If we used a temporary buffer to collect the un-scrubbed characters
        !          1129:         * it is no longer needed and can be free()'ed.
        !          1130:         */
        !          1131:        if(tmp_buf != NULL)
        !          1132:            free(tmp_buf);
        !          1133: 
        !          1134:        /*
        !          1135:         * Now we are ready to recursively call parse_a_buffer() with our buffer
        !          1136:         * of scrubed characters.  So save the state of parse_a_buffer() and set
        !          1137:         * it up with our buffer of scrubed characters.
        !          1138:         */
        !          1139:        old_input_line_pointer = input_line_pointer;
        !          1140:        old_buffer_limit = buffer_limit;
        !          1141: 
        !          1142:        input_line_pointer = new_buf;
        !          1143:        buffer_limit = new_tmp;
        !          1144:        parse_a_buffer(new_buf);
        !          1145: 
        !          1146:        /*
        !          1147:         * Free the buffer that held the scrubbed characters
        !          1148:         */
        !          1149:        free(new_buf);
        !          1150: 
        !          1151:        /*
        !          1152:         * After coming back from our recursive call parse_a_buffer() we want 
        !          1153:         * resume parsing after the "#NO_APP\n".  So bump the line counters
        !          1154:         * for the "#NO_APP\n" and restore the state so we can return to
        !          1155:         * parse_a_buffer().
        !          1156:         */
        !          1157:        if(count_lines == TRUE)
        !          1158:            bump_line_counters();
        !          1159:        input_line_pointer = old_input_line_pointer;
        !          1160:        buffer_limit = old_buffer_limit;
        !          1161: 
        !          1162:        return;
        !          1163: }
        !          1164: 
        !          1165: /*
        !          1166:  * s_abort() implements the pseudo op:
        !          1167:  *     .abort [ "abort_string" ]
        !          1168:  */
        !          1169: static
        !          1170: void
        !          1171: s_abort(
        !          1172: int value)
        !          1173: {
        !          1174:     char *p;
        !          1175: 
        !          1176:        p = input_line_pointer;
        !          1177:        while(is_end_of_line[(int)*p] == FALSE)
        !          1178:            p++;
        !          1179:        *p = '\0';
        !          1180:        
        !          1181:        as_fatal(".abort %s detected.  Assembly stopping.", input_line_pointer);
        !          1182: }
        !          1183: 
        !          1184: #if !defined(I860) /* i860 has it's own align and org */
        !          1185: /*
        !          1186:  * s_align() implements the pseudo op
        !          1187:  *     .align expression [ , fill_expression ]
        !          1188:  */
        !          1189: static
        !          1190: void
        !          1191: s_align(
        !          1192: int value)
        !          1193: {
        !          1194:        int temp;
        !          1195:        long temp_fill;
        !          1196: 
        !          1197:        temp = get_absolute_expression();
        !          1198: #define MAX_ALIGNMENT (15)
        !          1199:        if(temp > MAX_ALIGNMENT)
        !          1200:            as_warn("Alignment too large: %d. assumed.", temp = MAX_ALIGNMENT);
        !          1201:        else if(temp < 0){
        !          1202:            as_warn("Alignment negative. 0 assumed.");
        !          1203:            temp = 0;
        !          1204:        }
        !          1205:        if(*input_line_pointer == ','){
        !          1206:            input_line_pointer ++;
        !          1207:            temp_fill = get_absolute_expression ();
        !          1208:        }
        !          1209:        else
        !          1210:            temp_fill = 0;
        !          1211: 
        !          1212:        /* Only make a frag if we HAVE to. . . */
        !          1213:        if(temp != 0)
        !          1214:            frag_align(temp, (int)temp_fill);
        !          1215: 
        !          1216:        /*
        !          1217:         * If this alignment is larger than any previous alignment then this
        !          1218:         * becomes the section's alignment.
        !          1219:         */
        !          1220:        if(frchain_now->frch_section.align < temp)
        !          1221:            frchain_now->frch_section.align = temp;
        !          1222: 
        !          1223:        demand_empty_rest_of_line();
        !          1224: }
        !          1225: #endif /* !defined(I860) i860 has it's own align and org */
        !          1226: 
        !          1227: /*
        !          1228:  * s_comm() implements the pseudo op:
        !          1229:  *     .comm name , expression
        !          1230:  */
        !          1231: static
        !          1232: void
        !          1233: s_comm(
        !          1234: int value)
        !          1235: {
        !          1236:     char *name;
        !          1237:     char c;
        !          1238:     char *p;
        !          1239:     int temp;
        !          1240:     symbolS *symbolP;
        !          1241: 
        !          1242:        if(*input_line_pointer == '"')
        !          1243:            name = input_line_pointer + 1;
        !          1244:        else
        !          1245:            name = input_line_pointer;
        !          1246:        c = get_symbol_end();
        !          1247:        /* just after name is now '\0' */
        !          1248:        p = input_line_pointer;
        !          1249:        *p = c;
        !          1250:        SKIP_WHITESPACE();
        !          1251:        if(*input_line_pointer != ','){
        !          1252:            as_warn("Expected comma after symbol-name");
        !          1253:            ignore_rest_of_line();
        !          1254:            return;
        !          1255:        }
        !          1256:        input_line_pointer++; /* skip ',' */
        !          1257:        if((temp = get_absolute_expression ()) < 0){
        !          1258:            as_warn(".COMMon length (%d.) <0! Ignored.", temp);
        !          1259:            ignore_rest_of_line();
        !          1260:            return;
        !          1261:        }
        !          1262:        *p = 0;
        !          1263:        symbolP = symbol_find_or_make(name);
        !          1264:        *p = c;
        !          1265:        if((symbolP->sy_type & N_TYPE) != N_UNDF ||
        !          1266:           symbolP->sy_other != 0 ||
        !          1267:           symbolP->sy_desc != 0) {
        !          1268:            as_warn("Ignoring attempt to re-define symbol");
        !          1269:            ignore_rest_of_line();
        !          1270:            return;
        !          1271:        }
        !          1272:        if(symbolP->sy_value != 0){
        !          1273:            if(symbolP->sy_value != temp)
        !          1274:                as_warn("Length of .comm \"%s\" is already %ld. Not changed "
        !          1275:                        "to %d.", symbolP->sy_name, symbolP->sy_value, temp);
        !          1276:        }
        !          1277:        else{
        !          1278:            symbolP -> sy_value = temp;
        !          1279:            symbolP -> sy_type |= N_EXT;
        !          1280:        }
        !          1281:        know(symbolP->sy_frag == &zero_address_frag);
        !          1282:        demand_empty_rest_of_line();
        !          1283: }
        !          1284: 
        !          1285: /*
        !          1286:  * s_desc() implements the pseudo op:
        !          1287:  *     .desc name , expression
        !          1288:  * sets the n_desc field of a symbol.
        !          1289:  */
        !          1290: static
        !          1291: void
        !          1292: s_desc(
        !          1293: int value)
        !          1294: {
        !          1295:     char *name;
        !          1296:     char c;
        !          1297:     char *p;
        !          1298:     symbolS *symbolP;
        !          1299:     int temp;
        !          1300: 
        !          1301:        if(*input_line_pointer == '"')
        !          1302:            name = input_line_pointer + 1;
        !          1303:        else
        !          1304:            name = input_line_pointer;
        !          1305:        c = get_symbol_end();
        !          1306:        p = input_line_pointer;
        !          1307:        symbolP = symbol_table_lookup(name);
        !          1308:        *p = c;
        !          1309:        SKIP_WHITESPACE();
        !          1310:        if(*input_line_pointer != ','){
        !          1311:            *p = 0;
        !          1312:            as_warn("Expected comma after name \"%s\"", name);
        !          1313:            *p = c;
        !          1314:            ignore_rest_of_line();
        !          1315:        }
        !          1316:        else{
        !          1317:            input_line_pointer++;
        !          1318:            temp = get_absolute_expression();
        !          1319:            *p = 0;
        !          1320:            symbolP = symbol_find_or_make(name);
        !          1321:            *p = c;
        !          1322:            symbolP->sy_desc = temp;
        !          1323:        }
        !          1324:        demand_empty_rest_of_line();
        !          1325: }
        !          1326: 
        !          1327: /*
        !          1328:  * s_file() implements the pseudo op:
        !          1329:  *     .file name [ level_number ]
        !          1330:  * the level number is generated by /lib/cpp and is just ignored.
        !          1331:  */
        !          1332: static
        !          1333: void
        !          1334: s_file(
        !          1335: int value)
        !          1336: {
        !          1337:     char *s;
        !          1338:     int length;
        !          1339:     struct symbol *symbolP;
        !          1340: 
        !          1341:        /* Some assemblers tolerate immediately following '"' */
        !          1342:        if((s = demand_copy_string(&length))){
        !          1343:            SKIP_WHITESPACE();
        !          1344:            if(*input_line_pointer >= '0' && *input_line_pointer <= '9'){
        !          1345:                while(*input_line_pointer >= '0' &&
        !          1346:                      *input_line_pointer <= '9')
        !          1347:                      input_line_pointer++;
        !          1348:            }
        !          1349:            new_logical_line(s, -1);
        !          1350:            demand_empty_rest_of_line();
        !          1351: 
        !          1352:            /*
        !          1353:             * This is to generate stabs for debugging assembly code.
        !          1354:             * See the comments about stabs in read_a_source_file()
        !          1355:             * for a description of what is going on here.
        !          1356:             */
        !          1357:            if(flagseen['g'] && frchain_now->frch_nsect == text_nsect){
        !          1358:                symbolP = symbol_new(
        !          1359:                              logical_input_file,
        !          1360:                              132 /* N_SOL */,
        !          1361:                              text_nsect,
        !          1362:                              0,
        !          1363:                              obstack_next_free(&frags) - frag_now->fr_literal,
        !          1364:                              frag_now);
        !          1365:            }
        !          1366:        }
        !          1367: }
        !          1368: 
        !          1369: /*
        !          1370:  * s_fill() implements the pseudo op:
        !          1371:  *     .fill repeat_expression , fill_size , fill_expression
        !          1372:  */
        !          1373: static
        !          1374: void
        !          1375: s_fill(
        !          1376: int value)
        !          1377: {
        !          1378:     long temp_repeat;
        !          1379:     long temp_size;
        !          1380:     long temp_fill;
        !          1381:     char *p;
        !          1382: 
        !          1383:        if(get_absolute_expression_and_terminator(&temp_repeat) != ','){
        !          1384:            input_line_pointer--; /* Backup over what was not a ','. */
        !          1385:            as_warn("Expect comma after rep-size in .fill");
        !          1386:            ignore_rest_of_line();
        !          1387:            return;
        !          1388:        }
        !          1389:        if(get_absolute_expression_and_terminator(&temp_size) != ','){
        !          1390:            input_line_pointer--; /* Backup over what was not a ','. */
        !          1391:            as_warn("Expected comma after size in .fill");
        !          1392:            ignore_rest_of_line();
        !          1393:            return;
        !          1394:        }
        !          1395:        /*
        !          1396:         * This is to be compatible with BSD 4.2 AS, not for any rational
        !          1397:         * reason.
        !          1398:         */
        !          1399: #define BSD_FILL_SIZE_CROCK_8 (8)
        !          1400:        if(temp_size > BSD_FILL_SIZE_CROCK_8){
        !          1401:            as_warn(".fill size clamped to %d.", BSD_FILL_SIZE_CROCK_8);
        !          1402:            temp_size = BSD_FILL_SIZE_CROCK_8 ;
        !          1403:        }
        !          1404:        if(temp_size < 0){
        !          1405:            as_warn("Size negative: .fill ignored.");
        !          1406:            temp_size = 0;
        !          1407:        }
        !          1408:        /*
        !          1409:         * bug fix, if md_number_to_chars() is called with something other than
        !          1410:         * 1,2 or 4 it calls abort().  So we don't let the size be something
        !          1411:         * like 3. Bug #13017.
        !          1412:         */
        !          1413:        else if(temp_size != 0 &&
        !          1414:                temp_size != 1 &&
        !          1415:                temp_size != 2 &&
        !          1416:                temp_size != 4){
        !          1417:            as_warn("Repeat must be 0,1,2 or 4, .fill ignored");
        !          1418:            temp_size = 0;
        !          1419:        }
        !          1420:        else if(temp_repeat <= 0){
        !          1421:            as_warn("Repeat < 0, .fill ignored");
        !          1422:            temp_size = 0;
        !          1423:        }
        !          1424:        temp_fill = get_absolute_expression();
        !          1425:        /*
        !          1426:         * Note: .fill (),0 emits no frag (since we are asked to .fill 0 bytes)
        !          1427:         * but emits no error message because it seems a legal thing to do.
        !          1428:         * It is a degenerate case of .fill but could be emitted by a compiler.
        !          1429:         */
        !          1430:        if(temp_size != 0){
        !          1431:              p = frag_var(rs_fill,
        !          1432:                           (int)temp_size,
        !          1433:                           (int)temp_size,
        !          1434:                           (relax_substateT)0,
        !          1435:                           (symbolS *)0,
        !          1436:                           temp_repeat,
        !          1437:                           (char *)0);
        !          1438:              memset(p, '\0', (int)temp_size);
        !          1439:              /*
        !          1440:               * The magic number BSD_FILL_SIZE_CROCK_4 is from BSD 4.2 VAX
        !          1441:               * flavoured AS. The following bizzare behaviour is to be
        !          1442:               * compatible with above.  I guess they tried to take up to 8
        !          1443:               * bytes from a 4-byte expression and they forgot to sign extend.
        !          1444:               */
        !          1445: #define BSD_FILL_SIZE_CROCK_4 (4)
        !          1446:              md_number_to_chars(p,
        !          1447:                                 temp_fill,
        !          1448:                                 temp_size > BSD_FILL_SIZE_CROCK_4 ?
        !          1449:                                        BSD_FILL_SIZE_CROCK_4 : (int)temp_size);
        !          1450:        }
        !          1451:        demand_empty_rest_of_line();
        !          1452: }
        !          1453: 
        !          1454: /*
        !          1455:  * s_globl() implements the pseudo op:
        !          1456:  *     .globl name [ , name ]
        !          1457:  */
        !          1458: void
        !          1459: s_globl(
        !          1460: int value)
        !          1461: {
        !          1462:     char *name;
        !          1463:     int c;
        !          1464:     symbolS *symbolP;
        !          1465: 
        !          1466:        do{
        !          1467:            if(*input_line_pointer == '"')
        !          1468:                name = input_line_pointer + 1;
        !          1469:            else
        !          1470:                name = input_line_pointer;
        !          1471:            c = get_symbol_end();
        !          1472:            symbolP = symbol_find_or_make(name);
        !          1473:            *input_line_pointer = c;
        !          1474:            SKIP_WHITESPACE();
        !          1475:            symbolP->sy_type |= N_EXT;
        !          1476:            if(c == ','){
        !          1477:                input_line_pointer++;
        !          1478:                SKIP_WHITESPACE();
        !          1479:                if(*input_line_pointer == '\n')
        !          1480:                    c = '\n';
        !          1481:            }
        !          1482:        }while(c == ',');
        !          1483:        demand_empty_rest_of_line();
        !          1484: }
        !          1485: 
        !          1486: /*
        !          1487:  * s_private_extern() implements the pseudo op:
        !          1488:  *     .private_extern name [ , name ]
        !          1489:  */
        !          1490: static
        !          1491: void
        !          1492: s_private_extern(
        !          1493: int value)
        !          1494: {
        !          1495:     char *name;
        !          1496:     int c;
        !          1497:     symbolS *symbolP;
        !          1498: 
        !          1499:        if(!flagseen['k'])
        !          1500:            as_fatal("incompatible feature used: .private_extern (must specify "
        !          1501:                     "\"-dynamic\" to be used)");
        !          1502:        do{
        !          1503:            if(*input_line_pointer == '"')
        !          1504:                name = input_line_pointer + 1;
        !          1505:            else
        !          1506:                name = input_line_pointer;
        !          1507:            c = get_symbol_end();
        !          1508:            symbolP = symbol_find_or_make(name);
        !          1509:            *input_line_pointer = c;
        !          1510:            SKIP_WHITESPACE();
        !          1511:            symbolP->sy_type |= N_EXT;
        !          1512:            symbolP->sy_type |= N_PEXT;
        !          1513:            if(c == ','){
        !          1514:                input_line_pointer++;
        !          1515:                SKIP_WHITESPACE();
        !          1516:                if(*input_line_pointer == '\n')
        !          1517:                    c = '\n';
        !          1518:            }
        !          1519:        }while(c == ',');
        !          1520:        demand_empty_rest_of_line();
        !          1521: }
        !          1522: 
        !          1523: /*
        !          1524:  * s_indirect_symbol() implements the pseudo op:
        !          1525:  *     .indirect_symbol name
        !          1526:  */
        !          1527: static
        !          1528: void
        !          1529: s_indirect_symbol(
        !          1530: int value)
        !          1531: {
        !          1532:     char *name;
        !          1533:     int c;
        !          1534:     unsigned long section_type;
        !          1535: 
        !          1536:        if(!flagseen['k'])
        !          1537:            as_fatal("incompatible feature used: .indirect_symbol (must "
        !          1538:                     "specify \"-dynamic\" to be used)");
        !          1539:        if(frchain_now == NULL){
        !          1540:            know(flagseen['n']);
        !          1541:            as_fatal("with -n a section directive must be seen before assembly "
        !          1542:                     "can begin");
        !          1543:        }
        !          1544:        section_type = frchain_now->frch_section.flags & SECTION_TYPE;
        !          1545:        if(section_type != S_NON_LAZY_SYMBOL_POINTERS &&
        !          1546:           section_type != S_LAZY_SYMBOL_POINTERS &&
        !          1547:           section_type != S_SYMBOL_STUBS){
        !          1548:            as_warn("indirect symbol not in a symbol pointer or stub section, "
        !          1549:                    ".indirect_symbol ignored");
        !          1550:            ignore_rest_of_line();
        !          1551:            return;
        !          1552:        }
        !          1553: 
        !          1554:        if(*input_line_pointer == '"')
        !          1555:            name = input_line_pointer + 1;
        !          1556:        else
        !          1557:            name = input_line_pointer;
        !          1558:        c = get_symbol_end();
        !          1559:        indirect_symbol_new(name,
        !          1560:                            frag_now,
        !          1561:                            obstack_next_free(&frags) - frag_now->fr_literal);
        !          1562:        *input_line_pointer = c;
        !          1563: 
        !          1564:        demand_empty_rest_of_line();
        !          1565: }
        !          1566: 
        !          1567: /*
        !          1568:  * s_lcomm() implements the pseudo op:
        !          1569:  *     .lcomm name , size_expression [ , align_expression ]
        !          1570:  */
        !          1571: static
        !          1572: void
        !          1573: s_lcomm(
        !          1574: int value)
        !          1575: {
        !          1576:     char *name;
        !          1577:     char c;
        !          1578:     char *p;
        !          1579:     int size;
        !          1580:     symbolS *symbolP;
        !          1581:     int align;
        !          1582:     static frchainS *bss = NULL;
        !          1583: 
        !          1584:        if(*input_line_pointer == '"')
        !          1585:            name = input_line_pointer + 1;
        !          1586:        else
        !          1587:            name = input_line_pointer;
        !          1588:        c = get_symbol_end();
        !          1589:        p = input_line_pointer;
        !          1590:        *p = c;
        !          1591:        SKIP_WHITESPACE();
        !          1592:        if(*input_line_pointer != ','){
        !          1593:            as_warn("Expected comma after name");
        !          1594:            ignore_rest_of_line();
        !          1595:            return;
        !          1596:        }
        !          1597:        input_line_pointer ++;
        !          1598:        if((size = get_absolute_expression()) < 0){
        !          1599:            as_warn("BSS length (%d.) <0! Ignored.", size);
        !          1600:            ignore_rest_of_line();
        !          1601:            return;
        !          1602:        }
        !          1603: #define MAX_ALIGNMENT (15)
        !          1604:        align = 0;
        !          1605:        if(*input_line_pointer == ','){
        !          1606:            input_line_pointer++;
        !          1607:            align = get_absolute_expression();
        !          1608:            if(align > MAX_ALIGNMENT){
        !          1609:                as_warn("Alignment too large: %d. assumed.", MAX_ALIGNMENT);
        !          1610:                align = MAX_ALIGNMENT;
        !          1611:            }
        !          1612:            else if(align < 0){
        !          1613:                as_warn("Alignment negative. 0 assumed.");
        !          1614:                align = 0;
        !          1615:            }
        !          1616:        }
        !          1617:        *p = 0;
        !          1618:        symbolP = symbol_find_or_make(name);
        !          1619:        *p = c;
        !          1620: 
        !          1621:        if((symbolP->sy_type & N_TYPE) == N_UNDF && symbolP->sy_value == 0){
        !          1622:            if(bss == NULL){
        !          1623:                bss = section_new(SEG_DATA, SECT_BSS, S_ZEROFILL, 0, 0);
        !          1624:                bss->frch_root = xmalloc(SIZEOF_STRUCT_FRAG);
        !          1625:                memset(bss->frch_root, '\0', SIZEOF_STRUCT_FRAG);
        !          1626:                bss->frch_last = bss->frch_root;
        !          1627:            }
        !          1628:            bss->frch_root->fr_address = round(bss->frch_root->fr_address,
        !          1629:                                               1 << align);
        !          1630:            symbolP->sy_value = bss->frch_root->fr_address;
        !          1631:            symbolP->sy_type  = N_SECT;
        !          1632:            symbolP->sy_other = bss->frch_nsect;
        !          1633:            symbolP->sy_frag  = bss->frch_root;
        !          1634:            bss->frch_root->fr_address += size;
        !          1635:            /*
        !          1636:             * If this alignment is larger than any previous alignment then this
        !          1637:             * becomes the section's alignment.
        !          1638:             */
        !          1639:            if(bss->frch_section.align < align)
        !          1640:                bss->frch_section.align = align;
        !          1641:        }
        !          1642:        else
        !          1643:            as_warn("Ignoring attempt to re-define symbol.");
        !          1644:        demand_empty_rest_of_line();
        !          1645: }
        !          1646: 
        !          1647: /*
        !          1648:  * s_line() implements the pseudo op:
        !          1649:  *     .line line_number
        !          1650:  */
        !          1651: void
        !          1652: s_line(
        !          1653: int value)
        !          1654: {
        !          1655:        /*
        !          1656:         * Assume delimiter is part of expression. BSD4.2 as fails with
        !          1657:         * delightful bug, so we are not being incompatible here.
        !          1658:         */
        !          1659:        /*
        !          1660:         * Since the assembler bumps it's line counters at the end of a line
        !          1661:         * and it is the case that the .line is on it's own line what the
        !          1662:         * intent is that the line number is for the next line.  Thus
        !          1663:         * the -1 .  This is the way cpp'ed assembler files work which is the
        !          1664:         * common case.
        !          1665:         */
        !          1666:        new_logical_line((char *)NULL, (int)(get_absolute_expression()) - 1);
        !          1667:        demand_empty_rest_of_line();
        !          1668: }
        !          1669: 
        !          1670: /*
        !          1671:  * s_lsym() implements the pseudo op:
        !          1672:  *     .lsym name , expression
        !          1673:  */
        !          1674: static
        !          1675: void
        !          1676: s_lsym(
        !          1677: int value)
        !          1678: {
        !          1679:     char *name;
        !          1680:     char c;
        !          1681:     char *p;
        !          1682:     segT segment;
        !          1683:     expressionS exp;
        !          1684:     symbolS *symbolP;
        !          1685: 
        !          1686:        /* we permit ANY expression: BSD4.2 demands constants */
        !          1687:        if(*input_line_pointer == '"')
        !          1688:            name = input_line_pointer + 1;
        !          1689:        else
        !          1690:            name = input_line_pointer;
        !          1691:        c = get_symbol_end();
        !          1692:        p = input_line_pointer;
        !          1693:        *p = c;
        !          1694:        SKIP_WHITESPACE();
        !          1695:        if(*input_line_pointer != ','){
        !          1696:            *p = 0;
        !          1697:            as_warn("Expected comma after name \"%s\"", name);
        !          1698:            *p = c;
        !          1699:            ignore_rest_of_line();
        !          1700:            return;
        !          1701:        }
        !          1702:        input_line_pointer++;
        !          1703:        segment = expression(&exp);
        !          1704:        if(segment != SEG_ABSOLUTE && segment != SEG_SECT){
        !          1705: /* this warning still need fixing */
        !          1706:            as_warn("Bad expression: %s", seg_name[(int)segment]);
        !          1707:            ignore_rest_of_line();
        !          1708:            return;
        !          1709:        }
        !          1710:        know(segment == SEG_ABSOLUTE || segment == SEG_SECT);
        !          1711:        *p = 0;
        !          1712:        if(segment == SEG_SECT)
        !          1713:            symbolP = symbol_new(name,
        !          1714:                                 N_SECT,
        !          1715:                                 frchain_now->frch_nsect,
        !          1716:                                 0,
        !          1717:                                 (valueT)(exp.X_add_number),
        !          1718:                                 &zero_address_frag);
        !          1719:        else
        !          1720:            symbolP = symbol_new(name,
        !          1721:                                 N_ABS,
        !          1722:                                 0,
        !          1723:                                 0,
        !          1724:                                 (valueT)(exp.X_add_number),
        !          1725:                                 &zero_address_frag);
        !          1726:        *p = c;
        !          1727:        demand_empty_rest_of_line();
        !          1728: }
        !          1729: 
        !          1730: #if !defined(I860) /* i860 has it's own align and org */
        !          1731: /*
        !          1732:  * s_org() implements the pseudo op:
        !          1733:  *     .org  expression
        !          1734:  */
        !          1735: static
        !          1736: void
        !          1737: s_org(
        !          1738: int value)
        !          1739: {
        !          1740:     segT segment;
        !          1741:     expressionS exp;
        !          1742:     long temp_fill;
        !          1743:     char *p;
        !          1744: 
        !          1745:        /*
        !          1746:         * Don't believe the documentation of BSD 4.2 AS.
        !          1747:         * There is no such thing as a sub-segment-relative origin.
        !          1748:         * Any absolute origin is given a warning, then assumed to be
        !          1749:         * segment-relative.
        !          1750:         * Any segmented origin expression ("foo+42") had better be in the right
        !          1751:         * segment or the .org is ignored.
        !          1752:         *
        !          1753:         * BSD 4.2 AS warns if you try to .org backwards. We cannot because we
        !          1754:         * never know sub-segment sizes when we are reading code.
        !          1755:         * BSD will crash trying to emit -ve numbers of filler bytes in certain
        !          1756:         * .orgs. We don't crash, but see as-write for that code.
        !          1757:         */
        !          1758:        segment = get_known_segmented_expression(&exp);
        !          1759:        if(*input_line_pointer == ','){
        !          1760:            input_line_pointer ++;
        !          1761:            temp_fill = get_absolute_expression ();
        !          1762:        }
        !          1763:        else
        !          1764:            temp_fill = 0;
        !          1765:        if((segment != SEG_SECT ||
        !          1766:            exp.X_add_symbol->sy_other != frchain_now->frch_nsect) &&
        !          1767:            segment != SEG_ABSOLUTE)
        !          1768:            as_warn("Illegal expression. current section assumed.");
        !          1769:        p = frag_var(rs_org,
        !          1770:                     1,
        !          1771:                     1,
        !          1772:                     (relax_substateT)0,
        !          1773:                     exp.X_add_symbol,
        !          1774:                     exp.X_add_number,
        !          1775:                     (char *)0);
        !          1776:        *p = temp_fill;
        !          1777:        demand_empty_rest_of_line();
        !          1778: }
        !          1779: #endif /* !defined(I860) i860 has it's own align and org */
        !          1780: 
        !          1781: /*
        !          1782:  * s_set() implements the pseudo op:
        !          1783:  *     .set name , expression
        !          1784:  */
        !          1785: static
        !          1786: void
        !          1787: s_set(
        !          1788: int value)
        !          1789: {
        !          1790:     char *name;
        !          1791:     char delim;
        !          1792:     char *end_name;
        !          1793:     symbolS *symbolP;
        !          1794: 
        !          1795:        if( * input_line_pointer == '"')
        !          1796:            name = input_line_pointer + 1;
        !          1797:        else
        !          1798:            name = input_line_pointer;
        !          1799:        delim = get_symbol_end();
        !          1800:        end_name = input_line_pointer;
        !          1801:        *end_name = delim;
        !          1802:        SKIP_WHITESPACE();
        !          1803:        if(*input_line_pointer != ','){
        !          1804:            *end_name = 0;
        !          1805:            as_warn("Expected comma after name \"%s\"", name);
        !          1806:            *end_name = delim;
        !          1807:            ignore_rest_of_line();
        !          1808:            return;
        !          1809:        }
        !          1810:        input_line_pointer++;
        !          1811:        *end_name = 0;
        !          1812:        if(name[0] == '.' && name[1] == '\0'){
        !          1813:            /* Turn 'set . , mumble' into a .org mumble */
        !          1814:            segT segment;
        !          1815:            expressionS exp;
        !          1816:            char *ptr;
        !          1817: 
        !          1818:            segment = get_known_segmented_expression(&exp);
        !          1819:            if((segment != SEG_SECT ||
        !          1820:                exp.X_add_symbol->sy_other != frchain_now->frch_nsect) &&
        !          1821:                segment != SEG_ABSOLUTE)
        !          1822:                as_warn("Illegal expression. current section assumed.");
        !          1823:            ptr = frag_var(rs_org,
        !          1824:                           1,
        !          1825:                           1,
        !          1826:                           (relax_substateT)0,
        !          1827:                           exp.X_add_symbol,
        !          1828:                           exp.X_add_number,
        !          1829:                           (char *)0);
        !          1830:            *ptr = 0;
        !          1831:            *end_name = delim;
        !          1832:            return;
        !          1833:        }
        !          1834:        symbolP = symbol_find_or_make(name);
        !          1835:        *end_name = delim;
        !          1836:        pseudo_set(symbolP);
        !          1837:        demand_empty_rest_of_line();
        !          1838: }
        !          1839: 
        !          1840: /*
        !          1841:  * s_abs() implements the pseudo op:
        !          1842:  *     .abs name , expression
        !          1843:  * which sets symbol to 1 or 0 depending on if the expression is an absolute
        !          1844:  * expression.  This is intended for use in macros.
        !          1845:  */
        !          1846: void
        !          1847: s_abs(
        !          1848: int value)
        !          1849: {
        !          1850:     char *name;
        !          1851:     char c;
        !          1852:     char *p;
        !          1853:     segT segment;
        !          1854:     expressionS exp;
        !          1855:     symbolS *symbolP;
        !          1856: 
        !          1857:        if(*input_line_pointer == '"')
        !          1858:            name = input_line_pointer + 1;
        !          1859:        else
        !          1860:            name = input_line_pointer;
        !          1861:        c = get_symbol_end();
        !          1862:        p = input_line_pointer;
        !          1863:        *p = c;
        !          1864:        SKIP_WHITESPACE();
        !          1865:        if(*input_line_pointer != ','){
        !          1866:            *p = 0;
        !          1867:            as_warn("Expected comma after name \"%s\"", name);
        !          1868:            *p = c;
        !          1869:            ignore_rest_of_line();
        !          1870:            return;
        !          1871:        }
        !          1872:        input_line_pointer++;
        !          1873:        *p = 0;
        !          1874:        segment = expression(&exp);
        !          1875:        symbolP = symbol_find_or_make(name);
        !          1876:        symbolP->sy_type = N_ABS;
        !          1877:        symbolP->sy_other = 0; /* NO_SECT */
        !          1878:        symbolP->sy_frag = &zero_address_frag;
        !          1879:        if(segment == SEG_ABSOLUTE)
        !          1880:            symbolP->sy_value = 1;
        !          1881:        else
        !          1882:            symbolP->sy_value = 0;
        !          1883:        *p = c;
        !          1884:        totally_ignore_line();
        !          1885: }
        !          1886: 
        !          1887: /*
        !          1888:  * s_space() implements the pseudo op:
        !          1889:  *     .space repeat_expression [ , fill_expression ]
        !          1890:  */
        !          1891: void
        !          1892: s_space(
        !          1893: int value)
        !          1894: {
        !          1895:     long temp_repeat;
        !          1896:     long temp_fill;
        !          1897:     char *p;
        !          1898: 
        !          1899:        /* Just like .fill, but temp_size = 1 */
        !          1900:        if(get_absolute_expression_and_terminator(&temp_repeat) == ','){
        !          1901:            temp_fill = get_absolute_expression();
        !          1902:        }
        !          1903:        else{
        !          1904:            input_line_pointer--; /* Backup over what was not a ','. */
        !          1905:            temp_fill = 0;
        !          1906:        }
        !          1907:        if(temp_repeat <= 0){
        !          1908:            as_warn("Repeat < 0, .space ignored");
        !          1909:            ignore_rest_of_line();
        !          1910:            return;
        !          1911:        }
        !          1912:        p = frag_var(rs_fill,
        !          1913:                     1,
        !          1914:                     1,
        !          1915:                     (relax_substateT)0,
        !          1916:                     (symbolS *)0,
        !          1917:                     temp_repeat,
        !          1918:                     (char *)0);
        !          1919:        *p = temp_fill;
        !          1920:        demand_empty_rest_of_line();
        !          1921: }
        !          1922: 
        !          1923: static
        !          1924: unsigned long
        !          1925: s_builtin_section(
        !          1926: const struct builtin_section *s)
        !          1927: {
        !          1928:     frchainS *frcP;
        !          1929: 
        !          1930:        if(!flagseen['k']){
        !          1931:            if((s->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS ||
        !          1932:               (s->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ||
        !          1933:               (s->flags & SECTION_TYPE) == S_SYMBOL_STUBS ||
        !          1934:               (s->flags & SECTION_TYPE) == S_MOD_INIT_FUNC_POINTERS ||
        !          1935:               (s->flags & SECTION_ATTRIBUTES) != 0)
        !          1936:                as_fatal("incompatible feature used: directive .%s (must "
        !          1937:                         "specify \"-dynamic\" to be used)", s->directive);
        !          1938:        }
        !          1939:        /*
        !          1940:         * If we allowed to use the new features that are incompatible with 3.2
        !          1941:         * and this is the text section (which relys on the fact that the text
        !          1942:         * section is first in the built in sections list) then add the
        !          1943:         * S_ATTR_PURE_INSTRUCTIONS to the section attributes.
        !          1944:         */
        !          1945:        if(flagseen['k'] && s == builtin_sections){
        !          1946:            frcP = section_new(s->segname, s->sectname,
        !          1947:                               s->flags & SECTION_TYPE,
        !          1948:                               (s->flags & SECTION_ATTRIBUTES) |
        !          1949:                                        S_ATTR_PURE_INSTRUCTIONS,
        !          1950:                               s->sizeof_stub);
        !          1951:        }
        !          1952:        else{
        !          1953:            frcP = section_new(s->segname, s->sectname,
        !          1954:                               s->flags & SECTION_TYPE,
        !          1955:                               s->flags & SECTION_ATTRIBUTES, 
        !          1956:                               s->sizeof_stub);
        !          1957:        }
        !          1958:        if(frcP->frch_section.align < s->default_align)
        !          1959:            frcP->frch_section.align = s->default_align;
        !          1960:        return(frcP->frch_nsect);
        !          1961: }
        !          1962: 
        !          1963: /*
        !          1964:  * s_section() implements the pseudo op:
        !          1965:  *     .section segname , sectname [[[ , type ] , attribute] , sizeof_stub]
        !          1966:  */
        !          1967: static
        !          1968: void
        !          1969: s_section(
        !          1970: int value)
        !          1971: {
        !          1972:     char *segname, *sectname, *typename;
        !          1973:     char c, d, e, *p, *q, *r;
        !          1974:     struct type_name *type_name;
        !          1975:     unsigned long type, attribute;
        !          1976:     struct section s;
        !          1977:     frchainS *frcP;
        !          1978:     unsigned long sizeof_stub;
        !          1979: 
        !          1980:     struct attribute_name *attribute_name;
        !          1981:     char *attributename, *sizeof_stub_name, f, g, *t, *u, *endp;
        !          1982: 
        !          1983:        segname = input_line_pointer;
        !          1984:        do{
        !          1985:            c = *input_line_pointer++ ;
        !          1986:        }while(c != ',' && c != '\0' && c != '\n');
        !          1987:        if(c != ','){
        !          1988:            as_warn("Expected comma after segment-name");
        !          1989:            ignore_rest_of_line();
        !          1990:            return;
        !          1991:        }
        !          1992:        p = input_line_pointer - 1;
        !          1993: 
        !          1994:        sectname = input_line_pointer;
        !          1995:        do{
        !          1996:            d = *input_line_pointer++ ;
        !          1997:        }while(d != ',' && d != '\0' && d != '\n');
        !          1998:        if(p + 1 == input_line_pointer){
        !          1999:            as_warn("Expected section-name after comma");
        !          2000:            ignore_rest_of_line();
        !          2001:            return;
        !          2002:        }
        !          2003:        q = input_line_pointer - 1;
        !          2004: 
        !          2005:        *p = 0;
        !          2006:        if(strlen(segname) > sizeof(s.segname)){
        !          2007:            as_warn("segment-name: %s too long (maximum %ld characters)",
        !          2008:                    segname, sizeof(s.segname));
        !          2009:            ignore_rest_of_line();
        !          2010:            *p = c;
        !          2011:            return;
        !          2012:        }
        !          2013: 
        !          2014:        *q = 0;
        !          2015:        if(strlen(sectname) > sizeof(s.sectname)){
        !          2016:            as_warn("section-name: %s too long (maximum %ld characters)",
        !          2017:                    sectname, sizeof(s.sectname));
        !          2018:            ignore_rest_of_line();
        !          2019:            return;
        !          2020:        }
        !          2021:        /*
        !          2022:         * Now see if the optional section type is present.
        !          2023:         */
        !          2024:        type = 0;
        !          2025:        type_name = type_names;
        !          2026:        attribute = 0;
        !          2027:        attribute_name = attribute_names;
        !          2028:        sizeof_stub = 0;
        !          2029:        if(d == ','){
        !          2030:            typename = input_line_pointer;
        !          2031:            do{
        !          2032:                e = *input_line_pointer++ ;
        !          2033:            }
        !          2034:            while(e != ',' && e != '\0' && e != '\n');
        !          2035:            r = input_line_pointer - 1;
        !          2036:            *r = 0;
        !          2037:            for(type_name = type_names; type_name->name != NULL; type_name++)
        !          2038:                if(strcmp(type_name->name, typename) == 0)
        !          2039:                    break;
        !          2040:            if(type_name->name == NULL){
        !          2041:                as_warn("unknown section type: %s", typename);
        !          2042:                ignore_rest_of_line();
        !          2043:                return;
        !          2044:            }
        !          2045:            *r = e;
        !          2046:            type = type_name->type;
        !          2047:            /*
        !          2048:             * Now see if the optional section attribute is present.
        !          2049:             */
        !          2050:            if(e == ','){
        !          2051:                attributename = input_line_pointer;
        !          2052:                do{
        !          2053:                    f = *input_line_pointer++ ;
        !          2054:                }while(f != ',' && f != '\0' && f != '\n');
        !          2055:                t = input_line_pointer - 1;
        !          2056:                *t = 0;
        !          2057:                for(attribute_name = attribute_names;
        !          2058:                    attribute_name->name != NULL;
        !          2059:                    attribute_name++)
        !          2060:                    if(strcmp(attribute_name->name, attributename) == 0)
        !          2061:                        break;
        !          2062:                if(attribute_name->name == NULL){
        !          2063:                    as_warn("unknown section attribute: %s", attributename);
        !          2064:                    ignore_rest_of_line();
        !          2065:                    return;
        !          2066:                }
        !          2067:                *t = f;
        !          2068:                attribute = attribute_name->attribute;
        !          2069: 
        !          2070:                /*
        !          2071:                 * Now get the section stub size if this is a stub section.
        !          2072:                 */
        !          2073:                if(type == S_SYMBOL_STUBS){
        !          2074:                    if(f == ','){
        !          2075:                        sizeof_stub_name = input_line_pointer;
        !          2076:                        do{
        !          2077:                            g = *input_line_pointer++ ;
        !          2078:                        }while(g != '\0' && g != '\n');
        !          2079:                        u = input_line_pointer - 1;
        !          2080:                        *u = 0;
        !          2081:                        sizeof_stub = strtoul(sizeof_stub_name, &endp, 0);
        !          2082:                        if(*endp != '\0'){
        !          2083:                            as_warn("size of stub section: %s not a proper "
        !          2084:                                    "number", sizeof_stub_name);
        !          2085:                            ignore_rest_of_line();
        !          2086:                            return;
        !          2087:                        }
        !          2088:                        *u = g;
        !          2089:                    }
        !          2090:                    else{
        !          2091:                        as_warn("missing size of stub section (%s,%s)", segname,
        !          2092:                                sectname);
        !          2093:                        ignore_rest_of_line();
        !          2094:                        return;
        !          2095:                    }
        !          2096:                }
        !          2097:            }
        !          2098:            else if(type == S_SYMBOL_STUBS){
        !          2099:                as_warn("missing size of stub section (%s,%s)", segname,
        !          2100:                        sectname);
        !          2101:                ignore_rest_of_line();
        !          2102:                return;
        !          2103:            }
        !          2104:        }
        !          2105:        input_line_pointer--;
        !          2106: 
        !          2107:        if(!flagseen['k']){
        !          2108:            if(type == S_NON_LAZY_SYMBOL_POINTERS ||
        !          2109:               type == S_LAZY_SYMBOL_POINTERS ||
        !          2110:               type == S_SYMBOL_STUBS ||
        !          2111:               type == S_MOD_INIT_FUNC_POINTERS)
        !          2112:                as_fatal("incompatible feature used: section type %s (must "
        !          2113:                         "specify \"-dynamic\" to be "
        !          2114:                         "used)", type_name->name);
        !          2115:            if(attribute != 0)
        !          2116:                as_fatal("incompatible feature used: section attribute %s "
        !          2117:                         "(must specify \"-dynamic\" to be used)",
        !          2118:                         attribute_name->name);
        !          2119:        }
        !          2120: 
        !          2121:        frcP = section_new(segname, sectname, type, attribute, sizeof_stub);
        !          2122:        *p = c;
        !          2123:        *q = d;
        !          2124:        demand_empty_rest_of_line();
        !          2125: }
        !          2126: 
        !          2127: /*
        !          2128:  * s_zerofill() implements the pseudo op:
        !          2129:  *     .zerofill segname , sectname [, symbolname , size_expression [ , align]]
        !          2130:  */
        !          2131: static
        !          2132: void
        !          2133: s_zerofill(
        !          2134: int value)
        !          2135: {
        !          2136:     char *segname, *sectname, c, d, *p, *q, *name;
        !          2137:     struct section s;
        !          2138:     frchainS *frcP;
        !          2139:     symbolS *symbolP;
        !          2140:     int size, align;
        !          2141: 
        !          2142:        segname = input_line_pointer;
        !          2143:        do{
        !          2144:            c = *input_line_pointer++ ;
        !          2145:        }while(c != ',' && c != '\0' && c != '\n');
        !          2146:        if(c != ','){
        !          2147:            as_warn("Expected comma after segment-name");
        !          2148:            ignore_rest_of_line();
        !          2149:            return;
        !          2150:        }
        !          2151:        p = input_line_pointer - 1;
        !          2152: 
        !          2153:        sectname = input_line_pointer;
        !          2154:        do{
        !          2155:            d = *input_line_pointer++ ;
        !          2156:        }while(d != ',' && d != '\0' && d != '\n');
        !          2157:        if(p + 1 == input_line_pointer){
        !          2158:            as_warn("Expected section-name after comma");
        !          2159:            ignore_rest_of_line();
        !          2160:            return;
        !          2161:        }
        !          2162:        q = input_line_pointer - 1;
        !          2163: 
        !          2164:        *p = 0;
        !          2165:        if(strlen(segname) > sizeof(s.segname)){
        !          2166:            as_warn("segment-name: %s too long (maximum %ld characters)",
        !          2167:                    segname, sizeof(s.segname));
        !          2168:            ignore_rest_of_line();
        !          2169:            *p = c;
        !          2170:            return;
        !          2171:        }
        !          2172: 
        !          2173:        *q = 0;
        !          2174:        if(strlen(sectname) > sizeof(s.sectname)){
        !          2175:            as_warn("section-name: %s too long (maximum %ld characters)",
        !          2176:                    sectname, sizeof(s.sectname));
        !          2177:            ignore_rest_of_line();
        !          2178:            *p = c;
        !          2179:            *q = d;
        !          2180:            return;
        !          2181:        }
        !          2182: 
        !          2183:        frcP = section_new(segname, sectname, S_ZEROFILL, 0, 0);
        !          2184:        if(frcP->frch_root == NULL){
        !          2185:            frcP->frch_root = xmalloc(SIZEOF_STRUCT_FRAG);
        !          2186:            frcP->frch_last = frcP->frch_root;
        !          2187:            memset(frcP->frch_root, '\0', SIZEOF_STRUCT_FRAG);
        !          2188:        }
        !          2189:        *p = c;
        !          2190:        *q = d;
        !          2191:        /*
        !          2192:         * If this is the end of the line all that was wanted was to create the
        !          2193:         * the section which is now done, so return.
        !          2194:         */
        !          2195:        if(d != ',')
        !          2196:            return;
        !          2197: 
        !          2198:        if(*input_line_pointer == '"')
        !          2199:            name = input_line_pointer + 1;
        !          2200:        else
        !          2201:            name = input_line_pointer;
        !          2202:        c = get_symbol_end();
        !          2203:        p = input_line_pointer;
        !          2204:        *p = c;
        !          2205:        SKIP_WHITESPACE();
        !          2206:        if(*input_line_pointer != ','){
        !          2207:            as_warn("Expected comma after symbol-name");
        !          2208:            ignore_rest_of_line();
        !          2209:            return;
        !          2210:        }
        !          2211:        input_line_pointer ++;
        !          2212:        if((size = get_absolute_expression()) < 0){
        !          2213:            as_warn("zerofill size (%d.) <0! Ignored.", size);
        !          2214:            ignore_rest_of_line();
        !          2215:            return;
        !          2216:        }
        !          2217:        align = 0;
        !          2218:        if(*input_line_pointer == ','){
        !          2219:            input_line_pointer++;
        !          2220:            align = get_absolute_expression();
        !          2221:            if(align > MAX_ALIGNMENT){
        !          2222:                as_warn("Alignment too large: %d. assumed.", MAX_ALIGNMENT);
        !          2223:                align = MAX_ALIGNMENT;
        !          2224:            }
        !          2225:            else if(align < 0){
        !          2226:                as_warn("Alignment negative. 0 assumed.");
        !          2227:                align = 0;
        !          2228:            }
        !          2229:        }
        !          2230:        *p = 0;
        !          2231:        symbolP = symbol_find_or_make(name);
        !          2232:        *p = c;
        !          2233: 
        !          2234:        if((symbolP->sy_type & N_TYPE) == N_UNDF && symbolP->sy_value == 0){
        !          2235:            frcP->frch_root->fr_address = round(frcP->frch_root->fr_address,
        !          2236:                                                1 << align);
        !          2237:            symbolP->sy_value = frcP->frch_root->fr_address;
        !          2238:            symbolP->sy_type  = N_SECT | (symbolP->sy_type & N_EXT);
        !          2239:            symbolP->sy_other = frcP->frch_nsect;
        !          2240:            symbolP->sy_frag  = frcP->frch_root;
        !          2241:            frcP->frch_root->fr_address += size;
        !          2242:        }
        !          2243:        else
        !          2244:            as_warn("Ignoring attempt to re-define symbol.");
        !          2245: 
        !          2246:        demand_empty_rest_of_line();
        !          2247: }
        !          2248: 
        !          2249: /*
        !          2250:  * s_reference() implements the pseudo op:
        !          2251:  *     .reference name
        !          2252:  */
        !          2253: static
        !          2254: void
        !          2255: s_reference(
        !          2256: int value)
        !          2257: {
        !          2258:     char *name;
        !          2259:     char c;
        !          2260:     char *p;
        !          2261:     symbolS *symbolP;
        !          2262: 
        !          2263:        if(* input_line_pointer == '"')
        !          2264:            name = input_line_pointer + 1;
        !          2265:        else
        !          2266:            name = input_line_pointer;
        !          2267:        c = get_symbol_end();
        !          2268:        p = input_line_pointer;
        !          2269: 
        !          2270:        *p = 0;
        !          2271:        symbolP = symbol_find_or_make(name);
        !          2272:        *p = c;
        !          2273:        demand_empty_rest_of_line();
        !          2274: }
        !          2275: 
        !          2276: /*
        !          2277:  * s_lazy_reference() implements the pseudo op:
        !          2278:  *     .lazy_reference name
        !          2279:  */
        !          2280: static
        !          2281: void
        !          2282: s_lazy_reference(
        !          2283: int value)
        !          2284: {
        !          2285:     char *name;
        !          2286:     char c;
        !          2287:     char *p;
        !          2288:     symbolS *symbolP;
        !          2289: 
        !          2290:        if(!flagseen['k'])
        !          2291:            as_fatal("incompatible feature used: .lazy_reference (must specify "
        !          2292:                     "\"-dynamic\" to be used)");
        !          2293: 
        !          2294:        if(* input_line_pointer == '"')
        !          2295:            name = input_line_pointer + 1;
        !          2296:        else
        !          2297:            name = input_line_pointer;
        !          2298:        c = get_symbol_end();
        !          2299:        p = input_line_pointer;
        !          2300: 
        !          2301:        *p = 0;
        !          2302:        symbolP = symbol_find_or_make(name);
        !          2303:        if((symbolP->sy_type & N_TYPE) == N_UNDF && symbolP->sy_value == 0)
        !          2304:            symbolP->sy_desc |= REFERENCE_FLAG_UNDEFINED_LAZY;
        !          2305:        *p = c;
        !          2306:        demand_empty_rest_of_line();
        !          2307: }
        !          2308: 
        !          2309: /*
        !          2310:  * s_include() implements the pseudo op:
        !          2311:  *     .include "filename"
        !          2312:  */
        !          2313: static
        !          2314: void
        !          2315: s_include(
        !          2316: int value)
        !          2317: {
        !          2318:        char *filename;
        !          2319:        int length;
        !          2320:        symbolS *symbolP;
        !          2321: 
        !          2322:        /* Some assemblers tolerate immediately following '"' */
        !          2323:        if((filename = demand_copy_string( & length ) )) {
        !          2324:            demand_empty_rest_of_line();
        !          2325:            read_an_include_file(filename);
        !          2326:        }
        !          2327: 
        !          2328:        /*
        !          2329:         * This is to generate stabs for debugging assembly code.
        !          2330:         * See the second comment about stabs in read_a_source_file()
        !          2331:         * for a description of what is going on here
        !          2332:         */
        !          2333:        if(flagseen['g'] && frchain_now->frch_nsect == text_nsect){
        !          2334:            symbolP = symbol_new(
        !          2335:                            physical_input_file,
        !          2336:                            132 /* N_SOL */,
        !          2337:                            text_nsect,
        !          2338:                            0,
        !          2339:                            obstack_next_free(&frags) - frag_now->fr_literal,
        !          2340:                            frag_now);
        !          2341:        }
        !          2342: }
        !          2343: 
        !          2344: /*
        !          2345:  * demand_empty_rest_of_line() checks to make sure we are at the end of a line
        !          2346:  * and if not ignores the rest of the line.
        !          2347:  * This is global so machine dependent pseudo-ops can use this.
        !          2348:  */
        !          2349: void
        !          2350: demand_empty_rest_of_line(
        !          2351: void)
        !          2352: {
        !          2353:        SKIP_WHITESPACE();
        !          2354:        if(is_end_of_line[(int)*input_line_pointer])
        !          2355:            input_line_pointer++;
        !          2356:        else
        !          2357:            ignore_rest_of_line();
        !          2358: }
        !          2359: 
        !          2360: /*
        !          2361:  * ignore_rest_of_line() advances input_line_pointer to the next line and if
        !          2362:  * there is anything left on the current line print a warning.
        !          2363:  * This is global so machine dependent pseudo-ops can use this.
        !          2364:  */
        !          2365: void
        !          2366: ignore_rest_of_line(
        !          2367: void)
        !          2368: {
        !          2369:        if(!is_end_of_line[(int)*input_line_pointer]){
        !          2370:            as_warn("Rest of line ignored. 1st junk character valued %d (%c).",
        !          2371:                    *input_line_pointer, *input_line_pointer);
        !          2372:            while(input_line_pointer < buffer_limit &&
        !          2373:                  !is_end_of_line[(int)*input_line_pointer])
        !          2374:                input_line_pointer++;
        !          2375:        }
        !          2376:        input_line_pointer++;   /* Return pointing just after end-of-line. */
        !          2377:        know(is_end_of_line[(int)(input_line_pointer[-1])]);
        !          2378: }
        !          2379: 
        !          2380: /*
        !          2381:  *                     stab()
        !          2382:  *
        !          2383:  * Handle .stabX directives, which used to be open-coded.
        !          2384:  * So much creeping featurism overloaded the semantics that we decided
        !          2385:  * to put all .stabX thinking in one place. Here.
        !          2386:  *
        !          2387:  * We try to make any .stabX directive legal. Other people's AS will often
        !          2388:  * do assembly-time consistency checks: eg assigning meaning to n_type bits
        !          2389:  * and "protecting" you from setting them to certain values. (They also zero
        !          2390:  * certain bits before emitting symbols. Tut tut.)
        !          2391:  *
        !          2392:  * If an expression is not absolute we either gripe or use the relocation
        !          2393:  * information. Other people's assemblers silently forget information they
        !          2394:  * don't need and invent information they need that you didn't supply.
        !          2395:  *
        !          2396:  * .stabX directives always make a symbol table entry. It may be junk if
        !          2397:  * the rest of your .stabX directive is malformed.
        !          2398:  */
        !          2399: static
        !          2400: void
        !          2401: stab(
        !          2402: int what) /* d == .stabd, n == .stabn, and s == .stabs */
        !          2403: {
        !          2404:     symbolS *symbolP;
        !          2405:     char *string;
        !          2406:     int saved_type;
        !          2407:     int length;
        !          2408:     int goof;  /* TRUE if we have aborted. */
        !          2409:     long longint;
        !          2410: 
        !          2411:        saved_type = 0;
        !          2412:        /*
        !          2413:         * Enter with input_line_pointer pointing past .stabX and any following
        !          2414:         * whitespace.
        !          2415:         */
        !          2416:        goof = FALSE;
        !          2417:        if(what == 's'){
        !          2418:            string = demand_copy_C_string(&length);
        !          2419:            SKIP_WHITESPACE();
        !          2420:            if(*input_line_pointer == ',')
        !          2421:                input_line_pointer ++;
        !          2422:            else{
        !          2423:                as_warn("I need a comma after symbol's name");
        !          2424:                goof = TRUE;
        !          2425:            }
        !          2426:        }
        !          2427:        else
        !          2428:            string = "";
        !          2429: 
        !          2430:        /*
        !          2431:         * Input_line_pointer->after ','.  String -> symbol name.
        !          2432:         */
        !          2433:        if(!goof){
        !          2434:            symbolP = symbol_new(string, 0,0,0,0,(struct frag *)0);
        !          2435:            switch(what){
        !          2436:            case 'd':
        !          2437:                symbolP->sy_name = NULL; /* .stabd feature. */
        !          2438:                symbolP->sy_value = obstack_next_free(&frags) -
        !          2439:                                    frag_now->fr_literal;
        !          2440:                symbolP->sy_frag = frag_now;
        !          2441:                break;
        !          2442: 
        !          2443:            case 'n':
        !          2444:            case 's':
        !          2445:                symbolP->sy_frag = &zero_address_frag;
        !          2446:                break;
        !          2447: 
        !          2448:            default:
        !          2449:                BAD_CASE( what );
        !          2450:                break;
        !          2451:            }
        !          2452:            if(get_absolute_expression_and_terminator(&longint) == ','){
        !          2453:                saved_type = longint;
        !          2454:                symbolP->sy_type = longint;
        !          2455:            }
        !          2456:            else{
        !          2457:                as_warn("I want a comma after the n_type expression");
        !          2458:                goof = TRUE;
        !          2459:                input_line_pointer--; /* Backup over a non-',' char. */
        !          2460:            }
        !          2461:        }
        !          2462: 
        !          2463:        if(!goof){
        !          2464:            if(get_absolute_expression_and_terminator(&longint) == ',')
        !          2465:                symbolP->sy_other = longint;
        !          2466:            else {
        !          2467:                as_warn("I want a comma after the n_other expression");
        !          2468:                goof = TRUE;
        !          2469:                input_line_pointer--; /* Backup over a non-',' char. */
        !          2470:            }
        !          2471:        }
        !          2472: 
        !          2473:        if(!goof){
        !          2474:            symbolP->sy_desc = get_absolute_expression();
        !          2475:            if(what == 's' || what == 'n'){
        !          2476:                if(*input_line_pointer != ','){
        !          2477:                    as_warn( "I want a comma after the n_desc expression" );
        !          2478:                    goof = TRUE;
        !          2479:                }
        !          2480:                else
        !          2481:                    input_line_pointer ++;
        !          2482:            }
        !          2483:        }
        !          2484: 
        !          2485:        if((!goof) && (what=='s' || what=='n')){
        !          2486:            pseudo_set(symbolP);
        !          2487:            symbolP->sy_type = saved_type;
        !          2488:        }
        !          2489:        else if(!goof){
        !          2490:            /* for stabd the sy_other (n_sect) gets set to the current section*/
        !          2491:            symbolP->sy_other = frchain_now->frch_nsect;
        !          2492:        }
        !          2493:        if(goof)
        !          2494:            ignore_rest_of_line();
        !          2495:        else
        !          2496:            demand_empty_rest_of_line();
        !          2497: }
        !          2498: 
        !          2499: /*
        !          2500:  *                     pseudo_set()
        !          2501:  *
        !          2502:  * In: Pointer to a symbol.
        !          2503:  *     Input_line_pointer -> expression.
        !          2504:  *
        !          2505:  * Out:        Input_line_pointer -> just after any whitespace after expression.
        !          2506:  *     Tried to set symbol to value of expression.
        !          2507:  *     Will change sy_type, sy_value, sy_frag;
        !          2508:  *(old ->> May set need_pass_2 == TRUE. <<-- commented out by GNU below it
        !          2509:  * uses symbolP->sy_forward = exp.X_add_symbol;)
        !          2510:  */
        !          2511: static
        !          2512: void
        !          2513: pseudo_set(
        !          2514: symbolS *symbolP)
        !          2515: {
        !          2516:     expressionS exp;
        !          2517:     segT segment;
        !          2518:     int ext;
        !          2519: 
        !          2520:        know(symbolP);          /* NULL pointer is logic error. */
        !          2521:        ext = (symbolP->sy_type & N_EXT);
        !          2522:        segment = expression(&exp);
        !          2523: 
        !          2524:        switch(segment){
        !          2525:        case SEG_BIG:
        !          2526:            as_warn("%s number illegal. Absolute 0 assumed.",
        !          2527:                    exp.X_add_number > 0 ? "Bignum" : "Floating-Point");
        !          2528:            symbolP->sy_type = N_ABS | ext;
        !          2529:            symbolP->sy_other = 0; /* NO_SECT */
        !          2530:            symbolP->sy_value = 0;
        !          2531:            symbolP->sy_frag = &zero_address_frag;
        !          2532:            break;
        !          2533: 
        !          2534:        case SEG_NONE:
        !          2535:            as_warn("No expression:  Using absolute 0");
        !          2536:            symbolP->sy_type = N_ABS | ext;
        !          2537:            symbolP->sy_other = 0; /* NO_SECT */
        !          2538:            symbolP->sy_value = 0;
        !          2539:            symbolP->sy_frag = &zero_address_frag;
        !          2540:            break;
        !          2541: 
        !          2542:        case SEG_DIFFSECT:
        !          2543:            if(exp.X_add_symbol && exp.X_subtract_symbol &&
        !          2544:               exp.X_add_symbol->sy_other == exp.X_subtract_symbol->sy_other)
        !          2545:                exp.X_add_number += exp.X_add_symbol->sy_value -
        !          2546:                                    exp.X_subtract_symbol->sy_value;
        !          2547:            else
        !          2548:                as_warn("Complex expression. Absolute segment assumed." );
        !          2549:            /* fall through */
        !          2550: 
        !          2551:        case SEG_ABSOLUTE:
        !          2552:            symbolP->sy_type = N_ABS | ext;
        !          2553:            symbolP->sy_other = 0; /* NO_SECT */
        !          2554:            symbolP->sy_value = exp.X_add_number;
        !          2555:            symbolP->sy_frag = &zero_address_frag;
        !          2556:            break;
        !          2557: 
        !          2558:        case SEG_SECT:
        !          2559:            symbolP->sy_type  = N_SECT | ext;
        !          2560:            symbolP->sy_other = exp.X_add_symbol->sy_other;
        !          2561:            symbolP->sy_value = exp.X_add_number + exp.X_add_symbol->sy_value;
        !          2562:            symbolP->sy_frag  = exp.X_add_symbol->sy_frag;
        !          2563:            break;
        !          2564:          
        !          2565:        case SEG_UNKNOWN:
        !          2566:            symbolP->sy_forward = exp.X_add_symbol;
        !          2567: /* commented out by GNU */
        !          2568: /* as_warn("unknown symbol"); */
        !          2569: /* need_pass_2 = TRUE; */
        !          2570:            break;
        !          2571:          
        !          2572:        default:
        !          2573:            BAD_CASE(segment);
        !          2574:            break;
        !          2575:        }
        !          2576: }
        !          2577: 
        !          2578: /*
        !          2579:  *                     cons()
        !          2580:  *
        !          2581:  * CONStruct more frag of .bytes, or .words etc.
        !          2582:  * This understands EXPRESSIONS, as opposed to big_cons().
        !          2583:  *
        !          2584:  * Bug (?)
        !          2585:  *
        !          2586:  * This has a split personality. We use expression() to read the
        !          2587:  * value. We can detect if the value won't fit in a byte or word.
        !          2588:  * But we can't detect if expression() discarded significant digits
        !          2589:  * in the case of a long. Not worth the crocks required to fix it.
        !          2590:  *
        !          2591:  * Worker function to do .byte, .short, .long, statements.
        !          2592:  * This clobbers input_line_pointer, checks end-of-line.
        !          2593:  */
        !          2594: void
        !          2595: cons(  
        !          2596: int nbytes) /* nbytes == 1 for .byte, 2 for .word, 4 for .long */
        !          2597: {
        !          2598:     char c;
        !          2599:     long mask;         /* high-order bits to truncate */
        !          2600:     long unmask;       /* what bits we will store */
        !          2601:     long get;          /* the bits of the expression we get */
        !          2602:     long use;          /* the bits of the expression after truncation */
        !          2603:     char *p;           /* points into the frag */
        !          2604:     segT segment;
        !          2605:     expressionS exp;
        !          2606: 
        !          2607:        /*
        !          2608:         * Input_line_pointer -> 1st char after pseudo-op-code and could legally
        !          2609:         * be a end-of-line. (Or, less legally an eof - which we cope with.)
        !          2610:         */
        !          2611:        if(nbytes >= sizeof(long int))
        !          2612:            mask = 0;
        !          2613:        else 
        !          2614:            mask = ~0 << (BITS_PER_CHAR * nbytes); /* Don't store these bits. */
        !          2615:        unmask = ~mask;         /* Do store these bits. */
        !          2616: 
        !          2617:        /*
        !          2618:         * The following awkward logic is to parse ZERO or more expressions,
        !          2619:         * comma seperated. Recall an expression includes its leading &
        !          2620:         * trailing blanks. We fake a leading ',' if there is (supposed to
        !          2621:         * be) a 1st expression, and keep demanding 1 expression for each ','.
        !          2622:         */
        !          2623:        if(is_it_end_of_statement()){
        !          2624:            c = 0;                      /* Skip loop. */
        !          2625:            input_line_pointer++;       /* Matches end-of-loop 'correction'. */
        !          2626:        }
        !          2627:        else
        !          2628:            c = ',';                    /* Do loop. */
        !          2629: 
        !          2630:        while(c == ','){
        !          2631:            segment = expression(&exp); /* At least scan over the expression */
        !          2632: 
        !          2633:            if(segment == SEG_DIFFSECT && exp.X_add_symbol == NULL){
        !          2634:                as_warn("Subtracting symbol \"%s\"(segment\"%s\") is too "
        !          2635:                        "hard. Absolute segment assumed.",
        !          2636:                        exp.X_subtract_symbol->sy_name,
        !          2637:                        seg_name[(int)N_TYPE_seg[
        !          2638:                            exp.X_subtract_symbol->sy_type & N_TYPE]]);
        !          2639:                segment = SEG_ABSOLUTE;
        !          2640:                /* Leave exp .X_add_number alone. */
        !          2641:            }
        !          2642:            p = frag_more(nbytes);
        !          2643:            switch(segment){
        !          2644:            case SEG_BIG:
        !          2645:                as_warn("%s number illegal. Absolute 0 assumed.",
        !          2646:                        exp.X_add_number > 0 ? "Bignum" : "Floating-Point");
        !          2647:                md_number_to_chars(p, (long)0, nbytes);
        !          2648:                break;
        !          2649: 
        !          2650:            case SEG_NONE:
        !          2651:                as_warn("0 assumed for missing expression");
        !          2652:                exp.X_add_number = 0;
        !          2653:                know(exp.X_add_symbol == NULL);
        !          2654:                /* fall into SEG_ABSOLUTE */
        !          2655: 
        !          2656:            case SEG_ABSOLUTE:
        !          2657:                get = exp.X_add_number;
        !          2658:                use = get & unmask;
        !          2659:                if((get & mask) && (get & mask) != mask){
        !          2660:                    /* Leading bits contain both 0s & 1s. */
        !          2661:                    as_warn("Value x%x truncated to x%x.", (unsigned int)get,
        !          2662:                            (unsigned int)use);
        !          2663:                }
        !          2664:                /* put bytes in right order. */
        !          2665:                md_number_to_chars(p, use, nbytes);
        !          2666:                break;
        !          2667: 
        !          2668:            case SEG_DIFFSECT:
        !          2669:            case SEG_UNKNOWN:
        !          2670:            case SEG_SECT:
        !          2671:                fix_new(frag_now,
        !          2672:                        p - frag_now->fr_literal,
        !          2673:                        nbytes,
        !          2674:                        exp.X_add_symbol,
        !          2675:                        exp.X_subtract_symbol,
        !          2676:                        exp.X_add_number,
        !          2677:                        0,
        !          2678:                        0,
        !          2679:                        0);
        !          2680:                break;
        !          2681: 
        !          2682:            default:
        !          2683:                BAD_CASE(segment);
        !          2684:                break;
        !          2685:            }                   /* switch(segment) */
        !          2686:            c = *input_line_pointer++;
        !          2687:        }                               /* while(c==',') */
        !          2688:        input_line_pointer--;   /* Put terminator back into stream. */
        !          2689:        demand_empty_rest_of_line();
        !          2690: }
        !          2691: 
        !          2692: #ifdef M68K /* we allow big cons only on the 68k machines */
        !          2693: /*
        !          2694:  *                     big_cons()
        !          2695:  *
        !          2696:  * CONStruct more frag(s) of .quads, or .octa etc.
        !          2697:  * Makes 0 or more new frags.
        !          2698:  * This understands only bignums, not expressions. Cons() understands
        !          2699:  * expressions.
        !          2700:  *
        !          2701:  * Constants recognised are '0...'(octal) '0x...'(hex) '...'(decimal).
        !          2702:  *
        !          2703:  * This creates objects with struct obstack_control objs, destroying
        !          2704:  * any context objs held about a partially completed object. Beware!
        !          2705:  *
        !          2706:  *
        !          2707:  * I think it sucks to have 2 different types of integers, with 2
        !          2708:  * routines to read them, store them etc.
        !          2709:  * It would be nicer to permit bignums in expressions and only
        !          2710:  * complain if the result overflowed. However, due to "efficiency"...
        !          2711:  *
        !          2712:  * Worker function to do .quad and .octa statements.
        !          2713:  * This clobbers input_line_pointer, checks end-of-line.
        !          2714:  */
        !          2715: void
        !          2716: big_cons(
        !          2717: int nbytes) /* 8 == .quad, 16 == .octa ... */
        !          2718: {
        !          2719:     char c;    /* input_line_pointer -> c. */
        !          2720:     int radix;
        !          2721:     long length;/* Number of chars in an object. */
        !          2722:     int digit; /* Value of 1 digit. */
        !          2723:     int carry; /* For multi-precision arithmetic. */
        !          2724:     int work;  /* For multi-precision arithmetic. */
        !          2725:     char *p,*q;        /* For multi-precision arithmetic. */
        !          2726:     int i;
        !          2727: 
        !          2728:        /*
        !          2729:         * The following awkward logic is to parse ZERO or more strings,
        !          2730:         * comma seperated. Recall an expression includes its leading &
        !          2731:         * trailing blanks. We fake a leading ',' if there is (supposed to
        !          2732:         * be) a 1st expression, and keep demanding 1 expression for each ','.
        !          2733:         */
        !          2734:        if(is_it_end_of_statement()){
        !          2735:            c = 0;                      /* Skip loop. */
        !          2736:        }
        !          2737:        else{
        !          2738:            c = ',';                    /* Do loop. */
        !          2739:            --input_line_pointer;
        !          2740:        }
        !          2741:        while(c == ','){
        !          2742:            ++input_line_pointer;
        !          2743:            SKIP_WHITESPACE();
        !          2744:            c = *input_line_pointer;
        !          2745:            /* c contains 1st non-blank char of what we hope is a number */
        !          2746:            if(c == '0'){
        !          2747:                c = *++input_line_pointer;
        !          2748:                if(c == 'x' || c=='X'){
        !          2749:                    c = *++input_line_pointer;
        !          2750:                    radix = 16;
        !          2751:                }
        !          2752:                else{
        !          2753:                    radix = 8;
        !          2754:                }
        !          2755:            }
        !          2756:            else{
        !          2757:                radix = 10;
        !          2758:            }
        !          2759:            /*
        !          2760:             * This feature (?) is here to stop people worrying about
        !          2761:             * mysterious zero constants: which is what they get when
        !          2762:             * they completely omit digits.
        !          2763:             */
        !          2764:            if(hex_value[(int)c] >= radix){
        !          2765:                as_warn("Missing digits. 0 assumed.");
        !          2766:            }
        !          2767:            bignum_high = bignum_low - 1; /* Start constant with 0 chars. */
        !          2768:            for( ;
        !          2769:                (digit = hex_value[(int)c]) < radix;
        !          2770:                c = *++input_line_pointer){
        !          2771:                /* Multiply existing number by radix, then add digit. */
        !          2772:                carry = digit;
        !          2773:                for(p = bignum_low; p <= bignum_high; p++){
        !          2774:                    work = (*p & MASK_CHAR) * radix + carry;
        !          2775:                    *p = work & MASK_CHAR;
        !          2776:                    carry = work >> BITS_PER_CHAR;
        !          2777:                }
        !          2778:                if(carry){
        !          2779:                    grow_bignum();
        !          2780:                    *bignum_high = carry & MASK_CHAR;
        !          2781:                    know((carry & ~ MASK_CHAR) == 0);
        !          2782:                }
        !          2783:            }
        !          2784:            length = bignum_high - bignum_low + 1;
        !          2785:            if(length > nbytes){
        !          2786:                as_warn("Most significant bits truncated in integer constant.");
        !          2787:            }
        !          2788:            else{
        !          2789:                long leading_zeroes;
        !          2790: 
        !          2791:                for(leading_zeroes = nbytes - length;
        !          2792:                    leading_zeroes;
        !          2793:                    leading_zeroes--){
        !          2794:                    grow_bignum();
        !          2795:                    *bignum_high = 0;
        !          2796:                }
        !          2797:            }
        !          2798:            p = frag_more(nbytes);
        !          2799:            if(md_target_byte_sex == BIG_ENDIAN_BYTE_SEX){
        !          2800:                q = (char *)bignum_low;
        !          2801:                for(i = nbytes - 1; i >= 0; i--)
        !          2802:                    *p++ = q[i];
        !          2803:            }
        !          2804:            else{
        !          2805:                memcpy(p, bignum_low, (int)nbytes);
        !          2806:            }
        !          2807:            /* C contains character after number. */
        !          2808:            SKIP_WHITESPACE();
        !          2809:            c = *input_line_pointer;
        !          2810:            /* C contains 1st non-blank character after number. */
        !          2811:        }
        !          2812:        demand_empty_rest_of_line();
        !          2813: }
        !          2814: 
        !          2815: /*
        !          2816:  * grow_bignum() extends bignum (that is adjust bignum_low, bignum_high and
        !          2817:  * bignum_limit).
        !          2818:  */
        !          2819: static
        !          2820: void
        !          2821: grow_bignum(
        !          2822: void)
        !          2823: {
        !          2824:     long length;
        !          2825: 
        !          2826:        bignum_high++;
        !          2827:        if(bignum_high >= bignum_limit)
        !          2828:        {
        !          2829:            length = bignum_limit - bignum_low;
        !          2830:            bignum_low = xrealloc(bignum_low, length + length);
        !          2831:            bignum_high = bignum_low + length;
        !          2832:            bignum_limit = bignum_low + length + length;
        !          2833:        }
        !          2834: }
        !          2835: #endif /* M68K we allow big cons only on the 68k machines */
        !          2836: 
        !          2837: /*
        !          2838:  *                     float_cons()
        !          2839:  *
        !          2840:  * CONStruct some more frag chars of .floats .ffloats etc.
        !          2841:  * Makes 0 or more new frags.
        !          2842:  * This understands only floating literals, not expressions. Sorry.
        !          2843:  *
        !          2844:  * A floating constant is defined by atof_generic(), except it is preceded
        !          2845:  * by 0d 0f 0g or 0h. After observing the STRANGE way my BSD AS does its
        !          2846:  * reading, I decided to be incompatible. This always tries to give you
        !          2847:  * rounded bits to the precision of the pseudo-op. Former AS did premature
        !          2848:  * truncatation, restored noisy bits instead of trailing 0s AND gave you
        !          2849:  * a choice of 2 flavours of noise according to which of 2 floating-point
        !          2850:  * scanners you directed AS to use.
        !          2851:  *
        !          2852:  * In: input_line_pointer -> whitespace before, or '0' of flonum.
        !          2853:  *
        !          2854:  * Worker function to do .double, .float, .single statements.
        !          2855:  * This clobbers input_line-pointer, checks end-of-line.
        !          2856:  */
        !          2857: void
        !          2858: float_cons(
        !          2859: int float_type) /* 'f':.ffloat ... 'F':.float ... */
        !          2860: {
        !          2861:     char *p;
        !          2862:     char c;
        !          2863:     int length;        /* Number of chars in an object. */
        !          2864:     char *err; /* Error from scanning floating literal. */
        !          2865:     char temp[MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT];
        !          2866: 
        !          2867:        /*
        !          2868:         * The following awkward logic is to parse ZERO or more strings,
        !          2869:         * comma seperated. Recall an expression includes its leading &
        !          2870:         * trailing blanks. We fake a leading ',' if there is (supposed to
        !          2871:         * be) a 1st expression, and keep demanding 1 expression for each ','.
        !          2872:         */
        !          2873:        if(is_it_end_of_statement()){
        !          2874:            c = 0;                      /* Skip loop. */
        !          2875:            ++input_line_pointer;       /* -> past termintor. */
        !          2876:        }
        !          2877:        else{
        !          2878:            c = ',';                    /* Do loop. */
        !          2879:        }
        !          2880:        while(c == ','){
        !          2881:            /* input_line_pointer -> 1st char of a flonum (we hope!). */
        !          2882:            SKIP_WHITESPACE();
        !          2883:            /*
        !          2884:             * Skip any 0{letter} that may be present. Don't even check if the
        !          2885:             * letter is legal. Someone may invent a "z" format and this routine
        !          2886:             * has no use for such information. Lusers beware: you get
        !          2887:             * diagnostics if your input is ill-conditioned.
        !          2888:             */
        !          2889:            if(input_line_pointer[0] == '0' && isalpha(input_line_pointer[1]))
        !          2890:                input_line_pointer+=2;
        !          2891: 
        !          2892:            err = md_atof(float_type, temp, &length);
        !          2893:            know(length <=  MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT);
        !          2894:            know(length > 0);
        !          2895:            if(*err != '\0'){
        !          2896:                as_warn( "Bad floating literal: %s", err);
        !          2897:                ignore_rest_of_line();
        !          2898:                /* Input_line_pointer -> just after end-of-line. */
        !          2899:                c = 0;          /* Break out of loop. */
        !          2900:            }
        !          2901:            else{
        !          2902:                p = frag_more(length);
        !          2903:                memcpy(p, temp, length);
        !          2904:                SKIP_WHITESPACE();
        !          2905:                c = *input_line_pointer ++;
        !          2906:                /* C contains 1st non-white character after number. */
        !          2907:                /* input_line_pointer -> just after terminator (c). */
        !          2908:            }
        !          2909:        }
        !          2910:        --input_line_pointer;           /* -> terminator (is not ','). */
        !          2911:        demand_empty_rest_of_line();
        !          2912: }
        !          2913: 
        !          2914: /*
        !          2915:  *                     stringer()
        !          2916:  *
        !          2917:  * We read 0 or more ',' seperated, double-quoted strings.
        !          2918:  *
        !          2919:  * Worker function to do .ascii etc statements.
        !          2920:  * Checks end-of-line.
        !          2921:  */
        !          2922: void
        !          2923: stringer(
        !          2924: int append_zero) /* 0: don't append '\0', else 1 */
        !          2925: {
        !          2926:     int c;
        !          2927: 
        !          2928:        /*
        !          2929:         * The following awkward logic is to parse ZERO or more strings,
        !          2930:         * comma seperated. Recall a string expression includes spaces
        !          2931:         * before the opening '\"' and spaces after the closing '\"'.
        !          2932:         * We fake a leading ',' if there is (supposed to be)
        !          2933:         * a 1st, expression. We keep demanding expressions for each
        !          2934:         * ','.
        !          2935:         */
        !          2936:        if(is_it_end_of_statement()){
        !          2937:            c = 0;                      /* Skip loop. */
        !          2938:            ++ input_line_pointer;      /* Compensate for end of loop. */
        !          2939:        }
        !          2940:        else{
        !          2941:            c = ',';                    /* Do loop. */
        !          2942:        }
        !          2943:        for( ; c == ',';  c = *input_line_pointer++){
        !          2944:            SKIP_WHITESPACE();
        !          2945:            if(*input_line_pointer == '\"'){
        !          2946:                ++input_line_pointer; /* -> 1st char of string. */
        !          2947:                while((c = next_char_of_string()) >= 0){
        !          2948:                    FRAG_APPEND_1_CHAR(c);
        !          2949:                }
        !          2950:                if(append_zero){
        !          2951:                    FRAG_APPEND_1_CHAR(0);
        !          2952:                }
        !          2953:                know(input_line_pointer[-1] == '\"');
        !          2954:            }
        !          2955:            else{
        !          2956:                as_warn("Expected \"-ed string");
        !          2957:            }
        !          2958:            SKIP_WHITESPACE();
        !          2959:        }
        !          2960:        --input_line_pointer;
        !          2961:        demand_empty_rest_of_line();
        !          2962: }
        !          2963: 
        !          2964: /*
        !          2965:  * next_char_of_string() is used by stringer() and demand_copy_string() and
        !          2966:  * returns the next character from input_line_pointer that is in the string or 
        !          2967:  * -1 for the trailing " character.  This routine handles escaped characters
        !          2968:  * like \b, \f, etc.
        !          2969:  */
        !          2970: static
        !          2971: int
        !          2972: next_char_of_string(
        !          2973: void)
        !          2974: {
        !          2975:     int c;
        !          2976:     long number, i;
        !          2977: 
        !          2978:        c = *input_line_pointer++;
        !          2979:        /* make sure the 0xff char is not returned as -1 */
        !          2980:        c = (c & MASK_CHAR);
        !          2981:        switch(c){
        !          2982:        case '\"':
        !          2983:            c = -1;
        !          2984:            break;
        !          2985: 
        !          2986:        case '\\':
        !          2987:            c = *input_line_pointer++;
        !          2988:            switch(c){
        !          2989:            case 'b':
        !          2990:                c = '\b';
        !          2991:                break;
        !          2992:            case 'f':
        !          2993:                c = '\f';
        !          2994:                break;
        !          2995:            case 'n':
        !          2996:                c = '\n';
        !          2997:                break;
        !          2998:            case 'r':
        !          2999:                c = '\r';
        !          3000:                break;
        !          3001:            case 't':
        !          3002:                c = '\t';
        !          3003:                break;
        !          3004:            case '\\':
        !          3005:            case '"':
        !          3006:                break;          /* As itself. */
        !          3007:            case '0':
        !          3008:            case '1':
        !          3009:            case '2':
        !          3010:            case '3':
        !          3011:            case '4':
        !          3012:            case '5':
        !          3013:            case '6':
        !          3014:            case '7':
        !          3015:            case '8':
        !          3016:            case '9':
        !          3017:                for(i = 0, number = 0;
        !          3018:                    i < 3 && isdigit(c) && c < '8';
        !          3019:                    i++, c = *input_line_pointer++)
        !          3020:                    number = number * 8 + c - '0';
        !          3021:                c = number;
        !          3022:                --input_line_pointer;
        !          3023:                break;
        !          3024:            case '\n':
        !          3025:                /* To be compatible with BSD 4.2 as: give the user a linefeed */
        !          3026:                c = '\n';
        !          3027:                break;
        !          3028: 
        !          3029:            default:
        !          3030:                as_warn( "Bad escaped character in string, '?' assumed" );
        !          3031:                c = '?';
        !          3032:                break;
        !          3033:            }
        !          3034:            break;
        !          3035:        default:
        !          3036:            break;
        !          3037:        }
        !          3038:        return(c);
        !          3039: }
        !          3040: 
        !          3041: /*
        !          3042:  * get_segmented_expression() is passed an expression to fill in and return that
        !          3043:  * is anything except a bignum or a missing expression.
        !          3044:  */
        !          3045: static
        !          3046: segT
        !          3047: get_segmented_expression(
        !          3048: expressionS *expP)
        !          3049: {
        !          3050:     segT retval;
        !          3051: 
        !          3052:        retval = expression(expP);
        !          3053:        if(retval == SEG_NONE || retval == SEG_BIG){
        !          3054:            as_warn("Expected address expression: absolute 0 assumed");
        !          3055:            retval = expP->X_seg = SEG_ABSOLUTE;
        !          3056:            expP->X_add_number   = 0;
        !          3057:            expP->X_add_symbol   = NULL;
        !          3058:            expP->X_subtract_symbol = NULL;
        !          3059:        }
        !          3060:        return(retval);         /* SEG_ ABSOLUTE,UNKNOWN,SECT */
        !          3061: }
        !          3062: 
        !          3063: /*
        !          3064:  * get_known_segmented_expression() is passed an expression to fill in and
        !          3065:  * return that is anything except an unknown, bignum or a missing expression.
        !          3066:  */
        !          3067: segT
        !          3068: get_known_segmented_expression(
        !          3069: expressionS *expP)
        !          3070: {
        !          3071:     segT retval;
        !          3072:     char *name1;
        !          3073:     char *name2;
        !          3074: 
        !          3075:        retval = get_segmented_expression(expP);
        !          3076:        if(retval == SEG_UNKNOWN){
        !          3077:            name1 = expP->X_add_symbol ?
        !          3078:                    expP->X_add_symbol->sy_name : "";
        !          3079:            name2 = expP->X_subtract_symbol ?
        !          3080:                    expP->X_subtract_symbol->sy_name : "";
        !          3081:            if(name1 && name2){
        !          3082:                as_warn("Symbols \"%s\" \"%s\" are undefined: absolute 0 "
        !          3083:                        "assumed.", name1, name2);
        !          3084:            }
        !          3085:            else{
        !          3086:                as_warn("Symbol \"%s\" undefined: absolute 0 assumed.",
        !          3087:                        name1 ? name1 : name2);
        !          3088:            }
        !          3089:            retval      = SEG_ABSOLUTE;
        !          3090:            expP->X_seg = SEG_ABSOLUTE;
        !          3091:            expP->X_add_number = 0;
        !          3092:            expP->X_add_symbol      = NULL;
        !          3093:            expP->X_subtract_symbol = NULL;
        !          3094:        }
        !          3095:        know(retval == SEG_ABSOLUTE ||
        !          3096:             retval == SEG_SECT ||
        !          3097:             retval == SEG_DIFFSECT);
        !          3098:        return(retval);
        !          3099: }
        !          3100: 
        !          3101: /*
        !          3102:  * get_absolute_expression() gets an absolute expression and returns the value
        !          3103:  * of that expression.
        !          3104:  */
        !          3105: long
        !          3106: get_absolute_expression(
        !          3107: void)
        !          3108: {
        !          3109:     expressionS exp;
        !          3110:     segT s;
        !          3111: 
        !          3112:        s = expression(&exp);
        !          3113:        if(s != SEG_ABSOLUTE){
        !          3114: /* is this right? if not absolute: no message and return 0 */
        !          3115:            if(s != SEG_NONE){
        !          3116:                as_warn("Bad Absolute Expression, absolute 0 assumed.");
        !          3117:            }
        !          3118:            exp.X_add_number = 0;
        !          3119:        }
        !          3120:        return(exp.X_add_number);
        !          3121: }
        !          3122: 
        !          3123: /*
        !          3124:  * get_absolute_expression_and_terminator() gets an absolute expression and
        !          3125:  * returning the value of that expression indirectly through val_pointer and
        !          3126:  * returns the terminator.
        !          3127:  */
        !          3128: static
        !          3129: char                   /* return terminator */
        !          3130: get_absolute_expression_and_terminator(
        !          3131: long *val_pointer)     /* return value of expression */
        !          3132: {
        !          3133:     *val_pointer = get_absolute_expression();
        !          3134:     return(*input_line_pointer++);
        !          3135: }
        !          3136: 
        !          3137: /*
        !          3138:  *                     demand_copy_C_string()
        !          3139:  *
        !          3140:  * Like demand_copy_string, but return NULL if the string contains any '\0's.
        !          3141:  * Give a warning if that happens.
        !          3142:  */
        !          3143: static
        !          3144: char *
        !          3145: demand_copy_C_string(
        !          3146: int *len_pointer)
        !          3147: {
        !          3148:     char *s;
        !          3149:     int len;
        !          3150: 
        !          3151:        if((s = demand_copy_string(len_pointer))){
        !          3152:            for(len = *len_pointer; len > 0; len--){
        !          3153:                if(*s == '\0'){
        !          3154:                    s = 0;
        !          3155:                    len = 1;
        !          3156:                    *len_pointer = 0;
        !          3157:                    as_warn("This string may not contain \'\\0\'");
        !          3158:                }
        !          3159:            }
        !          3160:        }
        !          3161:        return(s);
        !          3162: }
        !          3163: 
        !          3164: /*
        !          3165:  *                     demand_copy_string()
        !          3166:  *
        !          3167:  * Demand string, but return a safe (=private) copy of the string.
        !          3168:  * Return NULL if we can't read a string here.
        !          3169:  */
        !          3170: static
        !          3171: char *
        !          3172: demand_copy_string(
        !          3173: int *lenP)
        !          3174: {
        !          3175:     int c;
        !          3176:     int len;
        !          3177:     char *retval;
        !          3178: 
        !          3179:        len = 0;
        !          3180:        SKIP_WHITESPACE();
        !          3181:        if(*input_line_pointer == '\"'){
        !          3182:            input_line_pointer++;       /* Skip opening quote. */
        !          3183:            while((c = next_char_of_string()) >= 0){
        !          3184:                obstack_1grow(&notes, c);
        !          3185:                len++;
        !          3186:            }
        !          3187:            /*
        !          3188:             * This next line is so demand_copy_C_string will return a null
        !          3189:             * termanated string.
        !          3190:             */
        !          3191:            obstack_1grow(&notes, '\0');
        !          3192:            retval = obstack_finish(&notes);
        !          3193:        }
        !          3194:        else{
        !          3195:            as_warn("Missing string");
        !          3196:            retval = NULL;
        !          3197:            ignore_rest_of_line();
        !          3198:        }
        !          3199:        *lenP = len;
        !          3200:        return(retval);
        !          3201: }
        !          3202: 
        !          3203: /*
        !          3204:  *             is_it_end_of_statement()
        !          3205:  *
        !          3206:  * In: Input_line_pointer -> next character.
        !          3207:  *
        !          3208:  * Do: Skip input_line_pointer over all whitespace.
        !          3209:  *
        !          3210:  * Out:        TRUE if input_line_pointer -> end-of-line.
        !          3211:  */
        !          3212: static
        !          3213: int
        !          3214: is_it_end_of_statement(
        !          3215: void)
        !          3216: {
        !          3217:        SKIP_WHITESPACE();
        !          3218:        return(is_end_of_line[(int)*input_line_pointer]);
        !          3219: }
        !          3220: 
        !          3221: /*
        !          3222:  * equals() implements the assembly statement:
        !          3223:  *      x = expression
        !          3224:  */
        !          3225: static
        !          3226: void
        !          3227: equals(
        !          3228: char *sym_name)
        !          3229: {
        !          3230:     struct symbol *symbolP;
        !          3231:     segT segment;
        !          3232:     expressionS exp;
        !          3233:     char *p;
        !          3234: 
        !          3235:        /* Turn '. = mumble' into a .org mumble */
        !          3236:        if(sym_name[0]=='.' && sym_name[1]=='\0'){
        !          3237:            if(input_line_pointer[1] == '=')
        !          3238:                input_line_pointer += 2;
        !          3239:            else
        !          3240:                *input_line_pointer++ = '=';            /* Put it back */
        !          3241:            if(*input_line_pointer==' ' || *input_line_pointer=='\t')
        !          3242:                input_line_pointer++;
        !          3243:            segment = get_known_segmented_expression(&exp);
        !          3244:            if((segment != SEG_SECT ||
        !          3245:                exp.X_add_symbol->sy_other != frchain_now->frch_nsect) &&
        !          3246:                segment != SEG_ABSOLUTE)
        !          3247:            as_warn("Illegal expression. current section assumed.");
        !          3248:            p = frag_var(rs_org,
        !          3249:                         1,
        !          3250:                         1,
        !          3251:                         (relax_substateT)0,
        !          3252:                         exp.X_add_symbol,
        !          3253:                         exp.X_add_number,
        !          3254:                         (char *)0);
        !          3255:            *p = 0;
        !          3256:            return;
        !          3257:        }
        !          3258: 
        !          3259:        symbolP = symbol_find_or_make(sym_name);
        !          3260:        if(input_line_pointer[1] == '=')
        !          3261:            input_line_pointer += 2;
        !          3262:        else
        !          3263:            *input_line_pointer++ = '=';                /* Put it back */
        !          3264:        if(*input_line_pointer==' ' || *input_line_pointer=='\t')
        !          3265:            input_line_pointer++;
        !          3266:        pseudo_set(symbolP);
        !          3267: }
        !          3268: 
        !          3269: /*
        !          3270:  * s_if() implements the pseudo op:
        !          3271:  *     .if expression
        !          3272:  * that does conditional assembly using assembler defined expressions.
        !          3273:  */
        !          3274: static
        !          3275: void
        !          3276: s_if(
        !          3277: int value)
        !          3278: {
        !          3279:        if(if_depth >= MAX_IF_DEPTH)
        !          3280:            as_fatal("You can't nest if's more than %d levels deep",
        !          3281:                     MAX_IF_DEPTH);
        !          3282:        last_states[if_depth++] = the_cond_state;
        !          3283:        the_cond_state.the_cond = if_cond;
        !          3284:        if(the_cond_state.ignore)
        !          3285:            totally_ignore_line();
        !          3286:        else{
        !          3287:            the_cond_state.cond_met = get_absolute_expression();
        !          3288:            the_cond_state.ignore = !the_cond_state.cond_met;
        !          3289:            demand_empty_rest_of_line();
        !          3290:        }
        !          3291: }
        !          3292: 
        !          3293: /*
        !          3294:  * s_elseif() implements the pseudo op:
        !          3295:  *     .elseif expression
        !          3296:  * that does conditional assembly using assembler defined expressions.
        !          3297:  */
        !          3298: static
        !          3299: void
        !          3300: s_elseif(
        !          3301: int value)
        !          3302: {
        !          3303:     int last_ignore_state;
        !          3304: 
        !          3305:        if(the_cond_state.the_cond != if_cond &&
        !          3306:           the_cond_state.the_cond != elseif_cond)
        !          3307:            as_fatal("Encountered a .elseif that doesn't follow a .if or an "
        !          3308:                     ".elseif");
        !          3309:        the_cond_state.the_cond = elseif_cond;
        !          3310: 
        !          3311:        last_ignore_state = FALSE;
        !          3312:        if(if_depth)
        !          3313:            last_ignore_state = last_states[if_depth-1].ignore;
        !          3314:         if(last_ignore_state || the_cond_state.cond_met){
        !          3315:            the_cond_state.ignore = TRUE;
        !          3316:            totally_ignore_line();
        !          3317:        }
        !          3318:        else{
        !          3319:            the_cond_state.cond_met = get_absolute_expression();
        !          3320:            the_cond_state.ignore = !the_cond_state.cond_met;
        !          3321:            demand_empty_rest_of_line();
        !          3322:        }
        !          3323: }
        !          3324: 
        !          3325: /*
        !          3326:  * s_else() implements the pseudo op:
        !          3327:  *     .else
        !          3328:  * that does conditional assembly using assembler defined expressions.
        !          3329:  */
        !          3330: static
        !          3331: void
        !          3332: s_else(
        !          3333: int value)
        !          3334: {
        !          3335:     int last_ignore_state;
        !          3336: 
        !          3337:        if(the_cond_state.the_cond != if_cond &&
        !          3338:           the_cond_state.the_cond != elseif_cond)
        !          3339:            as_fatal("Encountered a .else that doesn't follow a .if or an "
        !          3340:                     ".elseif");
        !          3341:        the_cond_state.the_cond = else_cond;
        !          3342:        last_ignore_state = FALSE;
        !          3343:        if(if_depth)
        !          3344:            last_ignore_state = last_states[if_depth-1].ignore;
        !          3345:         if(last_ignore_state || the_cond_state.cond_met)
        !          3346:            the_cond_state.ignore = TRUE;
        !          3347:        else
        !          3348:            the_cond_state.ignore = FALSE;
        !          3349:        demand_empty_rest_of_line();
        !          3350: }
        !          3351: 
        !          3352: /*
        !          3353:  * s_endif() implements the pseudo op:
        !          3354:  *     .endif
        !          3355:  * that does conditional assembly using assembler defined expressions.
        !          3356:  */
        !          3357: static
        !          3358: void
        !          3359: s_endif(
        !          3360: int value)
        !          3361: {
        !          3362:        if((the_cond_state.the_cond == no_cond) || (if_depth == 0))
        !          3363:            as_fatal("Encountered a .endif that doesn't follow a .if or .else");
        !          3364:        the_cond_state = last_states[--if_depth];
        !          3365:        demand_empty_rest_of_line();
        !          3366: }
        !          3367: 
        !          3368: /* 
        !          3369:  * totally_ignore_line() ignores lines during conditional assembly.
        !          3370:  */
        !          3371: void
        !          3372: totally_ignore_line(
        !          3373: void)
        !          3374: {
        !          3375:        if(!is_end_of_line[(int)*input_line_pointer]){
        !          3376:            while(input_line_pointer < buffer_limit &&
        !          3377:                  !is_end_of_line[(int)*input_line_pointer]){
        !          3378:                input_line_pointer ++;
        !          3379:            }
        !          3380:        }
        !          3381:        input_line_pointer++;   /* Return pointing just after end-of-line. */
        !          3382:        know(is_end_of_line[(int)(input_line_pointer[-1])]);
        !          3383: }
        !          3384: 
        !          3385: /*
        !          3386:  * s_macros_on() implements the pseudo op:
        !          3387:  *     .macros_on
        !          3388:  */
        !          3389: static
        !          3390: void
        !          3391: s_macros_on(
        !          3392: int value)
        !          3393: {
        !          3394:        macros_on = TRUE;
        !          3395:        demand_empty_rest_of_line();
        !          3396: }
        !          3397: 
        !          3398: /*
        !          3399:  * s_macros_off() implements the pseudo op:
        !          3400:  *     .macros_off
        !          3401:  */
        !          3402: void
        !          3403: s_macros_off(
        !          3404: int value)
        !          3405: {
        !          3406:        macros_on = FALSE;
        !          3407:        demand_empty_rest_of_line();
        !          3408: }
        !          3409: 
        !          3410: /*
        !          3411:  * s_macro() implements the pseudo op:
        !          3412:  *     .macro macro_name
        !          3413:  * that defines a macro.
        !          3414:  */
        !          3415: void
        !          3416: s_macro(
        !          3417: int value)
        !          3418: {
        !          3419:     int c;
        !          3420:     pseudo_typeS *pop;
        !          3421: 
        !          3422:        if(macro_name)
        !          3423:            as_warn("Can't define a macro inside another macro definition");
        !          3424:        else{
        !          3425:            SKIP_WHITESPACE();
        !          3426:            while(is_part_of_name(c = *input_line_pointer ++))
        !          3427:                obstack_1grow (&macros, c);
        !          3428:            obstack_1grow(&macros, '\0');
        !          3429:            --input_line_pointer;
        !          3430:            macro_name = obstack_finish(&macros);
        !          3431:            if(macro_name == "")
        !          3432:                as_warn("Missing name of macro");
        !          3433:            if(*macro_name == '.'){
        !          3434:                pop = (pseudo_typeS *)hash_find(po_hash, macro_name + 1);
        !          3435:                if(pop != NULL)
        !          3436:                    as_warn("Pseudo-op name: %s can't be a macro name",
        !          3437:                            macro_name);
        !          3438:            }
        !          3439:        }
        !          3440:        totally_ignore_line();
        !          3441: }
        !          3442: 
        !          3443: /*
        !          3444:  * s_endmacro() implements the pseudo op:
        !          3445:  *     .endmacro
        !          3446:  * which is the end of a macro definition.
        !          3447:  */
        !          3448: void
        !          3449: s_endmacro(
        !          3450: int value)
        !          3451: {
        !          3452:     char *errorString;
        !          3453: 
        !          3454:        if(!macro_name){
        !          3455:            as_warn ("This .endmacro does not match with a preceeding .macro");
        !          3456:            ignore_rest_of_line();
        !          3457:        }
        !          3458:        else{
        !          3459:            obstack_1grow(&macros, '\0');
        !          3460:            errorString = hash_insert(ma_hash, macro_name,
        !          3461:                                      obstack_finish(&macros));
        !          3462:            if(*errorString)
        !          3463:                as_warn("The macro named \"%s\" is already defined",
        !          3464:                        macro_name);
        !          3465:            macro_name = FALSE;
        !          3466:        }
        !          3467: }
        !          3468: 
        !          3469: /*
        !          3470:  * macro_begin() initializes macros.
        !          3471:  */
        !          3472: static
        !          3473: void
        !          3474: macro_begin(
        !          3475: void)
        !          3476: {
        !          3477:        ma_hash = hash_new();
        !          3478:        obstack_begin(&macros, 5000);
        !          3479: }
        !          3480: 
        !          3481: /*
        !          3482:  * add_to_macro_definition() is called after a .macro to store the contents of
        !          3483:  * a macro into the obstack.
        !          3484:  */
        !          3485: void
        !          3486: add_to_macro_definition(
        !          3487: char *char_pointer)
        !          3488: {
        !          3489:     char c;
        !          3490: 
        !          3491:        do{
        !          3492:            c = *char_pointer ++;
        !          3493:            know(c != '\0');
        !          3494:            obstack_1grow(&macros, c);
        !          3495:        }while((c != ':') && !(is_end_of_line[(int)c]));
        !          3496:        if(char_pointer > input_line_pointer)
        !          3497:            input_line_pointer = char_pointer;
        !          3498: }
        !          3499: 
        !          3500: /*
        !          3501:  * expand_macro() is called to expand macros.
        !          3502:  */
        !          3503: static
        !          3504: void
        !          3505: expand_macro(
        !          3506: char *macro_contents)
        !          3507: {
        !          3508:     char *buffer;
        !          3509:     char c;
        !          3510:     int index, nargs;
        !          3511:     char *last_buffer_limit;
        !          3512:     int last_count_lines;
        !          3513:     char *last_input_line_pointer;
        !          3514:     char *arguments [10]; /* at most 10 arguments, each is substituted */
        !          3515: 
        !          3516:        if(macro_depth >= MAX_MACRO_DEPTH)
        !          3517:           as_fatal("You can't nest macro's more than %d levels deep",
        !          3518:                    MAX_MACRO_DEPTH);
        !          3519:        macro_depth++;
        !          3520: 
        !          3521:        /* copy each argument to a object in the macro obstack */
        !          3522:        nargs = 0;
        !          3523:        for(index = 0; index < 10; index ++){
        !          3524:            if(*input_line_pointer == ' ')
        !          3525:                ++input_line_pointer;
        !          3526:            know(*input_line_pointer != ' ');
        !          3527:            c = *input_line_pointer;
        !          3528:            if(is_end_of_line[(int)c])
        !          3529:                arguments[index] = NULL;
        !          3530:            else{
        !          3531:                int parenthesis_depth = 0;
        !          3532:                do{
        !          3533:                    c = *input_line_pointer++;
        !          3534:                    if(parenthesis_depth){
        !          3535:                        if(c == ')')
        !          3536:                            parenthesis_depth --;
        !          3537:                    }
        !          3538:                    else{
        !          3539:                        if(c == '(')
        !          3540:                            parenthesis_depth ++;
        !          3541:                        else
        !          3542:                            if(is_end_of_line[(int)c] ||
        !          3543:                               (c == ' ') || (c == ','))
        !          3544:                            break;
        !          3545:                    }
        !          3546:                    know(c != '\0');
        !          3547:                    if(is_end_of_line[(int)c])
        !          3548:                        as_warn("missmatched parenthesis");
        !          3549:                    obstack_1grow(&macros, c);
        !          3550:                }while(1);
        !          3551:                obstack_1grow(&macros, '\0');
        !          3552:                arguments[index] = obstack_finish(&macros);
        !          3553:                nargs++;
        !          3554:                if(is_end_of_line[(int)c])
        !          3555:                    --input_line_pointer;
        !          3556:                else if(c == ' ')
        !          3557:                    if(*input_line_pointer == ',')
        !          3558:                        input_line_pointer++;
        !          3559:            }
        !          3560:        }
        !          3561:        if(!is_end_of_line[(int)c]){
        !          3562:            as_warn("More than 10 arguments not allowed for macros");
        !          3563:            ignore_rest_of_line();
        !          3564:        }
        !          3565:        /*
        !          3566:         * Build a buffer containing the macro contents with arguments
        !          3567:         * substituted
        !          3568:         */
        !          3569:        obstack_1grow(&macros, '\n');
        !          3570:        while((c = *macro_contents++)){
        !          3571:            if(c == '$'){
        !          3572:                if((*macro_contents >= '0') && (*macro_contents <= '9')){
        !          3573:                    index = *macro_contents++ - '0';
        !          3574:                    last_input_line_pointer = macro_contents;
        !          3575:                    macro_contents = arguments[index];
        !          3576:                    if(macro_contents){
        !          3577:                        while ((c = * macro_contents ++))
        !          3578:                        obstack_1grow (&macros, c);
        !          3579:                    }
        !          3580:                    macro_contents = last_input_line_pointer;
        !          3581:                    continue;
        !          3582:                }
        !          3583:                else if (*macro_contents == 'n'){
        !          3584:                    macro_contents++ ;
        !          3585:                    obstack_1grow(&macros, nargs + '0');
        !          3586:                    continue;
        !          3587:                }
        !          3588:            }
        !          3589:            obstack_1grow (&macros, c);
        !          3590:        }
        !          3591:        obstack_1grow (&macros, '\n');
        !          3592:        obstack_1grow (&macros, '\0');
        !          3593:        last_buffer_limit = buffer_limit;
        !          3594:        last_count_lines = count_lines;
        !          3595:        last_input_line_pointer = input_line_pointer;
        !          3596:        buffer_limit = obstack_next_free (&macros) - 1;
        !          3597:        buffer = obstack_finish (&macros);
        !          3598:        count_lines = FALSE;
        !          3599:        /*
        !          3600:        printf("expanded macro: %s", buffer + 1);
        !          3601:        */
        !          3602:        parse_a_buffer(buffer + 1);
        !          3603:        obstack_free (&macros, buffer);
        !          3604:        for(index = 9; index >= 0; index --)
        !          3605:            if(arguments[index])
        !          3606:                obstack_free(&macros, arguments[index]);
        !          3607:        buffer_limit = last_buffer_limit;
        !          3608:        count_lines = last_count_lines;
        !          3609:        input_line_pointer = last_input_line_pointer;
        !          3610:        macro_depth--;
        !          3611: }
        !          3612: 
        !          3613: /*
        !          3614:  * s_dump() implements the pseudo op:
        !          3615:  *     .dump filename
        !          3616:  * that does a quick binary dump of symbol tables.
        !          3617:  */
        !          3618: static
        !          3619: void
        !          3620: s_dump(
        !          3621: int value)
        !          3622: {
        !          3623:     char *filename;
        !          3624:     int length;
        !          3625:     static char null_string[] = "";
        !          3626: 
        !          3627:        if((filename = demand_copy_string(&length))){
        !          3628:            demand_empty_rest_of_line();
        !          3629:            if((dump_fp = fopen(filename, "w+"))){
        !          3630:                hash_apply(ma_hash, write_macro);
        !          3631:                fwrite(null_string, 1, 1, dump_fp);
        !          3632:                hash_apply(sy_hash, write_symbol);
        !          3633:                fwrite(null_string, 1, 1, dump_fp);
        !          3634:                fclose(dump_fp);
        !          3635:            }
        !          3636:            else
        !          3637:                as_warn("couldn't write to dump file: \"%s\"", filename);
        !          3638:        }
        !          3639: }
        !          3640: 
        !          3641: /*
        !          3642:  * write_macro() used by hash_apply indirectly through s_dump() to write one
        !          3643:  * macro.
        !          3644:  */
        !          3645: static
        !          3646: char *
        !          3647: write_macro(
        !          3648: char *string,
        !          3649: char *value)
        !          3650: {
        !          3651:        know(string);
        !          3652:        know(value);
        !          3653:        know(strlen(string));
        !          3654:        fwrite(string, (strlen(string) + 1), 1, dump_fp);
        !          3655:        fwrite(value, (strlen(value) + 1), 1, dump_fp);
        !          3656:        return(NULL);
        !          3657: }
        !          3658: 
        !          3659: /*
        !          3660:  * write_symbol() used by hash_apply indirectly through s_dump() to write one
        !          3661:  * N_ABS symbol and its value.
        !          3662:  */
        !          3663: static
        !          3664: char *
        !          3665: write_symbol(
        !          3666: char *string,
        !          3667: char *value)
        !          3668: {
        !          3669:     symbolS *symbolP;
        !          3670: 
        !          3671:        symbolP = (symbolS *)value;
        !          3672:        know(symbolP);
        !          3673:        if(((symbolP->sy_type) & N_TYPE) == N_ABS){
        !          3674:            know(string);
        !          3675:            know(strlen(string));
        !          3676:            fwrite(string, (strlen(string) + 1), 1, dump_fp);
        !          3677:            fwrite(&(symbolP -> sy_value), 4, 1, dump_fp);
        !          3678:        }
        !          3679:        return(NULL);
        !          3680: }
        !          3681: 
        !          3682: /*
        !          3683:  * s_load() implements the pseudo op:
        !          3684:  *     .load filename
        !          3685:  * that does a quick binary load of symbol tables.
        !          3686:  */
        !          3687: static
        !          3688: void
        !          3689: s_load(
        !          3690: int value)
        !          3691: {
        !          3692:     char *char_pointer;
        !          3693:     char *filename;
        !          3694:     int length;
        !          3695:     char the_char;
        !          3696:     symbolS    *the_symbol;
        !          3697:     symbolS    *temp_symbol_lastP;
        !          3698:     static symbolS *dump_symbol_lastP;
        !          3699: 
        !          3700:        if((filename = demand_copy_string(&length))){
        !          3701:            demand_empty_rest_of_line();
        !          3702:            if((dump_fp = fopen(filename, "r+"))){
        !          3703:                do{
        !          3704:                    do{
        !          3705:                        the_char = getc(dump_fp);
        !          3706:                        obstack_1grow(&macros, the_char);
        !          3707:                    }while(the_char);
        !          3708:                    char_pointer = obstack_finish (&macros);
        !          3709:                    if(!(*char_pointer))
        !          3710:                        break;
        !          3711:                    do{
        !          3712:                        the_char = getc(dump_fp);
        !          3713:                        obstack_1grow(&macros, the_char);
        !          3714:                    }while(the_char);
        !          3715:                    if(*hash_insert(ma_hash, char_pointer,
        !          3716:                                    obstack_finish(&macros)))
        !          3717:                        as_warn("a macro named \"%s\" encountered in a .load "
        !          3718:                                "is already defined", char_pointer);
        !          3719:                }while(1);
        !          3720:                /*
        !          3721:                 * We don't want to link in symbols that were loaded so they
        !          3722:                 * don't go out in the object file.  Instead these symbols
        !          3723:                 * should go out in the object file that did the .dump .
        !          3724:                 */
        !          3725:                temp_symbol_lastP = symbol_lastP;
        !          3726:                symbol_lastP = dump_symbol_lastP;
        !          3727:                do{
        !          3728:                    do{
        !          3729:                        the_char = getc(dump_fp);
        !          3730:                        obstack_1grow(&macros, the_char);
        !          3731:                    }while(the_char);
        !          3732:                    char_pointer = obstack_base(&macros);
        !          3733:                    obstack_next_free(&macros) = char_pointer;
        !          3734:                    if(!(*char_pointer))
        !          3735:                        break;
        !          3736:                    the_symbol = symbol_find_or_make(char_pointer);
        !          3737:                    the_symbol->sy_type = N_ABS;
        !          3738:                    char_pointer = (char *)&the_symbol->sy_value;
        !          3739:                    *char_pointer++ = getc(dump_fp);
        !          3740:                    *char_pointer++ = getc(dump_fp);
        !          3741:                    *char_pointer++ = getc(dump_fp);
        !          3742:                    *char_pointer++ = getc(dump_fp);
        !          3743:                    the_symbol->sy_frag = &zero_address_frag;
        !          3744:                }while(1);
        !          3745:                dump_symbol_lastP = symbol_lastP;
        !          3746:                symbol_lastP = temp_symbol_lastP;
        !          3747:                fclose(dump_fp);
        !          3748:            }
        !          3749:            else
        !          3750:                as_fatal("Couldn't find the dump file: \"%s\"", filename);
        !          3751:        }
        !          3752: }
        !          3753: 
        !          3754: #ifdef SPARC
        !          3755: 
        !          3756: /* Special stuff to allow assembly of Sun assembler sources
        !          3757:    This unfortunatley needs to be here instead of sparc.c because it
        !          3758:    uses the hash tables defined here.
        !          3759:    see also sparc.c for pseudo_table entries 
        !          3760: */
        !          3761: 
        !          3762: /* Handle the SUN sparc assembler .seg directive. .seg should only occur with
        !          3763:    either a ".text" or ".data" argument. Call .text or .data accordingly
        !          3764: */
        !          3765: void
        !          3766: s_seg (ignore)
        !          3767:      int ignore;
        !          3768: {
        !          3769:   pseudo_typeS *ps_t;
        !          3770:   char s[32];
        !          3771: 
        !          3772:   printf("S_SEG\n");
        !          3773: 
        !          3774:   if (strncmp (input_line_pointer, "\"text\"", 6) == 0)
        !          3775:     {
        !          3776:       input_line_pointer += 6;
        !          3777:       /* relies on .text being first section */
        !          3778:       (void)s_builtin_section(builtin_sections);
        !          3779:       demand_empty_rest_of_line();
        !          3780:       return;
        !          3781:     }
        !          3782:   if (strncmp (input_line_pointer, "\"data\"", 6) == 0)
        !          3783:     {
        !          3784:       /* copy the argument */
        !          3785:       input_line_pointer++;
        !          3786:       strncpy(s, input_line_pointer, 4);
        !          3787:       input_line_pointer += 5;
        !          3788:       /* find the section table index for .data */
        !          3789:       ps_t = (pseudo_typeS *) hash_find(po_hash, s);
        !          3790: 
        !          3791:       if (ps_t == 0)
        !          3792:        as_bad ("invalid .seg argument");
        !          3793: 
        !          3794:       printf("INDEX %s, %d\n", s, ps_t->poc_val);
        !          3795: 
        !          3796:       s_builtin_section ((const struct builtin_section *)ps_t->poc_val);
        !          3797:       demand_empty_rest_of_line();
        !          3798:       return;
        !          3799:     }
        !          3800:   as_bad ("Unknown segment type");
        !          3801:   demand_empty_rest_of_line ();
        !          3802: }
        !          3803: 
        !          3804: #endif /* SPARC */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.