diff options
| author | Paul Richards <paul@FreeBSD.org> | 1993-11-03 00:56:24 +0000 |
|---|---|---|
| committer | Paul Richards <paul@FreeBSD.org> | 1993-11-03 00:56:24 +0000 |
| commit | 3bab57bf8e94dcfa7f63ca3dfe2d903b5dda75bc (patch) | |
| tree | c6947a527e76f67f3d2eb22488df6f6ca9734b47 /gnu/usr.bin/as/app.c | |
| parent | 81fc6236e6282ee57c0a9dfd75135aaab443c1e3 (diff) | |
Notes
Diffstat (limited to 'gnu/usr.bin/as/app.c')
| -rw-r--r-- | gnu/usr.bin/as/app.c | 607 |
1 files changed, 377 insertions, 230 deletions
diff --git a/gnu/usr.bin/as/app.c b/gnu/usr.bin/as/app.c index a0ec8a28e808..4c89a77607a8 100644 --- a/gnu/usr.bin/as/app.c +++ b/gnu/usr.bin/as/app.c @@ -1,182 +1,273 @@ +/* Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. + + Modified by Allen Wirfs-Brock, Instantiations Inc 2/90 + */ /* This is the Assembler Pre-Processor Copyright (C) 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. */ + + 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 2, 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. */ /* App, the assembler pre-processor. This pre-processor strips out excess spaces, turns single-quoted characters into a decimal constant, and turns - # <number> <filename> <garbage> into a .line <number>;.file <filename> pair. + # <number> <filename> <garbage> into a .line <number>\n.app-file <filename> pair. This needs better error-handling. - */ -#include <stdio.h> -#ifdef USG -#define bzero(s,n) memset(s,0,n) + */ +#ifndef lint +static char rcsid[] = "$Id: app.c,v 1.3 1993/10/02 20:57:12 pk Exp $"; #endif -#if !defined(__STDC__) && !defined(const) + +#include <stdio.h> +#include "as.h" /* For BAD_CASE() only */ + +#if (__STDC__ != 1) && !defined(const) #define const /* Nothing */ #endif -static char lex [256]; -static const char symbol_chars[] = - "$._ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; +static char lex[256]; +static char symbol_chars[] = + "$._ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; +/* These will go in BSS if not defined elsewhere, producing empty strings. */ extern const char comment_chars[]; extern const char line_comment_chars[]; +extern const char line_separator_chars[]; -#define LEX_IS_SYMBOL_COMPONENT (1) -#define LEX_IS_WHITESPACE (2) -#define LEX_IS_LINE_SEPERATOR (4) -#define LEX_IS_COMMENT_START (8) /* JF added these two */ -#define LEX_IS_LINE_COMMENT_START (16) -#define IS_SYMBOL_COMPONENT(c) (lex [c] & LEX_IS_SYMBOL_COMPONENT) -#define IS_WHITESPACE(c) (lex [c] & LEX_IS_WHITESPACE) -#define IS_LINE_SEPERATOR(c) (lex [c] & LEX_IS_LINE_SEPERATOR) -#define IS_COMMENT(c) (lex [c] & LEX_IS_COMMENT_START) -#define IS_LINE_COMMENT(c) (lex [c] & LEX_IS_LINE_COMMENT_START) +#define LEX_IS_SYMBOL_COMPONENT 1 +#define LEX_IS_WHITESPACE 2 +#define LEX_IS_LINE_SEPARATOR 3 +#define LEX_IS_COMMENT_START 4 +#define LEX_IS_LINE_COMMENT_START 5 +#define LEX_IS_TWOCHAR_COMMENT_1ST 6 +#define LEX_IS_TWOCHAR_COMMENT_2ND 7 +#define LEX_IS_STRINGQUOTE 8 +#define LEX_IS_COLON 9 +#define LEX_IS_NEWLINE 10 +#define LEX_IS_ONECHAR_QUOTE 11 +#define IS_SYMBOL_COMPONENT(c) (lex[c] == LEX_IS_SYMBOL_COMPONENT) +#define IS_WHITESPACE(c) (lex[c] == LEX_IS_WHITESPACE) +#define IS_LINE_SEPARATOR(c) (lex[c] == LEX_IS_LINE_SEPARATOR) +#define IS_COMMENT(c) (lex[c] == LEX_IS_COMMENT_START) +#define IS_LINE_COMMENT(c) (lex[c] == LEX_IS_LINE_COMMENT_START) +#define IS_NEWLINE(c) (lex[c] == LEX_IS_NEWLINE) -void -do_scrub_begin() -{ - const char *p; +/* FIXME-soon: The entire lexer/parser thingy should be + built statically at compile time rather than dynamically + each and every time the assembler is run. xoxorich. */ - bzero (lex, sizeof(lex)); /* Trust NOBODY! */ - lex [' '] |= LEX_IS_WHITESPACE; - lex ['\t'] |= LEX_IS_WHITESPACE; - for (p =symbol_chars;*p;++p) - lex [*p] |= LEX_IS_SYMBOL_COMPONENT; - lex ['\n'] |= LEX_IS_LINE_SEPERATOR; -#ifdef DONTDEF - lex [':'] |= LEX_IS_LINE_SEPERATOR; -#endif - lex [';'] |= LEX_IS_LINE_SEPERATOR; - for (p=comment_chars;*p;p++) - lex[*p] |= LEX_IS_COMMENT_START; - for (p=line_comment_chars;*p;p++) - lex[*p] |= LEX_IS_LINE_COMMENT_START; -} +void do_scrub_begin() { + const char *p; + + lex[' '] = LEX_IS_WHITESPACE; + lex['\t'] = LEX_IS_WHITESPACE; + lex['\n'] = LEX_IS_NEWLINE; + lex[';'] = LEX_IS_LINE_SEPARATOR; + lex['"'] = LEX_IS_STRINGQUOTE; + lex['\''] = LEX_IS_ONECHAR_QUOTE; + lex[':'] = LEX_IS_COLON; + + /* Note that these override the previous defaults, e.g. if ';' + is a comment char, then it isn't a line separator. */ + for (p = symbol_chars; *p; ++p) { + lex[*p] = LEX_IS_SYMBOL_COMPONENT; + } /* declare symbol characters */ + + for (p = line_comment_chars; *p; p++) { + lex[*p] = LEX_IS_LINE_COMMENT_START; + } /* declare line comment chars */ + + for (p = comment_chars; *p; p++) { + lex[*p] = LEX_IS_COMMENT_START; + } /* declare comment chars */ + + for (p = line_separator_chars; *p; p++) { + lex[*p] = LEX_IS_LINE_SEPARATOR; + } /* declare line separators */ + + /* Only allow slash-star comments if slash is not in use */ + if (lex['/'] == 0) { + lex['/'] = LEX_IS_TWOCHAR_COMMENT_1ST; + } + /* FIXME-soon. This is a bad hack but otherwise, we + can't do c-style comments when '/' is a line + comment char. xoxorich. */ + if (lex['*'] == 0) { + lex['*'] = LEX_IS_TWOCHAR_COMMENT_2ND; + } +} /* do_scrub_begin() */ FILE *scrub_file; -int -scrub_from_file() -{ +int scrub_from_file() { return getc(scrub_file); } -void -scrub_to_file(ch) +void scrub_to_file(ch) int ch; { ungetc(ch,scrub_file); -} +} /* scrub_to_file() */ char *scrub_string; char *scrub_last_string; -int -scrub_from_string() -{ +int scrub_from_string() { return scrub_string == scrub_last_string ? EOF : *scrub_string++; -} +} /* scrub_from_string() */ -void -scrub_to_string(ch) +void scrub_to_string(ch) int ch; { *--scrub_string=ch; +} /* scrub_to_string() */ + +/* Saved state of the scrubber */ +static int state; +static int old_state; +static char *out_string; +static char out_buf[20]; +static int add_newlines = 0; + +/* Data structure for saving the state of app across #include's. Note that + app is called asynchronously to the parsing of the .include's, so our + state at the time .include is interpreted is completely unrelated. + That's why we have to save it all. */ + +struct app_save { + int state; + int old_state; + char *out_string; + char out_buf[sizeof (out_buf)]; + int add_newlines; + char *scrub_string; + char *scrub_last_string; + FILE *scrub_file; +}; + +char *app_push() { + register struct app_save *saved; + + saved = (struct app_save *) xmalloc(sizeof (*saved)); + saved->state = state; + saved->old_state = old_state; + saved->out_string = out_string; + memcpy(out_buf, saved->out_buf, sizeof(out_buf)); + saved->add_newlines = add_newlines; + saved->scrub_string = scrub_string; + saved->scrub_last_string = scrub_last_string; + saved->scrub_file = scrub_file; + + /* do_scrub_begin() is not useful, just wastes time. */ + return (char *)saved; } -int -do_scrub_next_char(get,unget) +void app_pop(arg) +char *arg; +{ + register struct app_save *saved = (struct app_save *)arg; + + /* There is no do_scrub_end (). */ + state = saved->state; + old_state = saved->old_state; + out_string = saved->out_string; + memcpy(saved->out_buf, out_buf, sizeof (out_buf)); + add_newlines = saved->add_newlines; + scrub_string = saved->scrub_string; + scrub_last_string = saved->scrub_last_string; + scrub_file = saved->scrub_file; + + free (arg); +} /* app_pop() */ + +int do_scrub_next_char(get,unget) int (*get)(); void (*unget)(); -/* FILE *fp; */ { - /* State 0: beginning of normal line - 1: After first whitespace on normal line (flush more white) - 2: After first non-white on normal line (keep 1white) - 3: after second white on normal line (flush white) - 4: after putting out a .line, put out digits - 5: parsing a string, then go to old-state - 6: putting out \ escape in a "d string. - 7: After putting out a .file, put out string. - 8: After putting out a .file string, flush until newline. - -1: output string in out_string and go to the state in old_state - -2: flush text until a '*' '/' is seen, then go to state old_state - */ - - static state; - static old_state; - static char *out_string; - static char out_buf[20]; - static add_newlines; - int ch; - - if(state==-1) { + /*State 0: beginning of normal line + 1: After first whitespace on line (flush more white) + 2: After first non-white (opcode) on line (keep 1white) + 3: after second white on line (into operands) (flush white) + 4: after putting out a .line, put out digits + 5: parsing a string, then go to old-state + 6: putting out \ escape in a "d string. + 7: After putting out a .app-file, put out string. + 8: After putting out a .app-file string, flush until newline. + -1: output string in out_string and go to the state in old_state + -2: flush text until a '*' '/' is seen, then go to state old_state + */ + + register int ch, ch2 = 0; + + switch (state) { + case -1: ch= *out_string++; - if(*out_string==0) { + if (*out_string == 0) { state=old_state; old_state=3; } return ch; - } - if(state==-2) { - for(;;) { - do ch=(*get)(); - while(ch!=EOF && ch!='\n' && ch!='*'); - if(ch=='\n' || ch==EOF) - return ch; - ch=(*get)(); - if(ch==EOF || ch=='/') - break; + + case -2: + for (;;) { + do { + ch=(*get)(); + } while (ch != EOF && ch != '\n' && ch != '*'); + if (ch == '\n' || ch == EOF) + return ch; + + /* At this point, ch must be a '*' */ + while ( (ch=(*get)()) == '*' ){ + ; + } + if (ch == EOF || ch == '/') + break; (*unget)(ch); } state=old_state; return ' '; - } - if(state==4) { + + case 4: ch=(*get)(); - if(ch==EOF || (ch>='0' && ch<='9')) - return ch; + if (ch == EOF || (ch >= '0' && ch <= '9')) + return ch; else { - while(ch!=EOF && IS_WHITESPACE(ch)) - ch=(*get)(); - if(ch=='"') { + while (ch != EOF && IS_WHITESPACE(ch)) + ch=(*get)(); + if (ch == '"') { (*unget)(ch); - out_string="; .file "; + out_string="\n.app-file "; old_state=7; state= -1; return *out_string++; } else { - while(ch!=EOF && ch!='\n') - ch=(*get)(); + while (ch != EOF && ch != '\n') + ch=(*get)(); return ch; } } - } - if(state==5) { + + case 5: ch=(*get)(); - if(ch=='"') { + if (ch == '"') { state=old_state; return '"'; - } else if(ch=='\\') { + } else if (ch == '\\') { state=6; return ch; - } else if(ch==EOF) { + } else if (ch == EOF) { as_warn("End of file in string: inserted '\"'"); state=old_state; (*unget)('\n'); @@ -184,19 +275,19 @@ void (*unget)(); } else { return ch; } - } - if(state==6) { + + case 6: state=5; ch=(*get)(); - switch(ch) { + switch (ch) { /* This is neet. Turn "string more string" into "string\n more string" - */ + */ case '\n': (*unget)('n'); add_newlines++; return '\\'; - + case '"': case '\\': case 'b': @@ -204,6 +295,9 @@ void (*unget)(); case 'n': case 'r': case 't': +#ifdef BACKSLASH_V + case 'v': +#endif /* BACKSLASH_V */ case '0': case '1': case '2': @@ -213,158 +307,202 @@ void (*unget)(); case '6': case '7': break; + +#ifdef ONLY_STANDARD_ESCAPES default: as_warn("Unknown escape '\\%c' in string: Ignored",ch); break; - +#else /* ONLY_STANDARD_ESCAPES */ + default: + /* Accept \x as x for any x */ + break; +#endif /* ONLY_STANDARD_ESCAPES */ + case EOF: as_warn("End of file in string: '\"' inserted"); return '"'; } return ch; - } - - if(state==7) { + + case 7: ch=(*get)(); state=5; old_state=8; return ch; - } - - if(state==8) { + + case 8: do ch= (*get)(); - while(ch!='\n'); + while (ch != '\n'); state=0; return ch; } - - flushchar: + + /* OK, we are somewhere in states 0 through 4 */ + + /* flushchar: */ ch=(*get)(); - switch(ch) { - case ' ': - case '\t': + recycle: + if (ch == EOF) { + if (state != 0) + as_warn("End of file not at end of a line: Newline inserted."); + return ch; + } + + switch (lex[ch]) { + case LEX_IS_WHITESPACE: do ch=(*get)(); - while(ch!=EOF && IS_WHITESPACE(ch)); - if(ch==EOF) - return ch; - if(IS_COMMENT(ch) || (state==0 && IS_LINE_COMMENT(ch)) || ch=='/' || IS_LINE_SEPERATOR(ch)) { - (*unget)(ch); - goto flushchar; + while (ch != EOF && IS_WHITESPACE(ch)); + if (ch == EOF) + return ch; + if (IS_COMMENT(ch) || (state == 0 && IS_LINE_COMMENT(ch)) || ch == '/' || IS_LINE_SEPARATOR(ch)) { + goto recycle; } - (*unget)(ch); - if(state==0 || state==2) { - state++; - return ' '; - } else goto flushchar; - - case '/': - ch=(*get)(); - if(ch=='*') { - for(;;) { + switch (state) { + case 0: state++; goto recycle; /* Punted leading sp */ + case 1: BAD_CASE(state); /* We can't get here */ + case 2: state++; (*unget)(ch); return ' '; /* Sp after opco */ + case 3: goto recycle; /* Sp in operands */ + default: BAD_CASE(state); + } + break; + + case LEX_IS_TWOCHAR_COMMENT_1ST: + ch2=(*get)(); + if (ch2 != EOF && lex[ch2] == LEX_IS_TWOCHAR_COMMENT_2ND) { + for (;;) { do { - ch=(*get)(); - if(ch=='\n') - add_newlines++; - } while(ch!=EOF && ch!='*'); - ch=(*get)(); - if(ch==EOF || ch=='/') - break; + ch2=(*get)(); + if (ch2 != EOF && IS_NEWLINE(ch2)) + add_newlines++; + } while (ch2 != EOF && + (lex[ch2] != LEX_IS_TWOCHAR_COMMENT_2ND)); + + while (ch2 != EOF && + (lex[ch2] == LEX_IS_TWOCHAR_COMMENT_2ND)){ + ch2=(*get)(); + } + + if (ch2 == EOF + || lex[ch2] == LEX_IS_TWOCHAR_COMMENT_1ST) + break; (*unget)(ch); } - if(ch==EOF) - as_warn("End of file in '/' '*' string: */ inserted"); - - (*unget)(' '); - goto flushchar; + if (ch2 == EOF) + as_warn("End of file in multiline comment"); + + ch = ' '; + goto recycle; } else { - if(IS_COMMENT('/') || (state==0 && IS_LINE_COMMENT('/'))) { - (*unget)(ch); - ch='/'; - goto deal_misc; - } - if(ch!=EOF) - (*unget)(ch); - return '/'; + if (ch2 != EOF) + (*unget)(ch2); + return ch; } break; - - case '"': + + case LEX_IS_STRINGQUOTE: old_state=state; state=5; - return '"'; - break; - - case '\'': + return ch; + +#ifndef IEEE_STYLE + case LEX_IS_ONECHAR_QUOTE: ch=(*get)(); - if(ch==EOF) { - as_warn("End-of-file after a ': \000 inserted"); + if (ch == EOF) { + as_warn("End-of-file after a one-character quote; \000 inserted"); ch=0; } - sprintf(out_buf,"(%d)",ch&0xff); + sprintf(out_buf,"%d", (int)(unsigned char)ch); + + /* None of these 'x constants for us. We want 'x'. + */ + if ( (ch=(*get)()) != '\'' ) { +#ifdef REQUIRE_CHAR_CLOSE_QUOTE + as_warn("Missing close quote: (assumed)"); +#else + (*unget)(ch); +#endif + } + old_state=state; state= -1; out_string=out_buf; return *out_string++; - - case ':': - if(state!=3) - state=0; +#endif + case LEX_IS_COLON: + if (state != 3) + state=0; return ch; - - case '\n': - if(add_newlines) { + + case LEX_IS_NEWLINE: + /* Roll out a bunch of newlines from inside comments, etc. */ + if (add_newlines) { --add_newlines; (*unget)(ch); } - case ';': + /* fall thru into... */ + + case LEX_IS_LINE_SEPARATOR: state=0; return ch; - - default: - deal_misc: - if(state==0 && IS_LINE_COMMENT(ch)) { - do ch=(*get)(); - while(ch!=EOF && IS_WHITESPACE(ch)); - if(ch==EOF) { - as_warn("EOF in comment: Newline inserted"); - return '\n'; - } - if(ch<'0' || ch>'9') { - while(ch!=EOF && ch!='\n') - ch=(*get)(); - if(ch==EOF) - as_warn("EOF in Comment: Newline inserted"); - state=0; - return '\n'; - } - (*unget)(ch); - old_state=4; - state= -1; - out_string=".line "; - return *out_string++; - - } else if(IS_COMMENT(ch)) { - do ch=(*get)(); - while(ch!=EOF && ch!='\n'); - if(ch==EOF) - as_warn("EOF in comment: Newline inserted"); + + case LEX_IS_LINE_COMMENT_START: + if (state != 0) /* Not at start of line, act normal */ + goto de_fault; + + /* FIXME-someday: The two character comment stuff was badly + thought out. On i386, we want '/' as line comment start + AND we want C style comments. hence this hack. The + whole lexical process should be reworked. xoxorich. */ + + if (ch == '/' && (ch2 = (*get)()) == '*') { + state = -2; + return(do_scrub_next_char(get, unget)); + } else { + (*unget)(ch2); + } /* bad hack */ + + do ch=(*get)(); + while (ch != EOF && IS_WHITESPACE(ch)); + if (ch == EOF) { + as_warn("EOF in comment: Newline inserted"); + return '\n'; + } + if (ch<'0' || ch>'9') { + /* Non-numerics: Eat whole comment line */ + while (ch != EOF && !IS_NEWLINE(ch)) + ch=(*get)(); + if (ch == EOF) + as_warn("EOF in Comment: Newline inserted"); state=0; return '\n'; - - } else if(state==0) { - state=2; + } + /* Numerics begin comment. Perhaps CPP `# 123 "filename"' */ + (*unget)(ch); + old_state=4; + state= -1; + out_string=".line "; + return *out_string++; + + case LEX_IS_COMMENT_START: + do ch=(*get)(); + while (ch != EOF && !IS_NEWLINE(ch)); + if (ch == EOF) + as_warn("EOF in comment: Newline inserted"); + state=0; + return '\n'; + + default: + de_fault: + /* Some relatively `normal' character. */ + if (state == 0) { + state=2; /* Now seeing opcode */ return ch; - } else if(state==1) { - state=2; + } else if (state == 1) { + state=2; /* Ditto */ return ch; } else { - return ch; - + return ch; /* Opcode or operands already */ } - case EOF: - if(state==0) - return ch; - as_warn("End-of-File not at end of a line"); } return -1; } @@ -377,10 +515,10 @@ char line_comment_chars[] = "#"; main() { int ch; - + app_begin(); - while((ch=do_scrub_next_char(stdin))!=EOF) - putc(ch,stdout); + while ((ch=do_scrub_next_char(stdin)) != EOF) + putc(ch,stdout); } as_warn(str) @@ -390,3 +528,12 @@ char *str; putc('\n',stderr); } #endif + +/* + * Local Variables: + * comment-column: 0 + * fill-column: 131 + * End: + */ + +/* end of app.c */ |
