home *** CD-ROM | disk | FTP | other *** search
/ OpenStep 4.2J (Developer) / os42jdev.iso / NextDeveloper / Source / GNU / cctools / as / read.c < prev    next >
C/C++ Source or Header  |  1995-09-27  |  104KB  |  3,809 lines

  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.     { NULL, 0 }
  235. };
  236.  
  237. /*
  238.  * These are the built in sections know to the assembler with a directive.
  239.  * They are known as which segment and section name as well as the type &
  240.  * attribute, and default alignment.
  241.  */
  242. struct builtin_section {
  243.     char *directive;
  244.     char *segname;
  245.     char *sectname;
  246.     unsigned long flags; /* type & attribute */
  247.     unsigned long default_align;
  248.     unsigned long sizeof_stub;
  249. };
  250. static const struct builtin_section builtin_sections[] = {
  251.     /*
  252.      * The text section must be first in this list as it is used by
  253.      * read_a_source_file() to do the equivalent of a .text at the start
  254.      * of the file and for s_builtin_section() to set S_ATTR_PURE_INSTRUCTIONS.
  255.      */
  256.     { "text",                "__TEXT", "__text" },
  257.     { "const",               "__TEXT", "__const" },
  258.     { "static_const",        "__TEXT", "__static_const" },
  259.     { "cstring",             "__TEXT", "__cstring", S_CSTRING_LITERALS },
  260.     { "literal4",            "__TEXT", "__literal4", S_4BYTE_LITERALS, 2 },
  261.     { "literal8",            "__TEXT", "__literal8", S_8BYTE_LITERALS, 3 },
  262.     { "constructor",         "__TEXT", "__constructor" },
  263.     { "destructor",          "__TEXT", "__destructor" },
  264.     { "fvmlib_init0",        "__TEXT", "__fvmlib_init0" },
  265.     { "fvmlib_init1",        "__TEXT", "__fvmlib_init1" },
  266.     { "symbol_stub",         "__TEXT", "__symbol_stub",
  267.         S_SYMBOL_STUBS | S_ATTR_PURE_INSTRUCTIONS,
  268. #if defined(M68K)
  269.         1, 20
  270. #endif
  271. #if defined(I386)
  272.         0, 16
  273. #endif
  274. #if defined(HPPA)
  275.         2, 28
  276. #endif
  277. #if defined(SPARC)
  278.           2, 32
  279. #endif
  280.         },
  281.     { "picsymbol_stub",         "__TEXT", "__picsymbol_stub",
  282.         S_SYMBOL_STUBS | S_ATTR_PURE_INSTRUCTIONS,
  283. #if defined(M68K)
  284.         1, 24
  285. #endif
  286. #if defined(I386)
  287.         0, 26
  288. #endif
  289. #if defined(HPPA)
  290.         2, 32
  291. #endif
  292. #if defined(SPARC)
  293.           2, 60
  294. #endif
  295.         },
  296.     { "non_lazy_symbol_pointer","__DATA","__nl_symbol_ptr",
  297.         S_NON_LAZY_SYMBOL_POINTERS, 2 },
  298.     { "lazy_symbol_pointer", "__DATA", "__la_symbol_ptr",
  299.         S_LAZY_SYMBOL_POINTERS, 2 },
  300.     { "mod_init_func",         "__DATA", "__mod_init_func",
  301.         S_MOD_INIT_FUNC_POINTERS, 2 },
  302.     { "dyld",             "__DATA", "__dyld" },
  303.     { "data",                "__DATA", "__data" },
  304.     { "static_data",         "__DATA", "__static_data" },
  305.     { "const_data",          "__DATA", "__const" },
  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(¬es, 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.     do{
  1500.         if(*input_line_pointer == '"')
  1501.         name = input_line_pointer + 1;
  1502.         else
  1503.         name = input_line_pointer;
  1504.         c = get_symbol_end();
  1505.         symbolP = symbol_find_or_make(name);
  1506.         *input_line_pointer = c;
  1507.         SKIP_WHITESPACE();
  1508.         symbolP->sy_type |= N_EXT;
  1509.         symbolP->sy_type |= N_PEXT;
  1510.         if(c == ','){
  1511.         input_line_pointer++;
  1512.         SKIP_WHITESPACE();
  1513.         if(*input_line_pointer == '\n')
  1514.             c = '\n';
  1515.         }
  1516.     }while(c == ',');
  1517.     demand_empty_rest_of_line();
  1518. }
  1519.  
  1520. /*
  1521.  * s_indirect_symbol() implements the pseudo op:
  1522.  *    .indirect_symbol name
  1523.  */
  1524. static
  1525. void
  1526. s_indirect_symbol(
  1527. int value)
  1528. {
  1529.     char *name;
  1530.     int c;
  1531.     unsigned long section_type;
  1532.  
  1533.     if(!flagseen['k'])
  1534.         as_fatal("incompatible feature used: .indirect_symbol (must "
  1535.              "specify \"-dynamic\" to be used)");
  1536.     if(frchain_now == NULL){
  1537.         know(flagseen['n']);
  1538.         as_fatal("with -n a section directive must be seen before assembly "
  1539.              "can begin");
  1540.     }
  1541.     section_type = frchain_now->frch_section.flags & SECTION_TYPE;
  1542.     if(section_type != S_NON_LAZY_SYMBOL_POINTERS &&
  1543.        section_type != S_LAZY_SYMBOL_POINTERS &&
  1544.        section_type != S_SYMBOL_STUBS){
  1545.         as_warn("indirect symbol not in a symbol pointer or stub section, "
  1546.             ".indirect_symbol ignored");
  1547.         ignore_rest_of_line();
  1548.         return;
  1549.     }
  1550.  
  1551.     if(*input_line_pointer == '"')
  1552.         name = input_line_pointer + 1;
  1553.     else
  1554.         name = input_line_pointer;
  1555.     c = get_symbol_end();
  1556.     indirect_symbol_new(name,
  1557.                 frag_now,
  1558.                 obstack_next_free(&frags) - frag_now->fr_literal);
  1559.     *input_line_pointer = c;
  1560.  
  1561.     demand_empty_rest_of_line();
  1562. }
  1563.  
  1564. /*
  1565.  * s_lcomm() implements the pseudo op:
  1566.  *    .lcomm name , size_expression [ , align_expression ]
  1567.  */
  1568. static
  1569. void
  1570. s_lcomm(
  1571. int value)
  1572. {
  1573.     char *name;
  1574.     char c;
  1575.     char *p;
  1576.     int size;
  1577.     symbolS *symbolP;
  1578.     int align;
  1579.     static frchainS *bss = NULL;
  1580.  
  1581.     if(*input_line_pointer == '"')
  1582.         name = input_line_pointer + 1;
  1583.     else
  1584.         name = input_line_pointer;
  1585.     c = get_symbol_end();
  1586.     p = input_line_pointer;
  1587.     *p = c;
  1588.     SKIP_WHITESPACE();
  1589.     if(*input_line_pointer != ','){
  1590.         as_warn("Expected comma after name");
  1591.         ignore_rest_of_line();
  1592.         return;
  1593.     }
  1594.     input_line_pointer ++;
  1595.     if((size = get_absolute_expression()) < 0){
  1596.         as_warn("BSS length (%d.) <0! Ignored.", size);
  1597.         ignore_rest_of_line();
  1598.         return;
  1599.     }
  1600. #define MAX_ALIGNMENT (15)
  1601.     align = 0;
  1602.     if(*input_line_pointer == ','){
  1603.         input_line_pointer++;
  1604.         align = get_absolute_expression();
  1605.         if(align > MAX_ALIGNMENT){
  1606.         as_warn("Alignment too large: %d. assumed.", MAX_ALIGNMENT);
  1607.         align = MAX_ALIGNMENT;
  1608.         }
  1609.         else if(align < 0){
  1610.         as_warn("Alignment negative. 0 assumed.");
  1611.         align = 0;
  1612.         }
  1613.     }
  1614.     *p = 0;
  1615.     symbolP = symbol_find_or_make(name);
  1616.     *p = c;
  1617.  
  1618.     if((symbolP->sy_type & N_TYPE) == N_UNDF && symbolP->sy_value == 0){
  1619.         if(bss == NULL){
  1620.         bss = section_new(SEG_DATA, SECT_BSS, S_ZEROFILL, 0, 0);
  1621.         bss->frch_root = xmalloc(SIZEOF_STRUCT_FRAG);
  1622.         memset(bss->frch_root, '\0', SIZEOF_STRUCT_FRAG);
  1623.         bss->frch_last = bss->frch_root;
  1624.         }
  1625.         bss->frch_root->fr_address = round(bss->frch_root->fr_address,
  1626.                            1 << align);
  1627.         symbolP->sy_value = bss->frch_root->fr_address;
  1628.         symbolP->sy_type  = N_SECT;
  1629.         symbolP->sy_other = bss->frch_nsect;
  1630.         symbolP->sy_frag  = bss->frch_root;
  1631.         bss->frch_root->fr_address += size;
  1632.         /*
  1633.          * If this alignment is larger than any previous alignment then this
  1634.          * becomes the section's alignment.
  1635.          */
  1636.         if(bss->frch_section.align < align)
  1637.         bss->frch_section.align = align;
  1638.     }
  1639.     else
  1640.         as_warn("Ignoring attempt to re-define symbol.");
  1641.     demand_empty_rest_of_line();
  1642. }
  1643.  
  1644. /*
  1645.  * s_line() implements the pseudo op:
  1646.  *    .line line_number
  1647.  */
  1648. void
  1649. s_line(
  1650. int value)
  1651. {
  1652.     /*
  1653.      * Assume delimiter is part of expression. BSD4.2 as fails with
  1654.      * delightful bug, so we are not being incompatible here.
  1655.      */
  1656.     /*
  1657.      * Since the assembler bumps it's line counters at the end of a line
  1658.      * and it is the case that the .line is on it's own line what the
  1659.      * intent is that the line number is for the next line.  Thus
  1660.      * the -1 .  This is the way cpp'ed assembler files work which is the
  1661.      * common case.
  1662.      */
  1663.     new_logical_line((char *)NULL, (int)(get_absolute_expression()) - 1);
  1664.     demand_empty_rest_of_line();
  1665. }
  1666.  
  1667. /*
  1668.  * s_lsym() implements the pseudo op:
  1669.  *    .lsym name , expression
  1670.  */
  1671. static
  1672. void
  1673. s_lsym(
  1674. int value)
  1675. {
  1676.     char *name;
  1677.     char c;
  1678.     char *p;
  1679.     segT segment;
  1680.     expressionS exp;
  1681.     symbolS *symbolP;
  1682.  
  1683.     /* we permit ANY expression: BSD4.2 demands constants */
  1684.     if(*input_line_pointer == '"')
  1685.         name = input_line_pointer + 1;
  1686.     else
  1687.         name = input_line_pointer;
  1688.     c = get_symbol_end();
  1689.     p = input_line_pointer;
  1690.     *p = c;
  1691.     SKIP_WHITESPACE();
  1692.     if(*input_line_pointer != ','){
  1693.         *p = 0;
  1694.         as_warn("Expected comma after name \"%s\"", name);
  1695.         *p = c;
  1696.         ignore_rest_of_line();
  1697.         return;
  1698.     }
  1699.     input_line_pointer++;
  1700.     segment = expression(&exp);
  1701.     if(segment != SEG_ABSOLUTE && segment != SEG_SECT){
  1702. /* this warning still need fixing */
  1703.         as_warn("Bad expression: %s", seg_name[(int)segment]);
  1704.         ignore_rest_of_line();
  1705.         return;
  1706.     }
  1707.     know(segment == SEG_ABSOLUTE || segment == SEG_SECT);
  1708.     *p = 0;
  1709.     if(segment == SEG_SECT)
  1710.         symbolP = symbol_new(name,
  1711.                  N_SECT,
  1712.                      frchain_now->frch_nsect,
  1713.                  0,
  1714.                  (valueT)(exp.X_add_number),
  1715.                  &zero_address_frag);
  1716.     else
  1717.         symbolP = symbol_new(name,
  1718.                  N_ABS,
  1719.                      0,
  1720.                  0,
  1721.                  (valueT)(exp.X_add_number),
  1722.                  &zero_address_frag);
  1723.     *p = c;
  1724.     demand_empty_rest_of_line();
  1725. }
  1726.  
  1727. #if !defined(I860) /* i860 has it's own align and org */
  1728. /*
  1729.  * s_org() implements the pseudo op:
  1730.  *    .org  expression
  1731.  */
  1732. static
  1733. void
  1734. s_org(
  1735. int value)
  1736. {
  1737.     segT segment;
  1738.     expressionS exp;
  1739.     long temp_fill;
  1740.     char *p;
  1741.  
  1742.     /*
  1743.      * Don't believe the documentation of BSD 4.2 AS.
  1744.      * There is no such thing as a sub-segment-relative origin.
  1745.      * Any absolute origin is given a warning, then assumed to be
  1746.      * segment-relative.
  1747.      * Any segmented origin expression ("foo+42") had better be in the right
  1748.      * segment or the .org is ignored.
  1749.      *
  1750.      * BSD 4.2 AS warns if you try to .org backwards. We cannot because we
  1751.      * never know sub-segment sizes when we are reading code.
  1752.      * BSD will crash trying to emit -ve numbers of filler bytes in certain
  1753.      * .orgs. We don't crash, but see as-write for that code.
  1754.      */
  1755.     segment = get_known_segmented_expression(&exp);
  1756.     if(*input_line_pointer == ','){
  1757.         input_line_pointer ++;
  1758.         temp_fill = get_absolute_expression ();
  1759.     }
  1760.     else
  1761.         temp_fill = 0;
  1762.     if((segment != SEG_SECT ||
  1763.         exp.X_add_symbol->sy_other != frchain_now->frch_nsect) &&
  1764.         segment != SEG_ABSOLUTE)
  1765.         as_warn("Illegal expression. current section assumed.");
  1766.     p = frag_var(rs_org,
  1767.              1,
  1768.              1,
  1769.              (relax_substateT)0,
  1770.              exp.X_add_symbol,
  1771.              exp.X_add_number,
  1772.              (char *)0);
  1773.     *p = temp_fill;
  1774.     demand_empty_rest_of_line();
  1775. }
  1776. #endif /* !defined(I860) i860 has it's own align and org */
  1777.  
  1778. /*
  1779.  * s_set() implements the pseudo op:
  1780.  *    .set name , expression
  1781.  */
  1782. static
  1783. void
  1784. s_set(
  1785. int value)
  1786. {
  1787.     char *name;
  1788.     char delim;
  1789.     char *end_name;
  1790.     symbolS *symbolP;
  1791.  
  1792.     if( * input_line_pointer == '"')
  1793.         name = input_line_pointer + 1;
  1794.     else
  1795.         name = input_line_pointer;
  1796.     delim = get_symbol_end();
  1797.     end_name = input_line_pointer;
  1798.     *end_name = delim;
  1799.     SKIP_WHITESPACE();
  1800.     if(*input_line_pointer != ','){
  1801.         *end_name = 0;
  1802.         as_warn("Expected comma after name \"%s\"", name);
  1803.         *end_name = delim;
  1804.         ignore_rest_of_line();
  1805.         return;
  1806.     }
  1807.     input_line_pointer++;
  1808.     *end_name = 0;
  1809.     if(name[0] == '.' && name[1] == '\0'){
  1810.         /* Turn 'set . , mumble' into a .org mumble */
  1811.         segT segment;
  1812.         expressionS exp;
  1813.         char *ptr;
  1814.  
  1815.         segment = get_known_segmented_expression(&exp);
  1816.         if((segment != SEG_SECT ||
  1817.         exp.X_add_symbol->sy_other != frchain_now->frch_nsect) &&
  1818.         segment != SEG_ABSOLUTE)
  1819.         as_warn("Illegal expression. current section assumed.");
  1820.         ptr = frag_var(rs_org,
  1821.                1,
  1822.                1,
  1823.                (relax_substateT)0,
  1824.                exp.X_add_symbol,
  1825.                exp.X_add_number,
  1826.                (char *)0);
  1827.         *ptr = 0;
  1828.         *end_name = delim;
  1829.         return;
  1830.     }
  1831.     symbolP = symbol_find_or_make(name);
  1832.     *end_name = delim;
  1833.     pseudo_set(symbolP);
  1834.     demand_empty_rest_of_line();
  1835. }
  1836.  
  1837. /*
  1838.  * s_abs() implements the pseudo op:
  1839.  *    .abs name , expression
  1840.  * which sets symbol to 1 or 0 depending on if the expression is an absolute
  1841.  * expression.  This is intended for use in macros.
  1842.  */
  1843. void
  1844. s_abs(
  1845. int value)
  1846. {
  1847.     char *name;
  1848.     char c;
  1849.     char *p;
  1850.     segT segment;
  1851.     expressionS exp;
  1852.     symbolS *symbolP;
  1853.  
  1854.     if(*input_line_pointer == '"')
  1855.         name = input_line_pointer + 1;
  1856.     else
  1857.         name = input_line_pointer;
  1858.     c = get_symbol_end();
  1859.     p = input_line_pointer;
  1860.     *p = c;
  1861.     SKIP_WHITESPACE();
  1862.     if(*input_line_pointer != ','){
  1863.         *p = 0;
  1864.         as_warn("Expected comma after name \"%s\"", name);
  1865.         *p = c;
  1866.         ignore_rest_of_line();
  1867.         return;
  1868.     }
  1869.     input_line_pointer++;
  1870.     *p = 0;
  1871.     segment = expression(&exp);
  1872.     symbolP = symbol_find_or_make(name);
  1873.     symbolP->sy_type = N_ABS;
  1874.     symbolP->sy_other = 0; /* NO_SECT */
  1875.     symbolP->sy_frag = &zero_address_frag;
  1876.     if(segment == SEG_ABSOLUTE)
  1877.         symbolP->sy_value = 1;
  1878.     else
  1879.         symbolP->sy_value = 0;
  1880.     *p = c;
  1881.     totally_ignore_line();
  1882. }
  1883.  
  1884. /*
  1885.  * s_space() implements the pseudo op:
  1886.  *    .space repeat_expression [ , fill_expression ]
  1887.  */
  1888. void
  1889. s_space(
  1890. int value)
  1891. {
  1892.     long temp_repeat;
  1893.     long temp_fill;
  1894.     char *p;
  1895.  
  1896.     /* Just like .fill, but temp_size = 1 */
  1897.     if(get_absolute_expression_and_terminator(&temp_repeat) == ','){
  1898.         temp_fill = get_absolute_expression();
  1899.     }
  1900.     else{
  1901.         input_line_pointer--; /* Backup over what was not a ','. */
  1902.         temp_fill = 0;
  1903.     }
  1904.     if(temp_repeat <= 0){
  1905.         as_warn("Repeat < 0, .space ignored");
  1906.         ignore_rest_of_line();
  1907.         return;
  1908.     }
  1909.     p = frag_var(rs_fill,
  1910.              1,
  1911.              1,
  1912.              (relax_substateT)0,
  1913.              (symbolS *)0,
  1914.              temp_repeat,
  1915.              (char *)0);
  1916.     *p = temp_fill;
  1917.     demand_empty_rest_of_line();
  1918. }
  1919.  
  1920. static
  1921. unsigned long
  1922. s_builtin_section(
  1923. const struct builtin_section *s)
  1924. {
  1925.     frchainS *frcP;
  1926.  
  1927.     if(!flagseen['k']){
  1928.         if((s->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS ||
  1929.            (s->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS ||
  1930.            (s->flags & SECTION_TYPE) == S_SYMBOL_STUBS ||
  1931.            (s->flags & SECTION_TYPE) == S_MOD_INIT_FUNC_POINTERS ||
  1932.            (s->flags & SECTION_ATTRIBUTES) != 0)
  1933.         as_fatal("incompatible feature used: directive .%s (must "
  1934.              "specify \"-dynamic\" to be used)", s->directive);
  1935.     }
  1936.     /*
  1937.      * If we allowed to use the new features that are incompatible with 3.2
  1938.      * and this is the text section (which relys on the fact that the text
  1939.      * section is first in the built in sections list) then add the
  1940.      * S_ATTR_PURE_INSTRUCTIONS to the section attributes.
  1941.      */
  1942.     if(flagseen['k'] && s == builtin_sections){
  1943.         frcP = section_new(s->segname, s->sectname,
  1944.                    s->flags & SECTION_TYPE,
  1945.                    (s->flags & SECTION_ATTRIBUTES) |
  1946.                     S_ATTR_PURE_INSTRUCTIONS,
  1947.                    s->sizeof_stub);
  1948.     }
  1949.     else{
  1950.         frcP = section_new(s->segname, s->sectname,
  1951.                    s->flags & SECTION_TYPE,
  1952.                    s->flags & SECTION_ATTRIBUTES, 
  1953.                    s->sizeof_stub);
  1954.     }
  1955.     if(frcP->frch_section.align < s->default_align)
  1956.         frcP->frch_section.align = s->default_align;
  1957.     return(frcP->frch_nsect);
  1958. }
  1959.  
  1960. /*
  1961.  * s_section() implements the pseudo op:
  1962.  *    .section segname , sectname [[[ , type ] , attribute] , sizeof_stub]
  1963.  */
  1964. static
  1965. void
  1966. s_section(
  1967. int value)
  1968. {
  1969.     char *segname, *sectname, *typename;
  1970.     char c, d, e, *p, *q, *r;
  1971.     struct type_name *type_name;
  1972.     unsigned long type, attribute;
  1973.     struct section s;
  1974.     frchainS *frcP;
  1975.     unsigned long sizeof_stub;
  1976.  
  1977.     struct attribute_name *attribute_name;
  1978.     char *attributename, *sizeof_stub_name, f, g, *t, *u, *endp;
  1979.  
  1980.     segname = input_line_pointer;
  1981.     do{
  1982.         c = *input_line_pointer++ ;
  1983.     }while(c != ',' && c != '\0' && c != '\n');
  1984.     if(c != ','){
  1985.         as_warn("Expected comma after segment-name");
  1986.         ignore_rest_of_line();
  1987.         return;
  1988.     }
  1989.     p = input_line_pointer - 1;
  1990.  
  1991.     sectname = input_line_pointer;
  1992.     do{
  1993.         d = *input_line_pointer++ ;
  1994.     }while(d != ',' && d != '\0' && d != '\n');
  1995.     if(p + 1 == input_line_pointer){
  1996.         as_warn("Expected section-name after comma");
  1997.         ignore_rest_of_line();
  1998.         return;
  1999.     }
  2000.     q = input_line_pointer - 1;
  2001.  
  2002.     *p = 0;
  2003.     if(strlen(segname) > sizeof(s.segname)){
  2004.         as_warn("segment-name: %s too long (maximum %ld characters)",
  2005.             segname, sizeof(s.segname));
  2006.         ignore_rest_of_line();
  2007.         *p = c;
  2008.         return;
  2009.     }
  2010.  
  2011.     *q = 0;
  2012.     if(strlen(sectname) > sizeof(s.sectname)){
  2013.         as_warn("section-name: %s too long (maximum %ld characters)",
  2014.             sectname, sizeof(s.sectname));
  2015.         ignore_rest_of_line();
  2016.         return;
  2017.     }
  2018.     /*
  2019.      * Now see if the optional section type is present.
  2020.      */
  2021.     type = 0;
  2022.     type_name = type_names;
  2023.     attribute = 0;
  2024.     attribute_name = attribute_names;
  2025.     sizeof_stub = 0;
  2026.     if(d == ','){
  2027.         typename = input_line_pointer;
  2028.         do{
  2029.         e = *input_line_pointer++ ;
  2030.         }
  2031.         while(e != ',' && e != '\0' && e != '\n');
  2032.         r = input_line_pointer - 1;
  2033.         *r = 0;
  2034.         for(type_name = type_names; type_name->name != NULL; type_name++)
  2035.         if(strcmp(type_name->name, typename) == 0)
  2036.             break;
  2037.         if(type_name->name == NULL){
  2038.         as_warn("unknown section type: %s", typename);
  2039.         ignore_rest_of_line();
  2040.         return;
  2041.         }
  2042.         *r = e;
  2043.         type = type_name->type;
  2044.         /*
  2045.          * Now see if the optional section attribute is present.
  2046.          */
  2047.         if(e == ','){
  2048.         attributename = input_line_pointer;
  2049.         do{
  2050.             f = *input_line_pointer++ ;
  2051.         }while(f != ',' && f != '\0' && f != '\n');
  2052.         t = input_line_pointer - 1;
  2053.         *t = 0;
  2054.         for(attribute_name = attribute_names;
  2055.             attribute_name->name != NULL;
  2056.             attribute_name++)
  2057.             if(strcmp(attribute_name->name, attributename) == 0)
  2058.             break;
  2059.         if(attribute_name->name == NULL){
  2060.             as_warn("unknown section attribute: %s", attributename);
  2061.             ignore_rest_of_line();
  2062.             return;
  2063.         }
  2064.         *t = f;
  2065.         attribute = attribute_name->attribute;
  2066.  
  2067.         /*
  2068.          * Now get the section stub size if this is a stub section.
  2069.          */
  2070.         if(type == S_SYMBOL_STUBS){
  2071.             if(f == ','){
  2072.             sizeof_stub_name = input_line_pointer;
  2073.             do{
  2074.                 g = *input_line_pointer++ ;
  2075.             }while(g != '\0' && g != '\n');
  2076.             u = input_line_pointer - 1;
  2077.             *u = 0;
  2078.             sizeof_stub = strtoul(sizeof_stub_name, &endp, 0);
  2079.             if(*endp != '\0'){
  2080.                 as_warn("size of stub section: %s not a proper "
  2081.                     "number", sizeof_stub_name);
  2082.                 ignore_rest_of_line();
  2083.                 return;
  2084.             }
  2085.             *u = g;
  2086.             }
  2087.             else{
  2088.             as_warn("missing size of stub section (%s,%s)", segname,
  2089.                 sectname);
  2090.             ignore_rest_of_line();
  2091.             return;
  2092.             }
  2093.         }
  2094.         }
  2095.         else if(type == S_SYMBOL_STUBS){
  2096.         as_warn("missing size of stub section (%s,%s)", segname,
  2097.             sectname);
  2098.         ignore_rest_of_line();
  2099.         return;
  2100.         }
  2101.     }
  2102.     input_line_pointer--;
  2103.  
  2104.     if(!flagseen['k']){
  2105.         if(type == S_NON_LAZY_SYMBOL_POINTERS ||
  2106.            type == S_LAZY_SYMBOL_POINTERS ||
  2107.            type == S_SYMBOL_STUBS ||
  2108.            type == S_MOD_INIT_FUNC_POINTERS)
  2109.         as_fatal("incompatible feature used: section type %s (must "
  2110.              "specify \"-dynamic\" to be "
  2111.              "used)", type_name->name);
  2112.         if(attribute != 0)
  2113.         as_fatal("incompatible feature used: section attribute %s "
  2114.              "(must specify \"-dynamic\" to be used)",
  2115.              attribute_name->name);
  2116.     }
  2117.  
  2118.     frcP = section_new(segname, sectname, type, attribute, sizeof_stub);
  2119.     *p = c;
  2120.     *q = d;
  2121.     demand_empty_rest_of_line();
  2122. }
  2123.  
  2124. /*
  2125.  * s_zerofill() implements the pseudo op:
  2126.  *    .zerofill segname , sectname [, symbolname , size_expression [ , align]]
  2127.  */
  2128. static
  2129. void
  2130. s_zerofill(
  2131. int value)
  2132. {
  2133.     char *segname, *sectname, c, d, *p, *q, *name;
  2134.     struct section s;
  2135.     frchainS *frcP;
  2136.     symbolS *symbolP;
  2137.     int size, align;
  2138.  
  2139.     segname = input_line_pointer;
  2140.     do{
  2141.         c = *input_line_pointer++ ;
  2142.     }while(c != ',' && c != '\0' && c != '\n');
  2143.     if(c != ','){
  2144.         as_warn("Expected comma after segment-name");
  2145.         ignore_rest_of_line();
  2146.         return;
  2147.     }
  2148.     p = input_line_pointer - 1;
  2149.  
  2150.     sectname = input_line_pointer;
  2151.     do{
  2152.         d = *input_line_pointer++ ;
  2153.     }while(d != ',' && d != '\0' && d != '\n');
  2154.     if(p + 1 == input_line_pointer){
  2155.         as_warn("Expected section-name after comma");
  2156.         ignore_rest_of_line();
  2157.         return;
  2158.     }
  2159.     q = input_line_pointer - 1;
  2160.  
  2161.     *p = 0;
  2162.     if(strlen(segname) > sizeof(s.segname)){
  2163.         as_warn("segment-name: %s too long (maximum %ld characters)",
  2164.             segname, sizeof(s.segname));
  2165.         ignore_rest_of_line();
  2166.         *p = c;
  2167.         return;
  2168.     }
  2169.  
  2170.     *q = 0;
  2171.     if(strlen(sectname) > sizeof(s.sectname)){
  2172.         as_warn("section-name: %s too long (maximum %ld characters)",
  2173.             sectname, sizeof(s.sectname));
  2174.         ignore_rest_of_line();
  2175.         *p = c;
  2176.         *q = d;
  2177.         return;
  2178.     }
  2179.  
  2180.     frcP = section_new(segname, sectname, S_ZEROFILL, 0, 0);
  2181.     if(frcP->frch_root == NULL){
  2182.         frcP->frch_root = xmalloc(SIZEOF_STRUCT_FRAG);
  2183.         frcP->frch_last = frcP->frch_root;
  2184.         memset(frcP->frch_root, '\0', SIZEOF_STRUCT_FRAG);
  2185.     }
  2186.     *p = c;
  2187.     *q = d;
  2188.     /*
  2189.      * If this is the end of the line all that was wanted was to create the
  2190.      * the section which is now done, so return.
  2191.      */
  2192.     if(d != ',')
  2193.         return;
  2194.  
  2195.     if(*input_line_pointer == '"')
  2196.         name = input_line_pointer + 1;
  2197.     else
  2198.         name = input_line_pointer;
  2199.     c = get_symbol_end();
  2200.     p = input_line_pointer;
  2201.     *p = c;
  2202.     SKIP_WHITESPACE();
  2203.     if(*input_line_pointer != ','){
  2204.         as_warn("Expected comma after symbol-name");
  2205.         ignore_rest_of_line();
  2206.         return;
  2207.     }
  2208.     input_line_pointer ++;
  2209.     if((size = get_absolute_expression()) < 0){
  2210.         as_warn("zerofill size (%d.) <0! Ignored.", size);
  2211.         ignore_rest_of_line();
  2212.         return;
  2213.     }
  2214.     align = 0;
  2215.     if(*input_line_pointer == ','){
  2216.         input_line_pointer++;
  2217.         align = get_absolute_expression();
  2218.         if(align > MAX_ALIGNMENT){
  2219.         as_warn("Alignment too large: %d. assumed.", MAX_ALIGNMENT);
  2220.         align = MAX_ALIGNMENT;
  2221.         }
  2222.         else if(align < 0){
  2223.         as_warn("Alignment negative. 0 assumed.");
  2224.         align = 0;
  2225.         }
  2226.         /*
  2227.          * If this alignment is larger than any previous alignment then this
  2228.          * becomes the section's alignment.
  2229.          */
  2230.         if(frcP->frch_section.align < align)
  2231.         frcP->frch_section.align = align;
  2232.     }
  2233.     *p = 0;
  2234.     symbolP = symbol_find_or_make(name);
  2235.     *p = c;
  2236.  
  2237.     if((symbolP->sy_type & N_TYPE) == N_UNDF && symbolP->sy_value == 0){
  2238.         frcP->frch_root->fr_address = round(frcP->frch_root->fr_address,
  2239.                             1 << align);
  2240.         symbolP->sy_value = frcP->frch_root->fr_address;
  2241.         symbolP->sy_type  = N_SECT | (symbolP->sy_type & N_EXT);
  2242.         symbolP->sy_other = frcP->frch_nsect;
  2243.         symbolP->sy_frag  = frcP->frch_root;
  2244.         frcP->frch_root->fr_address += size;
  2245.     }
  2246.     else
  2247.         as_warn("Ignoring attempt to re-define symbol.");
  2248.  
  2249.     demand_empty_rest_of_line();
  2250. }
  2251.  
  2252. /*
  2253.  * s_reference() implements the pseudo op:
  2254.  *    .reference name
  2255.  */
  2256. static
  2257. void
  2258. s_reference(
  2259. int value)
  2260. {
  2261.     char *name;
  2262.     char c;
  2263.     char *p;
  2264.     symbolS *symbolP;
  2265.  
  2266.     if(* input_line_pointer == '"')
  2267.         name = input_line_pointer + 1;
  2268.     else
  2269.         name = input_line_pointer;
  2270.     c = get_symbol_end();
  2271.     p = input_line_pointer;
  2272.  
  2273.     *p = 0;
  2274.     symbolP = symbol_find_or_make(name);
  2275.     *p = c;
  2276.     demand_empty_rest_of_line();
  2277. }
  2278.  
  2279. /*
  2280.  * s_lazy_reference() implements the pseudo op:
  2281.  *    .lazy_reference name
  2282.  */
  2283. static
  2284. void
  2285. s_lazy_reference(
  2286. int value)
  2287. {
  2288.     char *name;
  2289.     char c;
  2290.     char *p;
  2291.     symbolS *symbolP;
  2292.  
  2293.     if(!flagseen['k'])
  2294.         as_fatal("incompatible feature used: .lazy_reference (must specify "
  2295.              "\"-dynamic\" to be used)");
  2296.  
  2297.     if(* input_line_pointer == '"')
  2298.         name = input_line_pointer + 1;
  2299.     else
  2300.         name = input_line_pointer;
  2301.     c = get_symbol_end();
  2302.     p = input_line_pointer;
  2303.  
  2304.     *p = 0;
  2305.     symbolP = symbol_find_or_make(name);
  2306.     if((symbolP->sy_type & N_TYPE) == N_UNDF && symbolP->sy_value == 0)
  2307.         symbolP->sy_desc |= REFERENCE_FLAG_UNDEFINED_LAZY;
  2308.     *p = c;
  2309.     demand_empty_rest_of_line();
  2310. }
  2311.  
  2312. /*
  2313.  * s_include() implements the pseudo op:
  2314.  *    .include "filename"
  2315.  */
  2316. static
  2317. void
  2318. s_include(
  2319. int value)
  2320. {
  2321.     char *filename;
  2322.     int length;
  2323.     symbolS *symbolP;
  2324.  
  2325.     /* Some assemblers tolerate immediately following '"' */
  2326.     if((filename = demand_copy_string( & length ) )) {
  2327.         demand_empty_rest_of_line();
  2328.         read_an_include_file(filename);
  2329.     }
  2330.  
  2331.     /*
  2332.      * This is to generate stabs for debugging assembly code.
  2333.      * See the second comment about stabs in read_a_source_file()
  2334.      * for a description of what is going on here
  2335.      */
  2336.     if(flagseen['g'] && frchain_now->frch_nsect == text_nsect){
  2337.         symbolP = symbol_new(
  2338.                 physical_input_file,
  2339.                 132 /* N_SOL */,
  2340.                 text_nsect,
  2341.                 0,
  2342.                 obstack_next_free(&frags) - frag_now->fr_literal,
  2343.                 frag_now);
  2344.     }
  2345. }
  2346.  
  2347. /*
  2348.  * demand_empty_rest_of_line() checks to make sure we are at the end of a line
  2349.  * and if not ignores the rest of the line.
  2350.  * This is global so machine dependent pseudo-ops can use this.
  2351.  */
  2352. void
  2353. demand_empty_rest_of_line(
  2354. void)
  2355. {
  2356.     SKIP_WHITESPACE();
  2357.     if(is_end_of_line[(int)*input_line_pointer])
  2358.         input_line_pointer++;
  2359.     else
  2360.         ignore_rest_of_line();
  2361. }
  2362.  
  2363. /*
  2364.  * ignore_rest_of_line() advances input_line_pointer to the next line and if
  2365.  * there is anything left on the current line print a warning.
  2366.  * This is global so machine dependent pseudo-ops can use this.
  2367.  */
  2368. void
  2369. ignore_rest_of_line(
  2370. void)
  2371. {
  2372.     if(!is_end_of_line[(int)*input_line_pointer]){
  2373.         as_warn("Rest of line ignored. 1st junk character valued %d (%c).",
  2374.             *input_line_pointer, *input_line_pointer);
  2375.         while(input_line_pointer < buffer_limit &&
  2376.           !is_end_of_line[(int)*input_line_pointer])
  2377.         input_line_pointer++;
  2378.     }
  2379.     input_line_pointer++;    /* Return pointing just after end-of-line. */
  2380.     know(is_end_of_line[(int)(input_line_pointer[-1])]);
  2381. }
  2382.  
  2383. /*
  2384.  *            stab()
  2385.  *
  2386.  * Handle .stabX directives, which used to be open-coded.
  2387.  * So much creeping featurism overloaded the semantics that we decided
  2388.  * to put all .stabX thinking in one place. Here.
  2389.  *
  2390.  * We try to make any .stabX directive legal. Other people's AS will often
  2391.  * do assembly-time consistency checks: eg assigning meaning to n_type bits
  2392.  * and "protecting" you from setting them to certain values. (They also zero
  2393.  * certain bits before emitting symbols. Tut tut.)
  2394.  *
  2395.  * If an expression is not absolute we either gripe or use the relocation
  2396.  * information. Other people's assemblers silently forget information they
  2397.  * don't need and invent information they need that you didn't supply.
  2398.  *
  2399.  * .stabX directives always make a symbol table entry. It may be junk if
  2400.  * the rest of your .stabX directive is malformed.
  2401.  */
  2402. static
  2403. void
  2404. stab(
  2405. int what) /* d == .stabd, n == .stabn, and s == .stabs */
  2406. {
  2407.     symbolS *symbolP;
  2408.     char *string;
  2409.     int saved_type;
  2410.     int length;
  2411.     int goof;    /* TRUE if we have aborted. */
  2412.     long longint;
  2413.  
  2414.     saved_type = 0;
  2415.     symbolP = NULL;
  2416.     /*
  2417.      * Enter with input_line_pointer pointing past .stabX and any following
  2418.      * whitespace.
  2419.      */
  2420.     goof = FALSE;
  2421.     if(what == 's'){
  2422.         string = demand_copy_C_string(&length);
  2423.         SKIP_WHITESPACE();
  2424.         if(*input_line_pointer == ',')
  2425.         input_line_pointer ++;
  2426.         else{
  2427.         as_warn("I need a comma after symbol's name");
  2428.         goof = TRUE;
  2429.         }
  2430.     }
  2431.     else
  2432.         string = "";
  2433.  
  2434.     /*
  2435.      * Input_line_pointer->after ','.  String -> symbol name.
  2436.      */
  2437.     if(!goof){
  2438.         symbolP = symbol_new(string, 0,0,0,0,(struct frag *)0);
  2439.         switch(what){
  2440.         case 'd':
  2441.         symbolP->sy_name = NULL; /* .stabd feature. */
  2442.         symbolP->sy_value = obstack_next_free(&frags) -
  2443.                     frag_now->fr_literal;
  2444.         symbolP->sy_frag = frag_now;
  2445.         break;
  2446.  
  2447.         case 'n':
  2448.         case 's':
  2449.         symbolP->sy_frag = &zero_address_frag;
  2450.         break;
  2451.  
  2452.         default:
  2453.         BAD_CASE( what );
  2454.         break;
  2455.         }
  2456.         if(get_absolute_expression_and_terminator(&longint) == ','){
  2457.         saved_type = longint;
  2458.         symbolP->sy_type = longint;
  2459.         }
  2460.         else{
  2461.         as_warn("I want a comma after the n_type expression");
  2462.         goof = TRUE;
  2463.         input_line_pointer--; /* Backup over a non-',' char. */
  2464.         }
  2465.     }
  2466.  
  2467.     if(!goof){
  2468.         if(get_absolute_expression_and_terminator(&longint) == ',')
  2469.         symbolP->sy_other = longint;
  2470.         else {
  2471.         as_warn("I want a comma after the n_other expression");
  2472.         goof = TRUE;
  2473.         input_line_pointer--; /* Backup over a non-',' char. */
  2474.         }
  2475.     }
  2476.  
  2477.     if(!goof){
  2478.         symbolP->sy_desc = get_absolute_expression();
  2479.         if(what == 's' || what == 'n'){
  2480.         if(*input_line_pointer != ','){
  2481.             as_warn( "I want a comma after the n_desc expression" );
  2482.             goof = TRUE;
  2483.         }
  2484.         else
  2485.             input_line_pointer ++;
  2486.         }
  2487.     }
  2488.  
  2489.     if((!goof) && (what=='s' || what=='n')){
  2490.         pseudo_set(symbolP);
  2491.         symbolP->sy_type = saved_type;
  2492.     }
  2493.     else if(!goof){
  2494.         /* for stabd the sy_other (n_sect) gets set to the current section*/
  2495.         symbolP->sy_other = frchain_now->frch_nsect;
  2496.     }
  2497.     if(goof)
  2498.         ignore_rest_of_line();
  2499.     else
  2500.         demand_empty_rest_of_line();
  2501. }
  2502.  
  2503. /*
  2504.  *            pseudo_set()
  2505.  *
  2506.  * In:    Pointer to a symbol.
  2507.  *    Input_line_pointer -> expression.
  2508.  *
  2509.  * Out:    Input_line_pointer -> just after any whitespace after expression.
  2510.  *    Tried to set symbol to value of expression.
  2511.  *    Will change sy_type, sy_value, sy_frag;
  2512.  *(old ->> May set need_pass_2 == TRUE. <<-- commented out by GNU below it
  2513.  * uses symbolP->sy_forward = exp.X_add_symbol;)
  2514.  */
  2515. static
  2516. void
  2517. pseudo_set(
  2518. symbolS *symbolP)
  2519. {
  2520.     expressionS exp;
  2521.     segT segment;
  2522.     int ext;
  2523.  
  2524.     know(symbolP);        /* NULL pointer is logic error. */
  2525.     ext = (symbolP->sy_type & N_EXT);
  2526.     segment = expression(&exp);
  2527.  
  2528.     switch(segment){
  2529.     case SEG_BIG:
  2530.         as_warn("%s number illegal. Absolute 0 assumed.",
  2531.             exp.X_add_number > 0 ? "Bignum" : "Floating-Point");
  2532.         symbolP->sy_type = N_ABS | ext;
  2533.         symbolP->sy_other = 0; /* NO_SECT */
  2534.         symbolP->sy_value = 0;
  2535.         symbolP->sy_frag = &zero_address_frag;
  2536.         break;
  2537.  
  2538.     case SEG_NONE:
  2539.         as_warn("No expression:  Using absolute 0");
  2540.         symbolP->sy_type = N_ABS | ext;
  2541.         symbolP->sy_other = 0; /* NO_SECT */
  2542.         symbolP->sy_value = 0;
  2543.         symbolP->sy_frag = &zero_address_frag;
  2544.         break;
  2545.  
  2546.     case SEG_DIFFSECT:
  2547.         if(exp.X_add_symbol && exp.X_subtract_symbol &&
  2548.            exp.X_add_symbol->sy_other == exp.X_subtract_symbol->sy_other)
  2549.         exp.X_add_number += exp.X_add_symbol->sy_value -
  2550.                     exp.X_subtract_symbol->sy_value;
  2551.         else
  2552.         as_warn("Complex expression. Absolute segment assumed." );
  2553.         /* fall through */
  2554.  
  2555.     case SEG_ABSOLUTE:
  2556.         symbolP->sy_type = N_ABS | ext;
  2557.         symbolP->sy_other = 0; /* NO_SECT */
  2558.         symbolP->sy_value = exp.X_add_number;
  2559.         symbolP->sy_frag = &zero_address_frag;
  2560.         break;
  2561.  
  2562.     case SEG_SECT:
  2563.         symbolP->sy_type  = N_SECT | ext;
  2564.         symbolP->sy_other = exp.X_add_symbol->sy_other;
  2565.         symbolP->sy_value = exp.X_add_number + exp.X_add_symbol->sy_value;
  2566.         symbolP->sy_frag  = exp.X_add_symbol->sy_frag;
  2567.         break;
  2568.       
  2569.     case SEG_UNKNOWN:
  2570.         symbolP->sy_forward = exp.X_add_symbol;
  2571. /* commented out by GNU */
  2572. /* as_warn("unknown symbol"); */
  2573. /* need_pass_2 = TRUE; */
  2574.         break;
  2575.       
  2576.     default:
  2577.         BAD_CASE(segment);
  2578.         break;
  2579.     }
  2580. }
  2581.  
  2582. /*
  2583.  *            cons()
  2584.  *
  2585.  * CONStruct more frag of .bytes, or .words etc.
  2586.  * This understands EXPRESSIONS, as opposed to big_cons().
  2587.  *
  2588.  * Bug (?)
  2589.  *
  2590.  * This has a split personality. We use expression() to read the
  2591.  * value. We can detect if the value won't fit in a byte or word.
  2592.  * But we can't detect if expression() discarded significant digits
  2593.  * in the case of a long. Not worth the crocks required to fix it.
  2594.  *
  2595.  * Worker function to do .byte, .short, .long, statements.
  2596.  * This clobbers input_line_pointer, checks end-of-line.
  2597.  */
  2598. void
  2599. cons(    
  2600. int nbytes) /* nbytes == 1 for .byte, 2 for .word, 4 for .long */
  2601. {
  2602.     char c;
  2603.     long mask;        /* high-order bits to truncate */
  2604.     long unmask;    /* what bits we will store */
  2605.     long get;        /* the bits of the expression we get */
  2606.     long use;        /* the bits of the expression after truncation */
  2607.     char *p;        /* points into the frag */
  2608.     segT segment;
  2609.     expressionS exp;
  2610.  
  2611.     /*
  2612.      * Input_line_pointer -> 1st char after pseudo-op-code and could legally
  2613.      * be a end-of-line. (Or, less legally an eof - which we cope with.)
  2614.      */
  2615.     if(nbytes >= sizeof(long int))
  2616.         mask = 0;
  2617.     else 
  2618.         mask = ~0 << (BITS_PER_CHAR * nbytes); /* Don't store these bits. */
  2619.     unmask = ~mask;        /* Do store these bits. */
  2620.  
  2621.     /*
  2622.      * The following awkward logic is to parse ZERO or more expressions,
  2623.      * comma seperated. Recall an expression includes its leading &
  2624.      * trailing blanks. We fake a leading ',' if there is (supposed to
  2625.      * be) a 1st expression, and keep demanding 1 expression for each ','.
  2626.      */
  2627.     if(is_it_end_of_statement()){
  2628.         c = 0;            /* Skip loop. */
  2629.         input_line_pointer++;    /* Matches end-of-loop 'correction'. */
  2630.     }
  2631.     else
  2632.         c = ',';            /* Do loop. */
  2633.  
  2634.     while(c == ','){
  2635.         segment = expression(&exp); /* At least scan over the expression */
  2636.  
  2637.         if(segment == SEG_DIFFSECT && exp.X_add_symbol == NULL){
  2638.         as_warn("Subtracting symbol \"%s\"(segment\"%s\") is too "
  2639.             "hard. Absolute segment assumed.",
  2640.             exp.X_subtract_symbol->sy_name,
  2641.             seg_name[(int)N_TYPE_seg[
  2642.                 exp.X_subtract_symbol->sy_type & N_TYPE]]);
  2643.         segment = SEG_ABSOLUTE;
  2644.         /* Leave exp .X_add_number alone. */
  2645.         }
  2646.         p = frag_more(nbytes);
  2647.         switch(segment){
  2648.         case SEG_BIG:
  2649.         as_warn("%s number illegal. Absolute 0 assumed.",
  2650.             exp.X_add_number > 0 ? "Bignum" : "Floating-Point");
  2651.         md_number_to_chars(p, (long)0, nbytes);
  2652.         break;
  2653.  
  2654.         case SEG_NONE:
  2655.         as_warn("0 assumed for missing expression");
  2656.         exp.X_add_number = 0;
  2657.         know(exp.X_add_symbol == NULL);
  2658.         /* fall into SEG_ABSOLUTE */
  2659.  
  2660.         case SEG_ABSOLUTE:
  2661.         get = exp.X_add_number;
  2662.         use = get & unmask;
  2663.         if((get & mask) && (get & mask) != mask){
  2664.             /* Leading bits contain both 0s & 1s. */
  2665.             as_warn("Value x%x truncated to x%x.", (unsigned int)get,
  2666.                 (unsigned int)use);
  2667.         }
  2668.         /* put bytes in right order. */
  2669.         md_number_to_chars(p, use, nbytes);
  2670.         break;
  2671.  
  2672.         case SEG_DIFFSECT:
  2673.         case SEG_UNKNOWN:
  2674.         case SEG_SECT:
  2675.         fix_new(frag_now,
  2676.             p - frag_now->fr_literal,
  2677.             nbytes,
  2678.             exp.X_add_symbol,
  2679.             exp.X_subtract_symbol,
  2680.             exp.X_add_number,
  2681.             0,
  2682.             0,
  2683.             0);
  2684.         break;
  2685.  
  2686.         default:
  2687.         BAD_CASE(segment);
  2688.         break;
  2689.         }            /* switch(segment) */
  2690.         c = *input_line_pointer++;
  2691.     }                /* while(c==',') */
  2692.     input_line_pointer--;    /* Put terminator back into stream. */
  2693.     demand_empty_rest_of_line();
  2694. }
  2695.  
  2696. #ifdef M68K /* we allow big cons only on the 68k machines */
  2697. /*
  2698.  *            big_cons()
  2699.  *
  2700.  * CONStruct more frag(s) of .quads, or .octa etc.
  2701.  * Makes 0 or more new frags.
  2702.  * This understands only bignums, not expressions. Cons() understands
  2703.  * expressions.
  2704.  *
  2705.  * Constants recognised are '0...'(octal) '0x...'(hex) '...'(decimal).
  2706.  *
  2707.  * This creates objects with struct obstack_control objs, destroying
  2708.  * any context objs held about a partially completed object. Beware!
  2709.  *
  2710.  *
  2711.  * I think it sucks to have 2 different types of integers, with 2
  2712.  * routines to read them, store them etc.
  2713.  * It would be nicer to permit bignums in expressions and only
  2714.  * complain if the result overflowed. However, due to "efficiency"...
  2715.  *
  2716.  * Worker function to do .quad and .octa statements.
  2717.  * This clobbers input_line_pointer, checks end-of-line.
  2718.  */
  2719. void
  2720. big_cons(
  2721. int nbytes) /* 8 == .quad, 16 == .octa ... */
  2722. {
  2723.     char c;    /* input_line_pointer -> c. */
  2724.     int radix;
  2725.     long length;/* Number of chars in an object. */
  2726.     int digit;    /* Value of 1 digit. */
  2727.     int carry;    /* For multi-precision arithmetic. */
  2728.     int work;    /* For multi-precision arithmetic. */
  2729.     char *p,*q;    /* For multi-precision arithmetic. */
  2730.     int i;
  2731.  
  2732.     /*
  2733.      * The following awkward logic is to parse ZERO or more strings,
  2734.      * comma seperated. Recall an expression includes its leading &
  2735.      * trailing blanks. We fake a leading ',' if there is (supposed to
  2736.      * be) a 1st expression, and keep demanding 1 expression for each ','.
  2737.      */
  2738.     if(is_it_end_of_statement()){
  2739.         c = 0;            /* Skip loop. */
  2740.     }
  2741.     else{
  2742.         c = ',';            /* Do loop. */
  2743.         --input_line_pointer;
  2744.     }
  2745.     while(c == ','){
  2746.         ++input_line_pointer;
  2747.         SKIP_WHITESPACE();
  2748.         c = *input_line_pointer;
  2749.         /* c contains 1st non-blank char of what we hope is a number */
  2750.         if(c == '0'){
  2751.         c = *++input_line_pointer;
  2752.         if(c == 'x' || c=='X'){
  2753.             c = *++input_line_pointer;
  2754.             radix = 16;
  2755.         }
  2756.         else{
  2757.             radix = 8;
  2758.         }
  2759.         }
  2760.         else{
  2761.         radix = 10;
  2762.         }
  2763.         /*
  2764.          * This feature (?) is here to stop people worrying about
  2765.          * mysterious zero constants: which is what they get when
  2766.          * they completely omit digits.
  2767.          */
  2768.         if(hex_value[(int)c] >= radix){
  2769.         as_warn("Missing digits. 0 assumed.");
  2770.         }
  2771.         bignum_high = bignum_low - 1; /* Start constant with 0 chars. */
  2772.         for( ;
  2773.         (digit = hex_value[(int)c]) < radix;
  2774.         c = *++input_line_pointer){
  2775.         /* Multiply existing number by radix, then add digit. */
  2776.         carry = digit;
  2777.         for(p = bignum_low; p <= bignum_high; p++){
  2778.             work = (*p & MASK_CHAR) * radix + carry;
  2779.             *p = work & MASK_CHAR;
  2780.             carry = work >> BITS_PER_CHAR;
  2781.         }
  2782.         if(carry){
  2783.             grow_bignum();
  2784.             *bignum_high = carry & MASK_CHAR;
  2785.             know((carry & ~ MASK_CHAR) == 0);
  2786.         }
  2787.         }
  2788.         length = bignum_high - bignum_low + 1;
  2789.         if(length > nbytes){
  2790.         as_warn("Most significant bits truncated in integer constant.");
  2791.         }
  2792.         else{
  2793.         long leading_zeroes;
  2794.  
  2795.         for(leading_zeroes = nbytes - length;
  2796.             leading_zeroes;
  2797.             leading_zeroes--){
  2798.             grow_bignum();
  2799.             *bignum_high = 0;
  2800.         }
  2801.         }
  2802.         p = frag_more(nbytes);
  2803.         if(md_target_byte_sex == BIG_ENDIAN_BYTE_SEX){
  2804.         q = (char *)bignum_low;
  2805.         for(i = nbytes - 1; i >= 0; i--)
  2806.             *p++ = q[i];
  2807.         }
  2808.         else{
  2809.         memcpy(p, bignum_low, (int)nbytes);
  2810.         }
  2811.         /* C contains character after number. */
  2812.         SKIP_WHITESPACE();
  2813.         c = *input_line_pointer;
  2814.         /* C contains 1st non-blank character after number. */
  2815.     }
  2816.     demand_empty_rest_of_line();
  2817. }
  2818.  
  2819. /*
  2820.  * grow_bignum() extends bignum (that is adjust bignum_low, bignum_high and
  2821.  * bignum_limit).
  2822.  */
  2823. static
  2824. void
  2825. grow_bignum(
  2826. void)
  2827. {
  2828.     long length;
  2829.  
  2830.     bignum_high++;
  2831.     if(bignum_high >= bignum_limit)
  2832.     {
  2833.         length = bignum_limit - bignum_low;
  2834.         bignum_low = xrealloc(bignum_low, length + length);
  2835.         bignum_high = bignum_low + length;
  2836.         bignum_limit = bignum_low + length + length;
  2837.     }
  2838. }
  2839. #endif /* M68K we allow big cons only on the 68k machines */
  2840.  
  2841. /*
  2842.  *            float_cons()
  2843.  *
  2844.  * CONStruct some more frag chars of .floats .ffloats etc.
  2845.  * Makes 0 or more new frags.
  2846.  * This understands only floating literals, not expressions. Sorry.
  2847.  *
  2848.  * A floating constant is defined by atof_generic(), except it is preceded
  2849.  * by 0d 0f 0g or 0h. After observing the STRANGE way my BSD AS does its
  2850.  * reading, I decided to be incompatible. This always tries to give you
  2851.  * rounded bits to the precision of the pseudo-op. Former AS did premature
  2852.  * truncatation, restored noisy bits instead of trailing 0s AND gave you
  2853.  * a choice of 2 flavours of noise according to which of 2 floating-point
  2854.  * scanners you directed AS to use.
  2855.  *
  2856.  * In:    input_line_pointer -> whitespace before, or '0' of flonum.
  2857.  *
  2858.  * Worker function to do .double, .float, .single statements.
  2859.  * This clobbers input_line-pointer, checks end-of-line.
  2860.  */
  2861. void
  2862. float_cons(
  2863. int float_type) /* 'f':.ffloat ... 'F':.float ... */
  2864. {
  2865.     char *p;
  2866.     char c;
  2867.     int length;    /* Number of chars in an object. */
  2868.     char *err;    /* Error from scanning floating literal. */
  2869.     char temp[MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT];
  2870.  
  2871.     /*
  2872.      * The following awkward logic is to parse ZERO or more strings,
  2873.      * comma seperated. Recall an expression includes its leading &
  2874.      * trailing blanks. We fake a leading ',' if there is (supposed to
  2875.      * be) a 1st expression, and keep demanding 1 expression for each ','.
  2876.      */
  2877.     if(is_it_end_of_statement()){
  2878.         c = 0;            /* Skip loop. */
  2879.         ++input_line_pointer;    /* -> past termintor. */
  2880.     }
  2881.     else{
  2882.         c = ',';            /* Do loop. */
  2883.     }
  2884.     while(c == ','){
  2885.         /* input_line_pointer -> 1st char of a flonum (we hope!). */
  2886.         SKIP_WHITESPACE();
  2887.         /*
  2888.          * Skip any 0{letter} that may be present. Don't even check if the
  2889.          * letter is legal. Someone may invent a "z" format and this routine
  2890.          * has no use for such information. Lusers beware: you get
  2891.          * diagnostics if your input is ill-conditioned.
  2892.          */
  2893.         if(input_line_pointer[0] == '0' && isalpha(input_line_pointer[1]))
  2894.         input_line_pointer+=2;
  2895.  
  2896.         err = md_atof(float_type, temp, &length);
  2897.         know(length <=  MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT);
  2898.         know(length > 0);
  2899.         if(*err != '\0'){
  2900.         as_warn( "Bad floating literal: %s", err);
  2901.         ignore_rest_of_line();
  2902.         /* Input_line_pointer -> just after end-of-line. */
  2903.         c = 0;        /* Break out of loop. */
  2904.         }
  2905.         else{
  2906.         p = frag_more(length);
  2907.         memcpy(p, temp, length);
  2908.         SKIP_WHITESPACE();
  2909.         c = *input_line_pointer ++;
  2910.         /* C contains 1st non-white character after number. */
  2911.         /* input_line_pointer -> just after terminator (c). */
  2912.         }
  2913.     }
  2914.     --input_line_pointer;        /* -> terminator (is not ','). */
  2915.     demand_empty_rest_of_line();
  2916. }
  2917.  
  2918. /*
  2919.  *            stringer()
  2920.  *
  2921.  * We read 0 or more ',' seperated, double-quoted strings.
  2922.  *
  2923.  * Worker function to do .ascii etc statements.
  2924.  * Checks end-of-line.
  2925.  */
  2926. void
  2927. stringer(
  2928. int append_zero) /* 0: don't append '\0', else 1 */
  2929. {
  2930.     int c;
  2931.  
  2932.     /*
  2933.      * The following awkward logic is to parse ZERO or more strings,
  2934.      * comma seperated. Recall a string expression includes spaces
  2935.      * before the opening '\"' and spaces after the closing '\"'.
  2936.      * We fake a leading ',' if there is (supposed to be)
  2937.      * a 1st, expression. We keep demanding expressions for each
  2938.      * ','.
  2939.      */
  2940.     if(is_it_end_of_statement()){
  2941.         c = 0;            /* Skip loop. */
  2942.         ++ input_line_pointer;    /* Compensate for end of loop. */
  2943.     }
  2944.     else{
  2945.         c = ',';            /* Do loop. */
  2946.     }
  2947.     for( ; c == ',';  c = *input_line_pointer++){
  2948.         SKIP_WHITESPACE();
  2949.         if(*input_line_pointer == '\"'){
  2950.         ++input_line_pointer; /* -> 1st char of string. */
  2951.         while((c = next_char_of_string()) >= 0){
  2952.             FRAG_APPEND_1_CHAR(c);
  2953.         }
  2954.         if(append_zero){
  2955.             FRAG_APPEND_1_CHAR(0);
  2956.         }
  2957.         know(input_line_pointer[-1] == '\"');
  2958.         }
  2959.         else{
  2960.         as_warn("Expected \"-ed string");
  2961.         }
  2962.         SKIP_WHITESPACE();
  2963.     }
  2964.     --input_line_pointer;
  2965.     demand_empty_rest_of_line();
  2966. }
  2967.  
  2968. /*
  2969.  * next_char_of_string() is used by stringer() and demand_copy_string() and
  2970.  * returns the next character from input_line_pointer that is in the string or 
  2971.  * -1 for the trailing " character.  This routine handles escaped characters
  2972.  * like \b, \f, etc.
  2973.  */
  2974. static
  2975. int
  2976. next_char_of_string(
  2977. void)
  2978. {
  2979.     int c;
  2980.     long number, i;
  2981.  
  2982.     c = *input_line_pointer++;
  2983.     /* make sure the 0xff char is not returned as -1 */
  2984.     c = (c & MASK_CHAR);
  2985.     switch(c){
  2986.     case '\"':
  2987.         c = -1;
  2988.         break;
  2989.  
  2990.     case '\\':
  2991.         c = *input_line_pointer++;
  2992.         switch(c){
  2993.         case 'b':
  2994.         c = '\b';
  2995.         break;
  2996.         case 'f':
  2997.         c = '\f';
  2998.         break;
  2999.         case 'n':
  3000.         c = '\n';
  3001.         break;
  3002.         case 'r':
  3003.         c = '\r';
  3004.         break;
  3005.         case 't':
  3006.         c = '\t';
  3007.         break;
  3008.         case '\\':
  3009.         case '"':
  3010.         break;        /* As itself. */
  3011.         case '0':
  3012.         case '1':
  3013.         case '2':
  3014.         case '3':
  3015.         case '4':
  3016.         case '5':
  3017.         case '6':
  3018.         case '7':
  3019.         case '8':
  3020.         case '9':
  3021.         for(i = 0, number = 0;
  3022.             i < 3 && isdigit(c) && c < '8';
  3023.             i++, c = *input_line_pointer++)
  3024.             number = number * 8 + c - '0';
  3025.         c = number;
  3026.         --input_line_pointer;
  3027.         break;
  3028.         case '\n':
  3029.         /* To be compatible with BSD 4.2 as: give the user a linefeed */
  3030.         c = '\n';
  3031.         break;
  3032.  
  3033.         default:
  3034.         as_warn( "Bad escaped character in string, '?' assumed" );
  3035.         c = '?';
  3036.         break;
  3037.         }
  3038.         break;
  3039.     default:
  3040.         break;
  3041.     }
  3042.     return(c);
  3043. }
  3044.  
  3045. /*
  3046.  * get_segmented_expression() is passed an expression to fill in and return that
  3047.  * is anything except a bignum or a missing expression.
  3048.  */
  3049. static
  3050. segT
  3051. get_segmented_expression(
  3052. expressionS *expP)
  3053. {
  3054.     segT retval;
  3055.  
  3056.     retval = expression(expP);
  3057.     if(retval == SEG_NONE || retval == SEG_BIG){
  3058.         as_warn("Expected address expression: absolute 0 assumed");
  3059.         retval = expP->X_seg = SEG_ABSOLUTE;
  3060.         expP->X_add_number   = 0;
  3061.         expP->X_add_symbol   = NULL;
  3062.         expP->X_subtract_symbol = NULL;
  3063.     }
  3064.     return(retval);        /* SEG_ ABSOLUTE,UNKNOWN,SECT */
  3065. }
  3066.  
  3067. /*
  3068.  * get_known_segmented_expression() is passed an expression to fill in and
  3069.  * return that is anything except an unknown, bignum or a missing expression.
  3070.  */
  3071. segT
  3072. get_known_segmented_expression(
  3073. expressionS *expP)
  3074. {
  3075.     segT retval;
  3076.     char *name1;
  3077.     char *name2;
  3078.  
  3079.     retval = get_segmented_expression(expP);
  3080.     if(retval == SEG_UNKNOWN){
  3081.         name1 = expP->X_add_symbol ?
  3082.             expP->X_add_symbol->sy_name : "";
  3083.         name2 = expP->X_subtract_symbol ?
  3084.             expP->X_subtract_symbol->sy_name : "";
  3085.         if(name1 && name2){
  3086.         as_warn("Symbols \"%s\" \"%s\" are undefined: absolute 0 "
  3087.             "assumed.", name1, name2);
  3088.         }
  3089.         else{
  3090.         as_warn("Symbol \"%s\" undefined: absolute 0 assumed.",
  3091.             name1 ? name1 : name2);
  3092.         }
  3093.         retval      = SEG_ABSOLUTE;
  3094.         expP->X_seg = SEG_ABSOLUTE;
  3095.         expP->X_add_number = 0;
  3096.         expP->X_add_symbol      = NULL;
  3097.         expP->X_subtract_symbol = NULL;
  3098.     }
  3099.     know(retval == SEG_ABSOLUTE ||
  3100.          retval == SEG_SECT ||
  3101.          retval == SEG_DIFFSECT);
  3102.     return(retval);
  3103. }
  3104.  
  3105. /*
  3106.  * get_absolute_expression() gets an absolute expression and returns the value
  3107.  * of that expression.
  3108.  */
  3109. long
  3110. get_absolute_expression(
  3111. void)
  3112. {
  3113.     expressionS exp;
  3114.     segT s;
  3115.  
  3116.     s = expression(&exp);
  3117.     if(s != SEG_ABSOLUTE){
  3118. /* is this right? if not absolute: no message and return 0 */
  3119.         if(s != SEG_NONE){
  3120.         as_warn("Bad Absolute Expression, absolute 0 assumed.");
  3121.         }
  3122.         exp.X_add_number = 0;
  3123.     }
  3124.     return(exp.X_add_number);
  3125. }
  3126.  
  3127. /*
  3128.  * get_absolute_expression_and_terminator() gets an absolute expression and
  3129.  * returning the value of that expression indirectly through val_pointer and
  3130.  * returns the terminator.
  3131.  */
  3132. static
  3133. char            /* return terminator */
  3134. get_absolute_expression_and_terminator(
  3135. long *val_pointer)    /* return value of expression */
  3136. {
  3137.     *val_pointer = get_absolute_expression();
  3138.     return(*input_line_pointer++);
  3139. }
  3140.  
  3141. /*
  3142.  *            demand_copy_C_string()
  3143.  *
  3144.  * Like demand_copy_string, but return NULL if the string contains any '\0's.
  3145.  * Give a warning if that happens.
  3146.  */
  3147. static
  3148. char *
  3149. demand_copy_C_string(
  3150. int *len_pointer)
  3151. {
  3152.     char *s;
  3153.     int len;
  3154.  
  3155.     if((s = demand_copy_string(len_pointer))){
  3156.         for(len = *len_pointer; len > 0; len--){
  3157.         if(*s == '\0'){
  3158.             s = 0;
  3159.             len = 1;
  3160.             *len_pointer = 0;
  3161.             as_warn("This string may not contain \'\\0\'");
  3162.         }
  3163.         }
  3164.     }
  3165.     return(s);
  3166. }
  3167.  
  3168. /*
  3169.  *            demand_copy_string()
  3170.  *
  3171.  * Demand string, but return a safe (=private) copy of the string.
  3172.  * Return NULL if we can't read a string here.
  3173.  */
  3174. static
  3175. char *
  3176. demand_copy_string(
  3177. int *lenP)
  3178. {
  3179.     int c;
  3180.     int len;
  3181.     char *retval;
  3182.  
  3183.     len = 0;
  3184.     SKIP_WHITESPACE();
  3185.     if(*input_line_pointer == '\"'){
  3186.         input_line_pointer++;    /* Skip opening quote. */
  3187.         while((c = next_char_of_string()) >= 0){
  3188.         obstack_1grow(¬es, c);
  3189.         len++;
  3190.         }
  3191.         /*
  3192.          * This next line is so demand_copy_C_string will return a null
  3193.          * termanated string.
  3194.          */
  3195.         obstack_1grow(¬es, '\0');
  3196.         retval = obstack_finish(¬es);
  3197.     }
  3198.     else{
  3199.         as_warn("Missing string");
  3200.         retval = NULL;
  3201.         ignore_rest_of_line();
  3202.     }
  3203.     *lenP = len;
  3204.     return(retval);
  3205. }
  3206.  
  3207. /*
  3208.  *        is_it_end_of_statement()
  3209.  *
  3210.  * In:    Input_line_pointer -> next character.
  3211.  *
  3212.  * Do:    Skip input_line_pointer over all whitespace.
  3213.  *
  3214.  * Out:    TRUE if input_line_pointer -> end-of-line.
  3215.  */
  3216. static
  3217. int
  3218. is_it_end_of_statement(
  3219. void)
  3220. {
  3221.     SKIP_WHITESPACE();
  3222.     return(is_end_of_line[(int)*input_line_pointer]);
  3223. }
  3224.  
  3225. /*
  3226.  * equals() implements the assembly statement:
  3227.  *     x = expression
  3228.  */
  3229. static
  3230. void
  3231. equals(
  3232. char *sym_name)
  3233. {
  3234.     struct symbol *symbolP;
  3235.     segT segment;
  3236.     expressionS exp;
  3237.     char *p;
  3238.  
  3239.     /* Turn '. = mumble' into a .org mumble */
  3240.     if(sym_name[0]=='.' && sym_name[1]=='\0'){
  3241.         if(input_line_pointer[1] == '=')
  3242.         input_line_pointer += 2;
  3243.         else
  3244.         *input_line_pointer++ = '=';        /* Put it back */
  3245.         if(*input_line_pointer==' ' || *input_line_pointer=='\t')
  3246.         input_line_pointer++;
  3247.         segment = get_known_segmented_expression(&exp);
  3248.         if((segment != SEG_SECT ||
  3249.         exp.X_add_symbol->sy_other != frchain_now->frch_nsect) &&
  3250.         segment != SEG_ABSOLUTE)
  3251.         as_warn("Illegal expression. current section assumed.");
  3252.         p = frag_var(rs_org,
  3253.              1,
  3254.              1,
  3255.              (relax_substateT)0,
  3256.              exp.X_add_symbol,
  3257.              exp.X_add_number,
  3258.              (char *)0);
  3259.         *p = 0;
  3260.         return;
  3261.     }
  3262.  
  3263.     symbolP = symbol_find_or_make(sym_name);
  3264.     if(input_line_pointer[1] == '=')
  3265.         input_line_pointer += 2;
  3266.     else
  3267.         *input_line_pointer++ = '=';        /* Put it back */
  3268.     if(*input_line_pointer==' ' || *input_line_pointer=='\t')
  3269.         input_line_pointer++;
  3270.     pseudo_set(symbolP);
  3271. }
  3272.  
  3273. /*
  3274.  * s_if() implements the pseudo op:
  3275.  *    .if expression
  3276.  * that does conditional assembly using assembler defined expressions.
  3277.  */
  3278. static
  3279. void
  3280. s_if(
  3281. int value)
  3282. {
  3283.     if(if_depth >= MAX_IF_DEPTH)
  3284.         as_fatal("You can't nest if's more than %d levels deep",
  3285.              MAX_IF_DEPTH);
  3286.     last_states[if_depth++] = the_cond_state;
  3287.     the_cond_state.the_cond = if_cond;
  3288.     if(the_cond_state.ignore)
  3289.         totally_ignore_line();
  3290.     else{
  3291.         the_cond_state.cond_met = get_absolute_expression();
  3292.         the_cond_state.ignore = !the_cond_state.cond_met;
  3293.         demand_empty_rest_of_line();
  3294.     }
  3295. }
  3296.  
  3297. /*
  3298.  * s_elseif() implements the pseudo op:
  3299.  *    .elseif expression
  3300.  * that does conditional assembly using assembler defined expressions.
  3301.  */
  3302. static
  3303. void
  3304. s_elseif(
  3305. int value)
  3306. {
  3307.     int last_ignore_state;
  3308.  
  3309.     if(the_cond_state.the_cond != if_cond &&
  3310.        the_cond_state.the_cond != elseif_cond)
  3311.         as_fatal("Encountered a .elseif that doesn't follow a .if or an "
  3312.              ".elseif");
  3313.     the_cond_state.the_cond = elseif_cond;
  3314.  
  3315.     last_ignore_state = FALSE;
  3316.     if(if_depth)
  3317.         last_ignore_state = last_states[if_depth-1].ignore;
  3318.         if(last_ignore_state || the_cond_state.cond_met){
  3319.         the_cond_state.ignore = TRUE;
  3320.         totally_ignore_line();
  3321.     }
  3322.     else{
  3323.         the_cond_state.cond_met = get_absolute_expression();
  3324.         the_cond_state.ignore = !the_cond_state.cond_met;
  3325.         demand_empty_rest_of_line();
  3326.     }
  3327. }
  3328.  
  3329. /*
  3330.  * s_else() implements the pseudo op:
  3331.  *    .else
  3332.  * that does conditional assembly using assembler defined expressions.
  3333.  */
  3334. static
  3335. void
  3336. s_else(
  3337. int value)
  3338. {
  3339.     int last_ignore_state;
  3340.  
  3341.     if(the_cond_state.the_cond != if_cond &&
  3342.        the_cond_state.the_cond != elseif_cond)
  3343.         as_fatal("Encountered a .else that doesn't follow a .if or an "
  3344.              ".elseif");
  3345.     the_cond_state.the_cond = else_cond;
  3346.     last_ignore_state = FALSE;
  3347.     if(if_depth)
  3348.         last_ignore_state = last_states[if_depth-1].ignore;
  3349.         if(last_ignore_state || the_cond_state.cond_met)
  3350.         the_cond_state.ignore = TRUE;
  3351.     else
  3352.         the_cond_state.ignore = FALSE;
  3353.     demand_empty_rest_of_line();
  3354. }
  3355.  
  3356. /*
  3357.  * s_endif() implements the pseudo op:
  3358.  *    .endif
  3359.  * that does conditional assembly using assembler defined expressions.
  3360.  */
  3361. static
  3362. void
  3363. s_endif(
  3364. int value)
  3365. {
  3366.     if((the_cond_state.the_cond == no_cond) || (if_depth == 0))
  3367.         as_fatal("Encountered a .endif that doesn't follow a .if or .else");
  3368.     the_cond_state = last_states[--if_depth];
  3369.     demand_empty_rest_of_line();
  3370. }
  3371.  
  3372. /* 
  3373.  * totally_ignore_line() ignores lines during conditional assembly.
  3374.  */
  3375. void
  3376. totally_ignore_line(
  3377. void)
  3378. {
  3379.     if(!is_end_of_line[(int)*input_line_pointer]){
  3380.         while(input_line_pointer < buffer_limit &&
  3381.           !is_end_of_line[(int)*input_line_pointer]){
  3382.         input_line_pointer ++;
  3383.         }
  3384.     }
  3385.     input_line_pointer++;    /* Return pointing just after end-of-line. */
  3386.     know(is_end_of_line[(int)(input_line_pointer[-1])]);
  3387. }
  3388.  
  3389. /*
  3390.  * s_macros_on() implements the pseudo op:
  3391.  *    .macros_on
  3392.  */
  3393. static
  3394. void
  3395. s_macros_on(
  3396. int value)
  3397. {
  3398.     macros_on = TRUE;
  3399.     demand_empty_rest_of_line();
  3400. }
  3401.  
  3402. /*
  3403.  * s_macros_off() implements the pseudo op:
  3404.  *    .macros_off
  3405.  */
  3406. void
  3407. s_macros_off(
  3408. int value)
  3409. {
  3410.     macros_on = FALSE;
  3411.     demand_empty_rest_of_line();
  3412. }
  3413.  
  3414. /*
  3415.  * s_macro() implements the pseudo op:
  3416.  *    .macro macro_name
  3417.  * that defines a macro.
  3418.  */
  3419. void
  3420. s_macro(
  3421. int value)
  3422. {
  3423.     int c;
  3424.     pseudo_typeS *pop;
  3425.  
  3426.     if(macro_name)
  3427.         as_warn("Can't define a macro inside another macro definition");
  3428.     else{
  3429.         SKIP_WHITESPACE();
  3430.         while(is_part_of_name(c = *input_line_pointer ++))
  3431.         obstack_1grow (¯os, c);
  3432.         obstack_1grow(¯os, '\0');
  3433.         --input_line_pointer;
  3434.         macro_name = obstack_finish(¯os);
  3435.         if(macro_name == "")
  3436.         as_warn("Missing name of macro");
  3437.         if(*macro_name == '.'){
  3438.         pop = (pseudo_typeS *)hash_find(po_hash, macro_name + 1);
  3439.         if(pop != NULL)
  3440.             as_warn("Pseudo-op name: %s can't be a macro name",
  3441.                 macro_name);
  3442.         }
  3443.     }
  3444.     totally_ignore_line();
  3445. }
  3446.  
  3447. /*
  3448.  * s_endmacro() implements the pseudo op:
  3449.  *    .endmacro
  3450.  * which is the end of a macro definition.
  3451.  */
  3452. void
  3453. s_endmacro(
  3454. int value)
  3455. {
  3456.     char *errorString;
  3457.  
  3458.     if(!macro_name){
  3459.         as_warn ("This .endmacro does not match with a preceeding .macro");
  3460.         ignore_rest_of_line();
  3461.     }
  3462.     else{
  3463.         obstack_1grow(¯os, '\0');
  3464.         errorString = hash_insert(ma_hash, macro_name,
  3465.                       obstack_finish(¯os));
  3466.         if(*errorString)
  3467.         as_warn("The macro named \"%s\" is already defined",
  3468.             macro_name);
  3469.         macro_name = FALSE;
  3470.     }
  3471. }
  3472.  
  3473. /*
  3474.  * macro_begin() initializes macros.
  3475.  */
  3476. static
  3477. void
  3478. macro_begin(
  3479. void)
  3480. {
  3481.     ma_hash = hash_new();
  3482.     obstack_begin(¯os, 5000);
  3483. }
  3484.  
  3485. /*
  3486.  * add_to_macro_definition() is called after a .macro to store the contents of
  3487.  * a macro into the obstack.
  3488.  */
  3489. void
  3490. add_to_macro_definition(
  3491. char *char_pointer)
  3492. {
  3493.     char c;
  3494.  
  3495.     do{
  3496.         c = *char_pointer ++;
  3497.         know(c != '\0');
  3498.         obstack_1grow(¯os, c);
  3499.     }while((c != ':') && !(is_end_of_line[(int)c]));
  3500.     if(char_pointer > input_line_pointer)
  3501.         input_line_pointer = char_pointer;
  3502. }
  3503.  
  3504. /*
  3505.  * expand_macro() is called to expand macros.
  3506.  */
  3507. static
  3508. void
  3509. expand_macro(
  3510. char *macro_contents)
  3511. {
  3512.     char *buffer;
  3513.     char c;
  3514.     int index, nargs;
  3515.     char *last_buffer_limit;
  3516.     int last_count_lines;
  3517.     char *last_input_line_pointer;
  3518.     char *arguments [10]; /* at most 10 arguments, each is substituted */
  3519.  
  3520.     if(macro_depth >= MAX_MACRO_DEPTH)
  3521.        as_fatal("You can't nest macro's more than %d levels deep",
  3522.             MAX_MACRO_DEPTH);
  3523.     macro_depth++;
  3524.  
  3525.     /* copy each argument to a object in the macro obstack */
  3526.     nargs = 0;
  3527.     for(index = 0; index < 10; index ++){
  3528.         if(*input_line_pointer == ' ')
  3529.         ++input_line_pointer;
  3530.         know(*input_line_pointer != ' ');
  3531.         c = *input_line_pointer;
  3532.         if(is_end_of_line[(int)c])
  3533.         arguments[index] = NULL;
  3534.         else{
  3535.         int parenthesis_depth = 0;
  3536.         do{
  3537.             c = *input_line_pointer++;
  3538.             if(parenthesis_depth){
  3539.             if(c == ')')
  3540.                 parenthesis_depth --;
  3541.             }
  3542.             else{
  3543.             if(c == '(')
  3544.                 parenthesis_depth ++;
  3545.             else
  3546.                 if(is_end_of_line[(int)c] ||
  3547.                    (c == ' ') || (c == ','))
  3548.                 break;
  3549.             }
  3550.             know(c != '\0');
  3551.             if(is_end_of_line[(int)c])
  3552.             as_warn("missmatched parenthesis");
  3553.             obstack_1grow(¯os, c);
  3554.         }while(1);
  3555.         obstack_1grow(¯os, '\0');
  3556.         arguments[index] = obstack_finish(¯os);
  3557.         nargs++;
  3558.         if(is_end_of_line[(int)c])
  3559.             --input_line_pointer;
  3560.         else if(c == ' ')
  3561.             if(*input_line_pointer == ',')
  3562.             input_line_pointer++;
  3563.         }
  3564.     }
  3565.     if(!is_end_of_line[(int)c]){
  3566.         as_warn("More than 10 arguments not allowed for macros");
  3567.         ignore_rest_of_line();
  3568.     }
  3569.     /*
  3570.      * Build a buffer containing the macro contents with arguments
  3571.      * substituted
  3572.      */
  3573.     obstack_1grow(¯os, '\n');
  3574.     while((c = *macro_contents++)){
  3575.         if(c == '$'){
  3576.         if((*macro_contents >= '0') && (*macro_contents <= '9')){
  3577.             index = *macro_contents++ - '0';
  3578.             last_input_line_pointer = macro_contents;
  3579.             macro_contents = arguments[index];
  3580.             if(macro_contents){
  3581.             while ((c = * macro_contents ++))
  3582.             obstack_1grow (¯os, c);
  3583.             }
  3584.             macro_contents = last_input_line_pointer;
  3585.             continue;
  3586.         }
  3587.         else if (*macro_contents == 'n'){
  3588.             macro_contents++ ;
  3589.             obstack_1grow(¯os, nargs + '0');
  3590.             continue;
  3591.         }
  3592.         }
  3593.         obstack_1grow (¯os, c);
  3594.     }
  3595.     obstack_1grow (¯os, '\n');
  3596.     obstack_1grow (¯os, '\0');
  3597.     last_buffer_limit = buffer_limit;
  3598.     last_count_lines = count_lines;
  3599.     last_input_line_pointer = input_line_pointer;
  3600.     buffer_limit = obstack_next_free (¯os) - 1;
  3601.     buffer = obstack_finish (¯os);
  3602.     count_lines = FALSE;
  3603.     /*
  3604.     printf("expanded macro: %s", buffer + 1);
  3605.     */
  3606.     parse_a_buffer(buffer + 1);
  3607.     obstack_free (¯os, buffer);
  3608.     for(index = 9; index >= 0; index --)
  3609.         if(arguments[index])
  3610.         obstack_free(¯os, arguments[index]);
  3611.     buffer_limit = last_buffer_limit;
  3612.     count_lines = last_count_lines;
  3613.     input_line_pointer = last_input_line_pointer;
  3614.     macro_depth--;
  3615. }
  3616.  
  3617. /*
  3618.  * s_dump() implements the pseudo op:
  3619.  *    .dump filename
  3620.  * that does a quick binary dump of symbol tables.
  3621.  */
  3622. static
  3623. void
  3624. s_dump(
  3625. int value)
  3626. {
  3627.     char *filename;
  3628.     int length;
  3629.     static char null_string[] = "";
  3630.  
  3631.     if((filename = demand_copy_string(&length))){
  3632.         demand_empty_rest_of_line();
  3633.         if((dump_fp = fopen(filename, "w+"))){
  3634.         hash_apply(ma_hash, write_macro);
  3635.         fwrite(null_string, 1, 1, dump_fp);
  3636.         hash_apply(sy_hash, write_symbol);
  3637.         fwrite(null_string, 1, 1, dump_fp);
  3638.         fclose(dump_fp);
  3639.         }
  3640.         else
  3641.         as_warn("couldn't write to dump file: \"%s\"", filename);
  3642.     }
  3643. }
  3644.  
  3645. /*
  3646.  * write_macro() used by hash_apply indirectly through s_dump() to write one
  3647.  * macro.
  3648.  */
  3649. static
  3650. char *
  3651. write_macro(
  3652. char *string,
  3653. char *value)
  3654. {
  3655.     know(string);
  3656.     know(value);
  3657.     know(strlen(string));
  3658.     fwrite(string, (strlen(string) + 1), 1, dump_fp);
  3659.     fwrite(value, (strlen(value) + 1), 1, dump_fp);
  3660.     return(NULL);
  3661. }
  3662.  
  3663. /*
  3664.  * write_symbol() used by hash_apply indirectly through s_dump() to write one
  3665.  * N_ABS symbol and its value.
  3666.  */
  3667. static
  3668. char *
  3669. write_symbol(
  3670. char *string,
  3671. char *value)
  3672. {
  3673.     symbolS *symbolP;
  3674.  
  3675.         symbolP = (symbolS *)value;
  3676.     know(symbolP);
  3677.     if(((symbolP->sy_type) & N_TYPE) == N_ABS){
  3678.         know(string);
  3679.         know(strlen(string));
  3680.         fwrite(string, (strlen(string) + 1), 1, dump_fp);
  3681.         fwrite(&(symbolP -> sy_value), 4, 1, dump_fp);
  3682.     }
  3683.     return(NULL);
  3684. }
  3685.  
  3686. /*
  3687.  * s_load() implements the pseudo op:
  3688.  *    .load filename
  3689.  * that does a quick binary load of symbol tables.
  3690.  */
  3691. static
  3692. void
  3693. s_load(
  3694. int value)
  3695. {
  3696.     char *char_pointer;
  3697.     char *filename;
  3698.     int length;
  3699.     char the_char;
  3700.     symbolS    *the_symbol;
  3701.     symbolS    *temp_symbol_lastP;
  3702.     static symbolS *dump_symbol_lastP;
  3703.  
  3704.     if((filename = demand_copy_string(&length))){
  3705.         demand_empty_rest_of_line();
  3706.         if((dump_fp = fopen(filename, "r+"))){
  3707.         do{
  3708.             do{
  3709.             the_char = getc(dump_fp);
  3710.             obstack_1grow(¯os, the_char);
  3711.             }while(the_char);
  3712.             char_pointer = obstack_finish (¯os);
  3713.             if(!(*char_pointer))
  3714.             break;
  3715.             do{
  3716.             the_char = getc(dump_fp);
  3717.             obstack_1grow(¯os, the_char);
  3718.             }while(the_char);
  3719.             if(*hash_insert(ma_hash, char_pointer,
  3720.                     obstack_finish(¯os)))
  3721.             as_warn("a macro named \"%s\" encountered in a .load "
  3722.                     "is already defined", char_pointer);
  3723.         }while(1);
  3724.             /*
  3725.          * We don't want to link in symbols that were loaded so they
  3726.          * don't go out in the object file.  Instead these symbols
  3727.          * should go out in the object file that did the .dump .
  3728.          */
  3729.         temp_symbol_lastP = symbol_lastP;
  3730.         symbol_lastP = dump_symbol_lastP;
  3731.         do{
  3732.             do{
  3733.             the_char = getc(dump_fp);
  3734.             obstack_1grow(¯os, the_char);
  3735.             }while(the_char);
  3736.             char_pointer = obstack_base(¯os);
  3737.             obstack_next_free(¯os) = char_pointer;
  3738.             if(!(*char_pointer))
  3739.             break;
  3740.             the_symbol = symbol_find_or_make(char_pointer);
  3741.             the_symbol->sy_type = N_ABS;
  3742.             char_pointer = (char *)&the_symbol->sy_value;
  3743.             *char_pointer++ = getc(dump_fp);
  3744.             *char_pointer++ = getc(dump_fp);
  3745.             *char_pointer++ = getc(dump_fp);
  3746.             *char_pointer++ = getc(dump_fp);
  3747.             the_symbol->sy_frag = &zero_address_frag;
  3748.         }while(1);
  3749.         dump_symbol_lastP = symbol_lastP;
  3750.         symbol_lastP = temp_symbol_lastP;
  3751.         fclose(dump_fp);
  3752.         }
  3753.         else
  3754.         as_fatal("Couldn't find the dump file: \"%s\"", filename);
  3755.     }
  3756. }
  3757.  
  3758. #ifdef SPARC
  3759.  
  3760. /* Special stuff to allow assembly of Sun assembler sources
  3761.    This unfortunatley needs to be here instead of sparc.c because it
  3762.    uses the hash tables defined here.
  3763.    see also sparc.c for pseudo_table entries 
  3764. */
  3765.  
  3766. /* Handle the SUN sparc assembler .seg directive. .seg should only occur with
  3767.    either a ".text" or ".data" argument. Call .text or .data accordingly
  3768. */
  3769. void
  3770. s_seg (ignore)
  3771.      int ignore;
  3772. {
  3773.   pseudo_typeS *ps_t;
  3774.   char s[32];
  3775.  
  3776.   printf("S_SEG\n");
  3777.  
  3778.   if (strncmp (input_line_pointer, "\"text\"", 6) == 0)
  3779.     {
  3780.       input_line_pointer += 6;
  3781.       /* relies on .text being first section */
  3782.       (void)s_builtin_section(builtin_sections);
  3783.       demand_empty_rest_of_line();
  3784.       return;
  3785.     }
  3786.   if (strncmp (input_line_pointer, "\"data\"", 6) == 0)
  3787.     {
  3788.       /* copy the argument */
  3789.       input_line_pointer++;
  3790.       strncpy(s, input_line_pointer, 4);
  3791.       input_line_pointer += 5;
  3792.       /* find the section table index for .data */
  3793.       ps_t = (pseudo_typeS *) hash_find(po_hash, s);
  3794.  
  3795.       if (ps_t == 0)
  3796.     as_bad ("invalid .seg argument");
  3797.  
  3798.       printf("INDEX %s, %d\n", s, ps_t->poc_val);
  3799.  
  3800.       s_builtin_section ((const struct builtin_section *)ps_t->poc_val);
  3801.       demand_empty_rest_of_line();
  3802.       return;
  3803.     }
  3804.   as_bad ("Unknown segment type");
  3805.   demand_empty_rest_of_line ();
  3806. }
  3807.  
  3808. #endif /* SPARC */
  3809.