12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012 |
- /* read.c - read a source file -
- Copyright (C) 1986,1987 Free Software Foundation, Inc.
- This file is part of GAS, the GNU Assembler.
- GAS is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 1, or (at your option)
- any later version.
- GAS is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with GAS; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
- #define MASK_CHAR (0xFF) /* If your chars aren't 8 bits, you will
- change this a bit. But then, GNU isn't
- spozed to run on your machine anyway.
- (RMS is so shortsighted sometimes.)
- */
- #define MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT (16)
- /* This is the largest known floating point */
- /* format (for now). It will grow when we */
- /* do 4361 style flonums. */
- /* Routines that read assembler source text to build spagetti in memory. */
- /* Another group of these functions is in the as-expr.c module */
- #include <ctype.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include "as.h"
- #include "read.h"
- #include "md.h"
- #include "hash.h"
- #include "obstack.h"
- #include "frags.h"
- #include "flonum.h"
- #include "struc-symbol.h"
- #include "expr.h"
- #include "symbols.h"
- #ifdef SPARC
- #include "sparc.h"
- #endif
- char * input_line_pointer; /* -> next char of source file to parse. */
- #if BITS_PER_CHAR != 8
- The following table is indexed by [ (char) ] and will break if
- a char does not have exactly 256 states (hopefully 0:255!) !
- #endif
- char /* used by is_... macros. our ctype[] */
- lex_type [256] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ABCDEFGHIJKLMNO */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* PQRSTUVWXYZ[\]^_ */
- 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, /* _!"#$%&'()*+,-./ */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0123456789:;<=>? */
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* @ABCDEFGHIJKLMNO */
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, /* PQRSTUVWXYZ[\]^_ */
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* `abcdefghijklmno */
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, /* pqrstuvwxyz{|}~. */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- };
- /*
- * In: a character.
- * Out: TRUE if this character ends a line.
- */
- #define _ (0)
- char is_end_of_line [256] = {
- _, _, _, _, _, _, _, _, _, _,99, _, _, _, _, _, /* @abcdefghijklmno */
- _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
- _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
- _, _, _, _, _, _, _, _, _, _, _,99, _, _, _, _, /* 0123456789:;<=>? */
- _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
- _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
- _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
- _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
- _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
- _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
- _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
- _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
- _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ /* */
- };
- #undef _
- /* Functions private to this file. */
- void equals();
- void big_cons();
- void cons();
- static char* demand_copy_C_string();
- static char* demand_copy_string();
- void demand_empty_rest_of_line();
- void float_cons();
- long int get_absolute_expression();
- static char get_absolute_expression_and_terminator();
- static segT get_known_segmented_expression();
- void ignore_rest_of_line();
- static int is_it_end_of_statement();
- static void pobegin();
- static void pseudo_set();
- static void stab();
- static void stringer();
- extern char line_comment_chars[];
- static char * buffer_limit; /* -> 1 + last char in buffer. */
- static char * bignum_low; /* Lowest char of bignum. */
- static char * bignum_limit; /* 1st illegal address of bignum. */
- static char * bignum_high; /* Highest char of bignum. */
- /* May point to (bignum_start-1). */
- /* Never >= bignum_limit. */
- static char *old_buffer = 0; /* JF a hack */
- static char *old_input;
- static char *old_limit;
- #ifndef WORKING_DOT_WORD
- struct broken_word *broken_words;
- int new_broken_words = 0;
- #endif
- static void grow_bignum ();
- static int next_char_of_string ();
- void
- read_begin()
- {
- pobegin();
- obstack_begin( ¬es, 5000 );
- #define BIGNUM_BEGIN_SIZE (16)
- bignum_low = xmalloc((long)BIGNUM_BEGIN_SIZE);
- bignum_limit = bignum_low + BIGNUM_BEGIN_SIZE;
- }
- /* set up pseudo-op tables */
- static struct hash_control *
- po_hash = NULL; /* use before set up: NULL-> address error */
- void s_abort(), s_align(), s_comm(), s_data();
- void s_desc(), s_even(), s_file(), s_fill();
- void s_gdbbeg(), s_gdbblock(), s_gdbend(), s_gdbsym();
- void s_globl(), s_lcomm(), s_line(), s_lsym();
- void s_org(), s_set(), s_space(), s_text();
- void s_gdbline(), s_gdblinetab();
- void stringer();
- void cons();
- void float_cons();
- void big_cons();
- void stab();
- static pseudo_typeS
- potable[] =
- {
- { "abort", s_abort, 0 },
- { "align", s_align, 0 },
- { "ascii", stringer, 0 },
- { "asciz", stringer, 1 },
- { "byte", cons, 1 },
- { "comm", s_comm, 0 },
- { "data", s_data, 0 },
- { "desc", s_desc, 0 },
- { "double", float_cons, 'd' },
- { "file", s_file, 0 },
- { "fill", s_fill, 0 },
- { "float", float_cons, 'f' },
- { "gdbbeg", s_gdbbeg, 0 },
- { "gdbblock", s_gdbblock, 0 },
- { "gdbend", s_gdbend, 0 },
- { "gdbsym", s_gdbsym, 0 },
- { "gdbline", s_gdbline, 0 },
- { "gdblinetab",s_gdblinetab, 0 },
- { "globl", s_globl, 0 },
- { "int", cons, 4 },
- { "lcomm", s_lcomm, 0 },
- { "line", s_line, 0 },
- { "long", cons, 4 },
- { "lsym", s_lsym, 0 },
- { "octa", big_cons, 16 },
- { "org", s_org, 0 },
- { "quad", big_cons, 8 },
- { "set", s_set, 0 },
- { "short", cons, 2 },
- { "single", float_cons, 'f' },
- { "space", s_space, 0 },
- { "stabd", stab, 'd' },
- { "stabn", stab, 'n' },
- { "stabs", stab, 's' },
- { "text", s_text, 0 },
- #ifndef SPARC
- { "word", cons, 2 },
- #endif
- { NULL} /* end sentinel */
- };
- static void
- pobegin()
- {
- char * errtxt; /* error text */
- pseudo_typeS * pop;
- po_hash = hash_new();
- errtxt = ""; /* OK so far */
- for (pop=potable; pop->poc_name && !*errtxt; pop++)
- {
- errtxt = hash_insert (po_hash, pop->poc_name, (char *)pop);
- }
- for(pop=md_pseudo_table; pop->poc_name && !*errtxt; pop++)
- errtxt = hash_insert (po_hash, pop->poc_name, (char *)pop);
- if (*errtxt)
- {
- as_fatal ("error constructing pseudo-op table");
- }
- } /* pobegin() */
- /* read_a_source_file()
- *
- * File has already been opened, and will be closed by our caller.
- *
- * We read the file, putting things into a web that
- * represents what we have been reading.
- */
- void
- read_a_source_file (buffer)
- char * buffer; /* 1st character of each buffer of lines is here. */
- {
- register char c;
- register char * s; /* string of symbol, '\0' appended */
- register int temp;
- /* register struct frag * fragP; JF unused */ /* a frag we just made */
- pseudo_typeS *pop;
- void gdb_block_beg();
- void gdb_block_position();
- void gdb_block_end();
- void gdb_symbols_fixup();
- subseg_new (SEG_TEXT, 0);
- while ( buffer_limit = input_scrub_next_buffer (&buffer) )
- { /* We have another line to parse. */
- know( buffer_limit [-1] == '\n' ); /* Must have a sentinel. */
- input_line_pointer = buffer;
- contin: /* JF this goto is my fault I admit it. Someone brave please re-write
- the whole input section here? Pleeze??? */
- while ( input_line_pointer < buffer_limit )
- { /* We have more of this buffer to parse. */
- /*
- * We now have input_line_pointer -> 1st char of next line.
- * If input_line_pointer [-1] == '\n' then we just
- * scanned another line: so bump line counters.
- */
- if (input_line_pointer [-1] == '\n')
- {
- bump_line_counters ();
- }
- /*
- * We are at the begining of a line, or similar place.
- * We expect a well-formed assembler statement.
- * A "symbol-name:" is a statement.
- *
- * Depending on what compiler is used, the order of these tests
- * may vary to catch most common case 1st.
- * Each test is independent of all other tests at the (top) level.
- * PLEASE make a compiler that doesn't use this assembler.
- * It is crufty to waste a compiler's time encoding things for this
- * assembler, which then wastes more time decoding it.
- * (And communicating via (linear) files is silly!
- * If you must pass stuff, please pass a tree!)
- */
- if ( (c= * input_line_pointer ++) == '\t' || c == ' ' || c=='\f')
- {
- c = * input_line_pointer ++;
- }
- know( c != ' ' ); /* No further leading whitespace. */
- /*
- * C is the 1st significant character.
- * Input_line_pointer points after that character.
- */
- if ( is_name_beginner(c) )
- { /* want user-defined label or pseudo/opcode */
- s = -- input_line_pointer;
- c = get_symbol_end(); /* name's delimiter */
- /*
- * C is character after symbol.
- * That character's place in the input line is now '\0'.
- * S points to the beginning of the symbol.
- * [In case of pseudo-op, s -> '.'.]
- * Input_line_pointer -> '\0' where c was.
- */
- if ( c == ':' )
- {
- colon(s); /* user-defined label */
- * input_line_pointer ++ = ':'; /* Put ':' back for error messages' sake. */
- /* Input_line_pointer -> after ':'. */
- SKIP_WHITESPACE();
- }
- else if(c=='=' || input_line_pointer[1]=='=') /* JF deal with FOO=BAR */
- {
- equals(s);
- demand_empty_rest_of_line();
- }
- else
- { /* expect pseudo-op or machine instruction */
- if ( *s=='.' )
- {
- /*
- * PSEUDO - OP.
- *
- * WARNING: c has next char, which may be end-of-line.
- * We lookup the pseudo-op table with s+1 because we
- * already know that the pseudo-op begins with a '.'.
- */
- pop= (pseudo_typeS *) hash_find (po_hash, s+1);
- /* Put it back for error messages etc. */
- * input_line_pointer = c;
- /* The following skip of whitespace is compulsory. */
- /* A well shaped space is sometimes all that seperates keyword from operands. */
- if ( c == ' ' || c == '\t' )
- { /* Skip seperator after keyword. */
- input_line_pointer ++;
- }
- /*
- * Input_line is restored.
- * Input_line_pointer -> 1st non-blank char
- * after pseudo-operation.
- */
- if(!pop) {
- as_warn("Unknown pseudo-op");
- ignore_rest_of_line();
- break;
- }
- else
- (*pop->poc_handler)(pop->poc_val);
- }
- else
- { /* machine instruction */
- /* WARNING: c has char, which may be end-of-line. */
- /* Also: input_line_pointer -> `\0` where c was. */
- * input_line_pointer = c;
- while ( ! is_end_of_line [* input_line_pointer] )
- {
- input_line_pointer ++;
- }
- c = * input_line_pointer;
- * input_line_pointer = '\0';
- md_assemble (s); /* Assemble 1 instruction. */
- * input_line_pointer ++ = c;
- /* We resume loop AFTER the end-of-line from this instruction */
- } /* if (*s=='.') */
- } /* if c==':' */
- continue;
- } /* if (is_name_beginner(c) */
- if ( is_end_of_line [c] )
- { /* empty statement */
- continue;
- }
- if ( isdigit(c) )
- { /* local label ("4:") */
- temp = c - '0';
- #ifdef SUN_ASM_SYNTAX
- if( *input_line_pointer=='$')
- input_line_pointer++;
- #endif
- if ( * input_line_pointer ++ == ':' )
- {
- local_colon (temp);
- }
- else
- {
- as_warn( "Spurious digit %d.", temp);
- input_line_pointer -- ;
- ignore_rest_of_line();
- }
- continue;
- }
- if(c && index(line_comment_chars,c)) { /* Its a comment. Better say APP or NO_APP */
- char *ends;
- char *strstr();
- char *new_buf;
- char *new_tmp;
- int new_length;
- char *tmp_buf = 0;
- extern char *scrub_string,*scrub_last_string;
- int scrub_from_string();
- void scrub_to_string();
- bump_line_counters();
- s=input_line_pointer;
- if(strncmp(s,"APP\n",4))
- continue; /* We ignore it */
- s+=4;
- ends=strstr(s,"#NO_APP\n");
- if(!ends) {
- int tmp_len;
- int num;
- /* The end of the #APP wasn't in this buffer. We
- keep reading in buffers until we find the #NO_APP
- that goes with this #APP There is one. The specs
- guarentee it. . .*/
- tmp_len=buffer_limit-s;
- tmp_buf=xmalloc(tmp_len);
- bcopy(s,tmp_buf,tmp_len);
- do {
- new_tmp = input_scrub_next_buffer(&buffer);
- if(!new_tmp)
- break;
- else
- buffer_limit = new_tmp;
- input_line_pointer = buffer;
- ends = strstr(buffer,"#NO_APP\n");
- if(ends)
- num=ends-buffer;
- else
- num=buffer_limit-buffer;
- tmp_buf=xrealloc(tmp_buf,tmp_len+num);
- bcopy(buffer,tmp_buf+tmp_len,num);
- tmp_len+=num;
- } while(!ends);
- input_line_pointer= ends ? ends+8 : NULL;
- s=tmp_buf;
- ends=s+tmp_len;
- } else {
- input_line_pointer=ends+8;
- }
- new_buf=xmalloc(100);
- new_length=100;
- new_tmp=new_buf;
- scrub_string=s;
- scrub_last_string = ends;
- for(;;) {
- int ch;
- ch=do_scrub_next_char(scrub_from_string,scrub_to_string);
- if(ch==EOF) break;
- *new_tmp++=ch;
- if(new_tmp==new_buf+new_length) {
- new_buf=xrealloc(new_buf,new_length+100);
- new_tmp=new_buf+new_length;
- new_length+=100;
- }
- }
- if(tmp_buf)
- free(tmp_buf);
- old_buffer=buffer;
- old_input=input_line_pointer;
- old_limit=buffer_limit;
- buffer=new_buf;
- input_line_pointer=new_buf;
- buffer_limit=new_tmp;
- continue;
- }
- as_warn("Junk character %d.",c);
- ignore_rest_of_line();
- } /* while (input_line_pointer<buffer_limit )*/
- if(old_buffer) {
- bump_line_counters();
- if(old_input == 0)
- return;
- buffer=old_buffer;
- input_line_pointer=old_input;
- buffer_limit=old_limit;
- old_buffer = 0;
- goto contin;
- }
- } /* while (more bufrers to scan) */
- } /* read_a_source_file() */
- void
- s_abort()
- {
- as_fatal(".abort detected. Abandoning ship.");
- }
- void
- s_align()
- {
- register int temp;
- register long int temp_fill;
- temp = get_absolute_expression ();
- #define MAX_ALIGNMENT (15)
- if ( temp > MAX_ALIGNMENT )
- as_warn("Alignment too large: %d. assumed.", temp = MAX_ALIGNMENT);
- else if ( temp < 0 ) {
- as_warn("Alignment negative. 0 assumed.");
- temp = 0;
- }
- if ( *input_line_pointer == ',' ) {
- input_line_pointer ++;
- temp_fill = get_absolute_expression ();
- } else
- temp_fill = 0;
- /* Only make a frag if we HAVE to. . . */
- if ( temp && ! need_pass_2 )
- frag_align (temp, (int)temp_fill);
- demand_empty_rest_of_line();
- }
- void
- s_comm()
- {
- register char *name;
- register char c;
- register char *p;
- register int temp;
- register symbolS * symbolP;
- name = input_line_pointer;
- c = get_symbol_end();
- /* just after name is now '\0' */
- p = input_line_pointer;
- *p = c;
- SKIP_WHITESPACE();
- if ( * input_line_pointer != ',' ) {
- as_warn("Expected comma after symbol-name");
- ignore_rest_of_line();
- return;
- }
- input_line_pointer ++; /* skip ',' */
- if ( (temp = get_absolute_expression ()) < 0 ) {
- as_warn(".COMMon length (%d.) <0! Ignored.", temp);
- ignore_rest_of_line();
- return;
- }
- *p = 0;
- symbolP = symbol_find_or_make (name);
- *p = c;
- if ( (symbolP -> sy_type & N_TYPE) != N_UNDF ||
- symbolP -> sy_other != 0 || symbolP -> sy_desc != 0) {
- as_warn( "Ignoring attempt to re-define symbol");
- ignore_rest_of_line();
- return;
- }
- if (symbolP -> sy_value) {
- if (symbolP -> sy_value != temp)
- as_warn( "Length of .comm \"%s\" is already %d. Not changed to %d.",
- symbolP -> sy_name, symbolP -> sy_value, temp);
- } else {
- symbolP -> sy_value = temp;
- symbolP -> sy_type |= N_EXT;
- }
- know( symbolP -> sy_frag == &zero_address_frag );
- demand_empty_rest_of_line();
- }
- void
- s_data()
- {
- register int temp;
- temp = get_absolute_expression ();
- subseg_new (SEG_DATA, (subsegT)temp);
- demand_empty_rest_of_line();
- }
- void
- s_desc()
- {
- register char *name;
- register char c;
- register char *p;
- register symbolS * symbolP;
- register int temp;
- /*
- * Frob invented at RMS' request. Set the n_desc of a symbol.
- */
- name = input_line_pointer;
- c = get_symbol_end();
- p = input_line_pointer;
- symbolP = symbol_table_lookup (name);
- * p = c;
- SKIP_WHITESPACE();
- if ( * input_line_pointer != ',' ) {
- *p = 0;
- as_warn("Expected comma after name \"%s\"", name);
- *p = c;
- ignore_rest_of_line();
- } else {
- input_line_pointer ++;
- temp = get_absolute_expression ();
- *p = 0;
- symbolP = symbol_find_or_make (name);
- *p = c;
- symbolP -> sy_desc = temp;
- }
- demand_empty_rest_of_line();
- }
- void
- s_file()
- {
- register char *s;
- int length;
- /* Some assemblers tolerate immediately following '"' */
- if ( s = demand_copy_string( & length ) ) {
- new_logical_line (s, -1);
- demand_empty_rest_of_line();
- }
- }
- void
- s_fill()
- {
- long int temp_repeat;
- long int temp_size;
- register long int temp_fill;
- char *p;
- if ( get_absolute_expression_and_terminator(& temp_repeat) != ',' ) {
- input_line_pointer --; /* Backup over what was not a ','. */
- as_warn("Expect comma after rep-size in .fill");
- ignore_rest_of_line();
- return;
- }
- if ( get_absolute_expression_and_terminator( & temp_size) != ',' ) {
- input_line_pointer --; /* Backup over what was not a ','. */
- as_warn("Expected comma after size in .fill");
- ignore_rest_of_line();
- return;
- }
- /*
- * This is to be compatible with BSD 4.2 AS, not for any rational reason.
- */
- #define BSD_FILL_SIZE_CROCK_8 (8)
- if ( temp_size > BSD_FILL_SIZE_CROCK_8 ) {
- as_warn(".fill size clamped to %d.", BSD_FILL_SIZE_CROCK_8);
- temp_size = BSD_FILL_SIZE_CROCK_8 ;
- } if ( temp_size < 0 ) {
- as_warn("Size negative: .fill ignored.");
- temp_size = 0;
- } else if ( temp_repeat <= 0 ) {
- as_warn("Repeat < 0, .fill ignored");
- temp_size = 0;
- }
- temp_fill = get_absolute_expression ();
- if ( temp_size && !need_pass_2 ) {
- p = frag_var (rs_fill, (int)temp_size, (int)temp_size, (relax_substateT)0, (symbolS *)0, temp_repeat, (char *)0);
- bzero (p, (int)temp_size);
- /*
- * The magic number BSD_FILL_SIZE_CROCK_4 is from BSD 4.2 VAX flavoured AS.
- * The following bizzare behaviour is to be compatible with above.
- * I guess they tried to take up to 8 bytes from a 4-byte expression
- * and they forgot to sign extend. Un*x Sux.
- */
- #define BSD_FILL_SIZE_CROCK_4 (4)
- md_number_to_chars (p, temp_fill, temp_size > BSD_FILL_SIZE_CROCK_4 ? BSD_FILL_SIZE_CROCK_4 : (int)temp_size);
- /*
- * Note: .fill (),0 emits no frag (since we are asked to .fill 0 bytes)
- * but emits no error message because it seems a legal thing to do.
- * It is a degenerate case of .fill but could be emitted by a compiler.
- */
- }
- demand_empty_rest_of_line();
- }
- void
- s_gdbbeg()
- {
- register int temp;
- temp = get_absolute_expression ();
- if (temp < 0)
- as_warn( "Block number <0. Ignored." );
- else if (flagseen ['G'])
- gdb_block_beg ( (long int) temp, frag_now, (long int)(obstack_next_free(& frags) - frag_now -> fr_literal));
- demand_empty_rest_of_line ();
- }
- void
- s_gdbblock()
- {
- register int position;
- int temp;
- if (get_absolute_expression_and_terminator (&temp) != ',') {
- as_warn( "expected comma before position in .gdbblock");
- --input_line_pointer;
- ignore_rest_of_line ();
- return;
- }
- position = get_absolute_expression ();
- if (flagseen ['G'])
- gdb_block_position ((long int) temp, (long int) position);
- demand_empty_rest_of_line ();
- }
- void
- s_gdbend()
- {
- register int temp;
- temp = get_absolute_expression ();
- if (temp < 0)
- as_warn( "Block number <0. Ignored." );
- else if (flagseen ['G'])
- gdb_block_end ( (long int) temp, frag_now, (long int)(obstack_next_free(& frags) - frag_now -> fr_literal));
- demand_empty_rest_of_line ();
- }
- void
- s_gdbsym()
- {
- register char *name,
- *p;
- register char c;
- register symbolS * symbolP;
- register int temp;
- name = input_line_pointer;
- c = get_symbol_end();
- p = input_line_pointer;
- symbolP = symbol_find_or_make (name);
- *p = c;
- SKIP_WHITESPACE();
- if ( * input_line_pointer != ',' ) {
- as_warn("Expected comma after name");
- ignore_rest_of_line();
- return;
- }
- input_line_pointer ++;
- if ( (temp = get_absolute_expression ()) < 0 ) {
- as_warn("Bad GDB symbol file offset (%d.) <0! Ignored.", temp);
- ignore_rest_of_line();
- return;
- }
- if (flagseen ['G'])
- gdb_symbols_fixup (symbolP, (long int)temp);
- demand_empty_rest_of_line ();
- }
- void
- s_gdbline()
- {
- int file_number,
- lineno;
- if(get_absolute_expression_and_terminator(&file_number) != ',') {
- as_warn("expected comman after filenum in .gdbline");
- ignore_rest_of_line();
- return;
- }
- lineno=get_absolute_expression();
- if(flagseen['G'])
- gdb_line(file_number,lineno);
- demand_empty_rest_of_line();
- }
- void
- s_gdblinetab()
- {
- int file_number,
- offset;
- if(get_absolute_expression_and_terminator(&file_number) != ',') {
- as_warn("expected comman after filenum in .gdblinetab");
- ignore_rest_of_line();
- return;
- }
- offset=get_absolute_expression();
- if(flagseen['G'])
- gdb_line_tab(file_number,offset);
- demand_empty_rest_of_line();
- }
-
- void
- s_globl()
- {
- register char *name;
- register int c;
- register symbolS * symbolP;
- do {
- name = input_line_pointer;
- c = get_symbol_end();
- symbolP = symbol_find_or_make (name);
- * input_line_pointer = c;
- SKIP_WHITESPACE();
- symbolP -> sy_type |= N_EXT;
- if(c==',') {
- input_line_pointer++;
- SKIP_WHITESPACE();
- if(*input_line_pointer=='\n')
- c='\n';
- }
- } while(c==',');
- demand_empty_rest_of_line();
- }
- void
- s_lcomm()
- {
- register char *name;
- register char c;
- register char *p;
- register int temp;
- register symbolS * symbolP;
- name = input_line_pointer;
- c = get_symbol_end();
- p = input_line_pointer;
- *p = c;
- SKIP_WHITESPACE();
- if ( * input_line_pointer != ',' ) {
- as_warn("Expected comma after name");
- ignore_rest_of_line();
- return;
- }
- input_line_pointer ++;
- if ( (temp = get_absolute_expression ()) < 0 ) {
- as_warn("BSS length (%d.) <0! Ignored.", temp);
- ignore_rest_of_line();
- return;
- }
- *p = 0;
- symbolP = symbol_find_or_make (name);
- *p = c;
- if ( symbolP -> sy_other == 0
- && symbolP -> sy_desc == 0
- && ( ( symbolP -> sy_type == N_BSS
- && symbolP -> sy_value == local_bss_counter)
- || ( (symbolP -> sy_type & N_TYPE) == N_UNDF
- && symbolP -> sy_value == 0))) {
- symbolP -> sy_value = local_bss_counter;
- symbolP -> sy_type = N_BSS;
- symbolP -> sy_frag = & bss_address_frag;
- local_bss_counter += temp;
- } else
- as_warn( "Ignoring attempt to re-define symbol from %d. to %d.",
- symbolP -> sy_value, local_bss_counter );
- demand_empty_rest_of_line();
- }
- void
- s_line()
- {
- /* Assume delimiter is part of expression. */
- /* BSD4.2 as fails with delightful bug, so we */
- /* are not being incompatible here. */
- new_logical_line ((char *)NULL, (int)(get_absolute_expression ()));
- demand_empty_rest_of_line();
- }
- void
- s_long()
- {
- cons(4);
- }
- void
- s_int()
- {
- cons(4);
- }
- void
- s_lsym()
- {
- register char *name;
- register char c;
- register char *p;
- register segT segment;
- expressionS exp;
- register symbolS *symbolP;
- /* we permit ANY expression: BSD4.2 demands constants */
- name = input_line_pointer;
- c = get_symbol_end();
- p = input_line_pointer;
- *p = c;
- SKIP_WHITESPACE();
- if ( * input_line_pointer != ',' ) {
- *p = 0;
- as_warn("Expected comma after name \"%s\"", name);
- *p = c;
- ignore_rest_of_line();
- return;
- }
- input_line_pointer ++;
- segment = expression (& exp);
- if ( segment != SEG_ABSOLUTE && segment != SEG_DATA &&
- segment != SEG_TEXT && segment != SEG_BSS) {
- as_warn("Bad expression: %s", seg_name [(int)segment]);
- ignore_rest_of_line();
- return;
- }
- know( segment == SEG_ABSOLUTE || segment == SEG_DATA || segment == SEG_TEXT || segment == SEG_BSS );
- *p = 0;
- symbolP = symbol_new (name,(unsigned char)(seg_N_TYPE [(int) segment]),
- 0, 0, (valueT)(exp . X_add_number), & zero_address_frag);
- *p = c;
- demand_empty_rest_of_line();
- }
- void
- s_org()
- {
- register segT segment;
- expressionS exp;
- register long int temp_fill;
- register char *p;
- /*
- * Don't believe the documentation of BSD 4.2 AS.
- * There is no such thing as a sub-segment-relative origin.
- * Any absolute origin is given a warning, then assumed to be segment-relative.
- * Any segmented origin expression ("foo+42") had better be in the right
- * segment or the .org is ignored.
- *
- * BSD 4.2 AS warns if you try to .org backwards. We cannot because we
- * never know sub-segment sizes when we are reading code.
- * BSD will crash trying to emit -ve numbers of filler bytes in certain
- * .orgs. We don't crash, but see as-write for that code.
- */
- /*
- * Don't make frag if need_pass_2==TRUE.
- */
- segment = get_known_segmented_expression(& exp);
- if ( *input_line_pointer == ',' ) {
- input_line_pointer ++;
- temp_fill = get_absolute_expression ();
- } else
- temp_fill = 0;
- if ( ! need_pass_2 ) {
- if (segment != now_seg && segment != SEG_ABSOLUTE)
- as_warn("Illegal segment \"%s\". Segment \"%s\" assumed.",
- seg_name [(int) segment], seg_name [(int) now_seg]);
- p = frag_var (rs_org, 1, 1, (relax_substateT)0, exp . X_add_symbol,
- exp . X_add_number, (char *)0);
- * p = temp_fill;
- } /* if (ok to make frag) */
- demand_empty_rest_of_line();
- }
- void
- s_set()
- {
- register char *name;
- register char delim;
- register char *end_name;
- register symbolS *symbolP;
- /*
- * Especial apologies for the random logic:
- * this just grew, and could be parsed much more simply!
- * Dean in haste.
- */
- name = input_line_pointer;
- delim = get_symbol_end();
- end_name = input_line_pointer;
- *end_name = delim;
- SKIP_WHITESPACE();
- if ( * input_line_pointer != ',' ) {
- *end_name = 0;
- as_warn("Expected comma after name \"%s\"", name);
- *end_name = delim;
- ignore_rest_of_line();
- return;
- }
- input_line_pointer ++;
- *end_name = 0;
- if(name[0]=='.' && name[1]=='\0') {
- /* Turn '. = mumble' into a .org mumble */
- register segT segment;
- expressionS exp;
- register char *ptr;
- segment = get_known_segmented_expression(& exp);
- if ( ! need_pass_2 ) {
- if (segment != now_seg && segment != SEG_ABSOLUTE)
- as_warn("Illegal segment \"%s\". Segment \"%s\" assumed.",
- seg_name [(int) segment], seg_name [(int) now_seg]);
- ptr = frag_var (rs_org, 1, 1, (relax_substateT)0, exp.X_add_symbol,
- exp.X_add_number, (char *)0);
- *ptr= 0;
- } /* if (ok to make frag) */
- *end_name = delim;
- return;
- }
- symbolP = symbol_find_or_make (name);
- *end_name = delim;
- pseudo_set (symbolP);
- demand_empty_rest_of_line ();
- }
- void
- s_space()
- {
- long int temp_repeat;
- register long int temp_fill;
- register char *p;
- /* Just like .fill, but temp_size = 1 */
- if ( get_absolute_expression_and_terminator( & temp_repeat) == ',' ) {
- temp_fill = get_absolute_expression ();
- } else {
- input_line_pointer --; /* Backup over what was not a ','. */
- temp_fill = 0;
- }
- if ( temp_repeat <= 0 ) {
- as_warn("Repeat < 0, .space ignored");
- ignore_rest_of_line();
- return;
- }
- if ( ! need_pass_2 ) {
- p = frag_var (rs_fill, 1, 1, (relax_substateT)0, (symbolS *)0,
- temp_repeat, (char *)0);
- * p = temp_fill;
- }
- demand_empty_rest_of_line();
- }
- void
- s_text()
- {
- register int temp;
- temp = get_absolute_expression ();
- subseg_new (SEG_TEXT, (subsegT)temp);
- demand_empty_rest_of_line();
- }
- /*( JF was static, but can't be if machine dependent pseudo-ops are to use it */
- void
- demand_empty_rest_of_line()
- {
- SKIP_WHITESPACE();
- if ( is_end_of_line [* input_line_pointer] )
- {
- input_line_pointer ++;
- }
- else
- {
- ignore_rest_of_line();
- }
- /* Return having already swallowed end-of-line. */
- } /* Return pointing just after end-of-line. */
- void
- ignore_rest_of_line() /* For suspect lines: gives warning. */
- {
- if ( ! is_end_of_line [* input_line_pointer])
- {
- as_warn("Rest of line ignored. 1st junk character valued %d."
- , * input_line_pointer);
- while ( input_line_pointer < buffer_limit
- && ! is_end_of_line [* input_line_pointer] )
- {
- input_line_pointer ++;
- }
- }
- input_line_pointer ++; /* Return pointing just after end-of-line. */
- know( is_end_of_line [input_line_pointer [-1]] );
- }
- /*
- * stab()
- *
- * Handle .stabX directives, which used to be open-coded.
- * So much creeping featurism overloaded the semantics that we decided
- * to put all .stabX thinking in one place. Here.
- *
- * We try to make any .stabX directive legal. Other people's AS will often
- * do assembly-time consistency checks: eg assigning meaning to n_type bits
- * and "protecting" you from setting them to certain values. (They also zero
- * certain bits before emitting symbols. Tut tut.)
- *
- * If an expression is not absolute we either gripe or use the relocation
- * information. Other people's assemblers silently forget information they
- * don't need and invent information they need that you didn't supply.
- *
- * .stabX directives always make a symbol table entry. It may be junk if
- * the rest of your .stabX directive is malformed.
- */
- static void
- stab (what)
- int what;
- {
- register symbolS * symbolP;
- register char * string;
- int saved_type;
- int length;
- int goof; /* TRUE if we have aborted. */
- long int longint;
- /*
- * Enter with input_line_pointer pointing past .stabX and any following
- * whitespace.
- */
- goof = FALSE; /* JF who forgot this?? */
- if (what == 's') {
- string = demand_copy_C_string (& length);
- SKIP_WHITESPACE();
- if (* input_line_pointer == ',')
- input_line_pointer ++;
- else {
- as_warn( "I need a comma after symbol's name" );
- goof = TRUE;
- }
- } else
- string = "";
- /*
- * Input_line_pointer->after ','. String -> symbol name.
- */
- if (! goof) {
- symbolP = symbol_new (string, 0,0,0,0,(struct frag *)0);
- switch (what) {
- case 'd':
- symbolP->sy_name = NULL; /* .stabd feature. */
- symbolP->sy_value = obstack_next_free(& frags) - frag_now->fr_literal;
- symbolP->sy_frag = frag_now;
- break;
- case 'n':
- symbolP->sy_frag = &zero_address_frag;
- break;
- case 's':
- symbolP->sy_frag = & zero_address_frag;
- break;
- default:
- BAD_CASE( what );
- break;
- }
- if (get_absolute_expression_and_terminator (& longint) == ',')
- symbolP->sy_type = saved_type = longint;
- else {
- as_warn( "I want a comma after the n_type expression" );
- goof = TRUE;
- input_line_pointer --; /* Backup over a non-',' char. */
- }
- }
- if (! goof) {
- if (get_absolute_expression_and_terminator (& longint) == ',')
- symbolP->sy_other = longint;
- else {
- as_warn( "I want a comma after the n_other expression" );
- goof = TRUE;
- input_line_pointer --; /* Backup over a non-',' char. */
- }
- }
- if (! goof) {
- symbolP->sy_desc = get_absolute_expression ();
- if (what == 's' || what == 'n') {
- if (* input_line_pointer != ',') {
- as_warn( "I want a comma after the n_desc expression" );
- goof = TRUE;
- } else {
- input_line_pointer ++;
- }
- }
- }
- if ((! goof) && (what=='s' || what=='n')) {
- pseudo_set (symbolP);
- symbolP->sy_type = saved_type;
- }
- if (goof)
- ignore_rest_of_line ();
- else
- demand_empty_rest_of_line ();
- }
- /*
- * pseudo_set()
- *
- * In: Pointer to a symbol.
- * Input_line_pointer -> expression.
- *
- * Out: Input_line_pointer -> just after any whitespace after expression.
- * Tried to set symbol to value of expression.
- * Will change sy_type, sy_value, sy_frag;
- * May set need_pass_2 == TRUE.
- */
- static void
- pseudo_set (symbolP)
- symbolS * symbolP;
- {
- expressionS exp;
- register segT segment;
- know( symbolP ); /* NULL pointer is logic error. */
- if ((segment = expression( & exp )) == SEG_NONE)
- {
- as_warn( "Missing expression: absolute 0 assumed" );
- exp . X_seg = SEG_ABSOLUTE;
- exp . X_add_number = 0;
- }
- switch (segment)
- {
- case SEG_BIG:
- as_warn( "%s number illegal. Absolute 0 assumed.",
- exp . X_add_number > 0 ? "Bignum" : "Floating-Point" );
- symbolP -> sy_type = N_ABS;
- symbolP -> sy_value = 0;
- symbolP -> sy_frag = & zero_address_frag;
- break;
- case SEG_NONE:
- as_warn("No expression: Using absolute 0");
- symbolP -> sy_type = N_ABS;
- symbolP -> sy_value = 0;
- symbolP -> sy_frag = & zero_address_frag;
- break;
- case SEG_DIFFERENCE:
- if (exp.X_add_symbol && exp.X_subtract_symbol
- && (exp.X_add_symbol->sy_type & N_TYPE)
- == (exp.X_subtract_symbol->sy_type & N_TYPE))
- exp.X_add_number+=exp.X_add_symbol->sy_value - exp.X_subtract_symbol->sy_value;
- else
- as_warn( "Complex expression. Absolute segment assumed." );
- case SEG_ABSOLUTE:
- symbolP -> sy_type = N_ABS;
- symbolP -> sy_value = exp . X_add_number;
- symbolP -> sy_frag = & zero_address_frag;
- break;
-
- case SEG_DATA:
- case SEG_TEXT:
- case SEG_BSS:
- symbolP -> sy_type = seg_N_TYPE [(int) segment];
- symbolP -> sy_value= exp . X_add_number + exp . X_add_symbol -> sy_value;
- symbolP -> sy_frag = exp . X_add_symbol -> sy_frag;
- break;
-
- case SEG_PASS1: /* Not an error. Just try another pass. */
- symbolP->sy_forward=exp.X_add_symbol;
- as_warn("Unknown expression");
- know( need_pass_2 == TRUE );
- break;
-
- case SEG_UNKNOWN:
- symbolP->sy_forward=exp.X_add_symbol;
- /* as_warn("unknown symbol"); */
- /* need_pass_2 = TRUE; */
- break;
-
- default:
- BAD_CASE( segment );
- break;
- }
- }
- /*
- * cons()
- *
- * CONStruct more frag of .bytes, or .words etc.
- * Should need_pass_2 be TRUE then emit no frag(s).
- * This understands EXPRESSIONS, as opposed to big_cons().
- *
- * Bug (?)
- *
- * This has a split personality. We use expression() to read the
- * value. We can detect if the value won't fit in a byte or word.
- * But we can't detect if expression() discarded significant digits
- * in the case of a long. Not worth the crocks required to fix it.
- */
- void
- cons(nbytes) /* worker to do .byte etc statements */
- /* clobbers input_line_pointer, checks */
- /* end-of-line. */
- register int nbytes; /* 1=.byte, 2=.word, 4=.long */
- {
- register char c;
- register long int mask; /* High-order bits we will left-truncate, */
- /* but includes sign bit also. */
- register long int get; /* what we get */
- register long int use; /* get after truncation. */
- register long int unmask; /* what bits we will store */
- register char * p;
- register segT segment;
- expressionS exp;
- #ifdef NS32K
- void fix_new_ns32k();
- #else
- void fix_new();
- #endif
- /*
- * Input_line_pointer -> 1st char after pseudo-op-code and could legally
- * be a end-of-line. (Or, less legally an eof - which we cope with.)
- */
- /* JF << of >= number of bits in the object is undefined. In particular
- SPARC (Sun 4) has problems */
- if(nbytes>=sizeof(long int))
- mask = 0;
- else
- mask = ~0 << (BITS_PER_CHAR * nbytes); /* Don't store these bits. */
- unmask = ~ mask; /* Do store these bits. */
- #ifdef NEVER
- "Do this mod if you want every overflow check to assume SIGNED 2's complement data.";
- mask = ~ (unmask >> 1); /* Includes sign bit now. */
- #endif
- /*
- * The following awkward logic is to parse ZERO or more expressions,
- * comma seperated. Recall an expression includes its leading &
- * trailing blanks. We fake a leading ',' if there is (supposed to
- * be) a 1st expression, and keep demanding 1 expression for each ','.
- */
- if (is_it_end_of_statement())
- {
- c = 0; /* Skip loop. */
- input_line_pointer ++; /* Matches end-of-loop 'correction'. */
- }
- else
- c = ','; /* Do loop. */
- while ( c == ',' )
- {
- segment = expression( &exp ); /* At least scan over the expression. */
- if ( ! need_pass_2 )
- { /* Still worthwhile making frags. */
- /* Don't call this if we are going to junk this pass anyway! */
- know( segment != SEG_PASS1 );
- if ( segment == SEG_DIFFERENCE && exp . X_add_symbol == NULL )
- {
- as_warn( "Subtracting symbol \"%s\"(segment\"%s\") is too hard. Absolute segment assumed.",
- exp . X_subtract_symbol -> sy_name,
- seg_name [(int) N_TYPE_seg [exp . X_subtract_symbol -> sy_type & N_TYPE]]);
- segment = SEG_ABSOLUTE;
- /* Leave exp . X_add_number alone. */
- }
- p = frag_more (nbytes);
- switch (segment)
- {
- case SEG_BIG:
- as_warn( "%s number illegal. Absolute 0 assumed.",
- exp . X_add_number > 0 ? "Bignum" : "Floating-Point");
- md_number_to_chars (p, (long)0, nbytes);
- break;
- case SEG_NONE:
- as_warn( "0 assumed for missing expression" );
- exp . X_add_number = 0;
- know( exp . X_add_symbol == NULL );
- /* fall into SEG_ABSOLUTE */
- case SEG_ABSOLUTE:
- get = exp . X_add_number;
- use = get & unmask;
- if ( (get & mask) && (get & mask) != mask )
- { /* Leading bits contain both 0s & 1s. */
- as_warn("Value x%x truncated to x%x.", get, use);
- }
- md_number_to_chars (p, use, nbytes); /* put bytes in right order. */
- break;
- case SEG_DIFFERENCE:
- #ifndef WORKING_DOT_WORD
- if(nbytes==2) {
- struct broken_word *x;
- x=(struct broken_word *)xmalloc(sizeof(struct broken_word));
- x->next_broken_word=broken_words;
- broken_words=x;
- x->frag=frag_now;
- x->word_goes_here=p;
- x->dispfrag=0;
- x->add=exp.X_add_symbol;
- x->sub=exp.X_subtract_symbol;
- x->addnum=exp.X_add_number;
- x->added=0;
- new_broken_words++;
- break;
- }
- /* Else Fall through into. . . */
- #endif
- case SEG_BSS:
- case SEG_UNKNOWN:
- case SEG_TEXT:
- case SEG_DATA:
- #ifdef SPARC
- fix_new (frag_now, p - frag_now -> fr_literal, nbytes,
- exp . X_add_symbol, exp . X_subtract_symbol,
- exp . X_add_number, 0, RELOC_32);
- #endif
- #ifdef NS32K
- fix_new_ns32k (frag_now, p - frag_now -> fr_literal, nbytes,
- exp . X_add_symbol, exp . X_subtract_symbol,
- exp . X_add_number, 0, 0, 2, 0, 0);
- #endif
- #if !defined(SPARC) && !defined(NS32K)
- fix_new (frag_now, p - frag_now -> fr_literal, nbytes,
- exp . X_add_symbol, exp . X_subtract_symbol,
- exp . X_add_number, 0);
- #endif
- break;
- default:
- BAD_CASE( segment );
- break;
- } /* switch(segment) */
- } /* if(!need_pass_2) */
- c = * input_line_pointer ++;
- } /* while(c==',') */
- input_line_pointer --; /* Put terminator back into stream. */
- demand_empty_rest_of_line();
- } /* cons() */
- /*
- * big_cons()
- *
- * CONStruct more frag(s) of .quads, or .octa etc.
- * Makes 0 or more new frags.
- * If need_pass_2 == TRUE, generate no frag.
- * This understands only bignums, not expressions. Cons() understands
- * expressions.
- *
- * Constants recognised are '0...'(octal) '0x...'(hex) '...'(decimal).
- *
- * This creates objects with struct obstack_control objs, destroying
- * any context objs held about a partially completed object. Beware!
- *
- *
- * I think it sucks to have 2 different types of integers, with 2
- * routines to read them, store them etc.
- * It would be nicer to permit bignums in expressions and only
- * complain if the result overflowed. However, due to "efficiency"...
- */
- void
- big_cons(nbytes) /* worker to do .quad etc statements */
- /* clobbers input_line_pointer, checks */
- /* end-of-line. */
- register int nbytes; /* 8=.quad 16=.octa ... */
- {
- register char c; /* input_line_pointer -> c. */
- register int radix;
- register long int length; /* Number of chars in an object. */
- register int digit; /* Value of 1 digit. */
- register int carry; /* For multi-precision arithmetic. */
- register int work; /* For multi-precision arithmetic. */
- register char * p; /* For multi-precision arithmetic. */
- extern char hex_value[]; /* In hex_value.c. */
- /*
- * The following awkward logic is to parse ZERO or more strings,
- * comma seperated. Recall an expression includes its leading &
- * trailing blanks. We fake a leading ',' if there is (supposed to
- * be) a 1st expression, and keep demanding 1 expression for each ','.
- */
- if (is_it_end_of_statement())
- {
- c = 0; /* Skip loop. */
- }
- else
- {
- c = ','; /* Do loop. */
- -- input_line_pointer;
- }
- while (c == ',')
- {
- ++ input_line_pointer;
- SKIP_WHITESPACE();
- c = * input_line_pointer;
- /* C contains 1st non-blank character of what we hope is a number. */
- if (c == '0')
- {
- c = * ++ input_line_pointer;
- if (c == 'x' || c=='X')
- {
- c = * ++ input_line_pointer;
- radix = 16;
- }
- else
- {
- radix = 8;
- }
- }
- else
- {
- radix = 10;
- }
- /*
- * This feature (?) is here to stop people worrying about
- * mysterious zero constants: which is what they get when
- * they completely omit digits.
- */
- if (hex_value[c] >= radix)
- {
- as_warn( "Missing digits. 0 assumed." );
- }
- bignum_high = bignum_low - 1; /* Start constant with 0 chars. */
- for( ; (digit = hex_value [c]) < radix; c = * ++ input_line_pointer)
- {
- /* Multiply existing number by radix, then add digit. */
- carry = digit;
- for (p=bignum_low; p <= bignum_high; p++)
- {
- work = (*p & MASK_CHAR) * radix + carry;
- *p = work & MASK_CHAR;
- carry = work >> BITS_PER_CHAR;
- }
- if (carry)
- {
- grow_bignum();
- * bignum_high = carry & MASK_CHAR;
- know( (carry & ~ MASK_CHAR) == 0);
- }
- }
- length = bignum_high - bignum_low + 1;
- if (length > nbytes)
- {
- as_warn( "Most significant bits truncated in integer constant." );
- }
- else
- {
- register long int leading_zeroes;
- for(leading_zeroes = nbytes - length;
- leading_zeroes;
- leading_zeroes --)
- {
- grow_bignum();
- * bignum_high = 0;
- }
- }
- if (! need_pass_2)
- {
- p = frag_more (nbytes);
- bcopy (bignum_low, p, (int)nbytes);
- }
- /* C contains character after number. */
- SKIP_WHITESPACE();
- c = * input_line_pointer;
- /* C contains 1st non-blank character after number. */
- }
- demand_empty_rest_of_line();
- } /* big_cons() */
- static void
- grow_bignum() /* Extend bignum by 1 char. */
- {
- register long int length;
- bignum_high ++;
- if (bignum_high >= bignum_limit)
- {
- length = bignum_limit - bignum_low;
- bignum_low = xrealloc (bignum_low, length + length);
- bignum_high = bignum_low + length;
- bignum_limit = bignum_low + length + length;
- }
- } /* grow_bignum(); */
- /*
- * float_cons()
- *
- * CONStruct some more frag chars of .floats .ffloats etc.
- * Makes 0 or more new frags.
- * If need_pass_2 == TRUE, no frags are emitted.
- * This understands only floating literals, not expressions. Sorry.
- *
- * A floating constant is defined by atof_generic(), except it is preceded
- * by 0d 0f 0g or 0h. After observing the STRANGE way my BSD AS does its
- * reading, I decided to be incompatible. This always tries to give you
- * rounded bits to the precision of the pseudo-op. Former AS did premature
- * truncatation, restored noisy bits instead of trailing 0s AND gave you
- * a choice of 2 flavours of noise according to which of 2 floating-point
- * scanners you directed AS to use.
- *
- * In: input_line_pointer -> whitespace before, or '0' of flonum.
- *
- */
- void /* JF was static, but can't be if VAX.C is goning to use it */
- float_cons(float_type) /* Worker to do .float etc statements. */
- /* Clobbers input_line-pointer, checks end-of-line. */
- register float_type; /* 'f':.ffloat ... 'F':.float ... */
- {
- register char * p;
- register char c;
- int length; /* Number of chars in an object. */
- register char * err; /* Error from scanning floating literal. */
- char temp [MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT];
- /*
- * The following awkward logic is to parse ZERO or more strings,
- * comma seperated. Recall an expression includes its leading &
- * trailing blanks. We fake a leading ',' if there is (supposed to
- * be) a 1st expression, and keep demanding 1 expression for each ','.
- */
- if (is_it_end_of_statement())
- {
- c = 0; /* Skip loop. */
- ++ input_line_pointer; /* -> past termintor. */
- }
- else
- {
- c = ','; /* Do loop. */
- }
- while (c == ',')
- {
- /* input_line_pointer -> 1st char of a flonum (we hope!). */
- SKIP_WHITESPACE();
- /* Skip any 0{letter} that may be present. Don't even check if the
- * letter is legal. Someone may invent a "z" format and this routine
- * has no use for such information. Lusers beware: you get
- * diagnostics if your input is ill-conditioned.
- */
- if(input_line_pointer[0]=='0' && isalpha(input_line_pointer[1]))
- input_line_pointer+=2;
- err = md_atof (float_type, temp, &length);
- know( length <= MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT);
- know( length > 0 );
- if (* err)
- {
- as_warn( "Bad floating literal: %s", err);
- ignore_rest_of_line();
- /* Input_line_pointer -> just after end-of-line. */
- c = 0; /* Break out of loop. */
- }
- else
- {
- if ( ! need_pass_2)
- {
- p = frag_more (length);
- bcopy (temp, p, length);
- }
- SKIP_WHITESPACE();
- c = * input_line_pointer ++;
- /* C contains 1st non-white character after number. */
- /* input_line_pointer -> just after terminator (c). */
- }
- }
- -- input_line_pointer; /* -> terminator (is not ','). */
- demand_empty_rest_of_line();
- } /* float_cons() */
- /*
- * stringer()
- *
- * We read 0 or more ',' seperated, double-quoted strings.
- *
- * Caller should have checked need_pass_2 is FALSE because we don't check it.
- */
- static void
- stringer(append_zero) /* Worker to do .ascii etc statements. */
- /* Checks end-of-line. */
- register int append_zero; /* 0: don't append '\0', else 1 */
- {
- /* register char * p; JF unused */
- /* register int length; JF unused */ /* Length of string we read, excluding */
- /* trailing '\0' implied by closing quote. */
- /* register char * where; JF unused */
- /* register fragS * fragP; JF unused */
- register int c;
- /*
- * The following awkward logic is to parse ZERO or more strings,
- * comma seperated. Recall a string expression includes spaces
- * before the opening '\"' and spaces after the closing '\"'.
- * We fake a leading ',' if there is (supposed to be)
- * a 1st, expression. We keep demanding expressions for each
- * ','.
- */
- if (is_it_end_of_statement())
- {
- c = 0; /* Skip loop. */
- ++ input_line_pointer; /* Compensate for end of loop. */
- }
- else
- {
- c = ','; /* Do loop. */
- }
- for ( ; c == ','; c = *input_line_pointer ++)
- {
- SKIP_WHITESPACE();
- if (* input_line_pointer == '\"')
- {
- ++ input_line_pointer; /* -> 1st char of string. */
- while ( (c = next_char_of_string()) >= 0)
- {
- FRAG_APPEND_1_CHAR( c );
- }
- if (append_zero)
- {
- FRAG_APPEND_1_CHAR( 0 );
- }
- know( input_line_pointer [-1] == '\"' );
- }
- else
- {
- as_warn( "Expected \"-ed string" );
- }
- SKIP_WHITESPACE();
- }
- -- input_line_pointer;
- demand_empty_rest_of_line();
- } /* stringer() */
- static int
- next_char_of_string ()
- {
- register int c;
- c = * input_line_pointer ++;
- switch (c)
- {
- case '\"':
- c = -1;
- break;
- case '\\':
- switch (c = * input_line_pointer ++)
- {
- case 'b':
- c = '\b';
- break;
- case 'f':
- c = '\f';
- break;
- case 'n':
- c = '\n';
- break;
- case 'r':
- c = '\r';
- break;
- case 't':
- c = '\t';
- break;
- case '\\':
- case '"':
- break; /* As itself. */
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- {
- long int number;
- for (number = 0; isdigit(c); c = * input_line_pointer ++)
- {
- number = number * 8 + c - '0';
- }
- c = number;
- }
- -- input_line_pointer;
- break;
- case '\n':
- /* as_fatal( "Unterminated string - use app!" ); */
- /* To be compatible with BSD 4.2 as: give the luser a linefeed!! */
- c = '\n';
- break;
- default:
- as_warn( "Bad escaped character in string, '?' assumed" );
- c = '?';
- break;
- }
- break;
- default:
- break;
- }
- return (c);
- }
- static segT
- get_segmented_expression ( expP )
- register expressionS * expP;
- {
- register segT retval;
- if ( (retval = expression( expP )) == SEG_PASS1 || retval == SEG_NONE || retval == SEG_BIG )
- {
- as_warn("Expected address expression: absolute 0 assumed");
- retval = expP -> X_seg = SEG_ABSOLUTE;
- expP -> X_add_number = 0;
- expP -> X_add_symbol = expP -> X_subtract_symbol = 0;
- }
- return (retval); /* SEG_ ABSOLUTE,UNKNOWN,DATA,TEXT,BSS */
- }
- static segT
- get_known_segmented_expression ( expP )
- register expressionS * expP;
- {
- register segT retval;
- register char * name1;
- register char * name2;
- if ( (retval = get_segmented_expression (expP)) == SEG_UNKNOWN
- )
- {
- name1 = expP -> X_add_symbol ? expP -> X_add_symbol -> sy_name : "";
- name2 = expP -> X_subtract_symbol ? expP -> X_subtract_symbol -> sy_name : "";
- if ( name1 && name2 )
- {
- as_warn("Symbols \"%s\" \"%s\" are undefined: absolute 0 assumed.",
- name1, name2);
- }
- else
- {
- as_warn("Symbol \"%s\" undefined: absolute 0 assumed.",
- name1 ? name1 : name2);
- }
- retval = expP -> X_seg = SEG_ABSOLUTE;
- expP -> X_add_number = 0;
- expP -> X_add_symbol = expP -> X_subtract_symbol = NULL;
- }
- know( retval == SEG_ABSOLUTE || retval == SEG_DATA || retval == SEG_TEXT || retval == SEG_BSS || retval == SEG_DIFFERENCE );
- return (retval);
- } /* get_known_segmented_expression() */
- /* static */ long int /* JF was static, but can't be if the MD pseudos are to use it */
- get_absolute_expression ()
- {
- expressionS exp;
- register segT s;
- if ( (s = expression(& exp)) != SEG_ABSOLUTE )
- {
- if ( s != SEG_NONE )
- {
- as_warn( "Bad Absolute Expression, absolute 0 assumed.");
- }
- exp . X_add_number = 0;
- }
- return (exp . X_add_number);
- }
- static char /* return terminator */
- get_absolute_expression_and_terminator( val_pointer)
- long int * val_pointer; /* return value of expression */
- {
- * val_pointer = get_absolute_expression ();
- return ( * input_line_pointer ++ );
- }
- /*
- * demand_copy_C_string()
- *
- * Like demand_copy_string, but return NULL if the string contains any '\0's.
- * Give a warning if that happens.
- */
- static char *
- demand_copy_C_string (len_pointer)
- int * len_pointer;
- {
- register char * s;
- if (s = demand_copy_string (len_pointer))
- {
- register int len;
- for (len = * len_pointer;
- len > 0;
- len--)
- {
- if (* s == 0)
- {
- s = 0;
- len = 1;
- * len_pointer = 0;
- as_warn( "This string may not contain \'\\0\'" );
- }
- }
- }
- return (s);
- }
- /*
- * demand_copy_string()
- *
- * Demand string, but return a safe (=private) copy of the string.
- * Return NULL if we can't read a string here.
- */
- static char *
- demand_copy_string (lenP)
- int * lenP;
- {
- register int c;
- register int len;
- char * retval;
- len = 0;
- SKIP_WHITESPACE();
- if (* input_line_pointer == '\"')
- {
- input_line_pointer ++; /* Skip opening quote. */
- while ( (c = next_char_of_string()) >= 0 ) {
- obstack_1grow ( ¬es, c );
- len ++;
- }
- /* JF this next line is so demand_copy_C_string will return a null
- termanated string. */
- obstack_1grow(¬es,'\0');
- retval=obstack_finish( ¬es);
- } else {
- as_warn( "Missing string" );
- retval = NULL;
- ignore_rest_of_line ();
- }
- * lenP = len;
- return (retval);
- }
- /*
- * is_it_end_of_statement()
- *
- * In: Input_line_pointer -> next character.
- *
- * Do: Skip input_line_pointer over all whitespace.
- *
- * Out: TRUE if input_line_pointer -> end-of-line.
- */
- static int
- is_it_end_of_statement()
- {
- SKIP_WHITESPACE();
- return (is_end_of_line [* input_line_pointer]);
- }
- void
- equals(sym_name)
- char *sym_name;
- {
- register struct symbol * symbolP; /* symbol we are working with */
- if(sym_name[0]=='.' && sym_name[1]=='\0') {
- /* Turn '. = mumble' into a .org mumble */
- register segT segment;
- expressionS exp;
- register char *p;
- if(input_line_pointer[1]=='=')
- input_line_pointer+=2;
- else
- *input_line_pointer++='='; /* Put it back */
- if(*input_line_pointer==' ' || *input_line_pointer=='\t')
- input_line_pointer++;
- segment = get_known_segmented_expression(& exp);
- if ( ! need_pass_2 ) {
- if (segment != now_seg && segment != SEG_ABSOLUTE)
- as_warn("Illegal segment \"%s\". Segment \"%s\" assumed.",
- seg_name [(int) segment], seg_name [(int) now_seg]);
- p = frag_var (rs_org, 1, 1, (relax_substateT)0, exp.X_add_symbol,
- exp.X_add_number, (char *)0);
- * p = 0;
- } /* if (ok to make frag) */
- return;
- }
- symbolP=symbol_find_or_make(sym_name);
- if(input_line_pointer[1]=='=')
- input_line_pointer+=2;
- else
- *input_line_pointer++='='; /* Put it back */
- pseudo_set(symbolP);
- }
- /* end: read.c */
|