/* 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. */ /* App, the assembler pre-processor. This pre-processor strips out excess spaces, turns single-quoted characters into a decimal constant, and turns # into a .line ;.file pair. This needs better error-handling. */ #include #ifdef USG #define bzero(s,n) memset(s,0,n) #endif #if !defined(__STDC__) && !defined(const) #define const /* Nothing */ #endif static char lex [256]; static const char symbol_chars[] = "$._ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; extern const char comment_chars[]; extern const char line_comment_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) void do_scrub_begin() { const char *p; 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; } FILE *scrub_file; int scrub_from_file() { return getc(scrub_file); } void scrub_to_file(ch) int ch; { ungetc(ch,scrub_file); } char *scrub_string; char *scrub_last_string; int scrub_from_string() { return scrub_string == scrub_last_string ? EOF : *scrub_string++; } void scrub_to_string(ch) int ch; { *--scrub_string=ch; } 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) { ch= *out_string++; 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; (*unget)(ch); } state=old_state; return ' '; } if(state==4) { ch=(*get)(); if(ch==EOF || (ch>='0' && ch<='9')) return ch; else { while(ch!=EOF && IS_WHITESPACE(ch)) ch=(*get)(); if(ch=='"') { (*unget)(ch); out_string="; .file "; old_state=7; state= -1; return *out_string++; } else { while(ch!=EOF && ch!='\n') ch=(*get)(); return ch; } } } if(state==5) { ch=(*get)(); if(ch=='"') { state=old_state; return '"'; } else if(ch=='\\') { state=6; return ch; } else if(ch==EOF) { as_warn("End of file in string: inserted '\"'"); state=old_state; (*unget)('\n'); return '"'; } else { return ch; } } if(state==6) { state=5; ch=(*get)(); 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': case 'f': case 'n': case 'r': case 't': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': break; default: as_warn("Unknown escape '\\%c' in string: Ignored",ch); break; case EOF: as_warn("End of file in string: '\"' inserted"); return '"'; } return ch; } if(state==7) { ch=(*get)(); state=5; old_state=8; return ch; } if(state==8) { do ch= (*get)(); while(ch!='\n'); state=0; return ch; } flushchar: ch=(*get)(); switch(ch) { case ' ': case '\t': 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; } (*unget)(ch); if(state==0 || state==2) { state++; return ' '; } else goto flushchar; case '/': ch=(*get)(); if(ch=='*') { for(;;) { do { ch=(*get)(); if(ch=='\n') add_newlines++; } while(ch!=EOF && ch!='*'); ch=(*get)(); if(ch==EOF || ch=='/') break; (*unget)(ch); } if(ch==EOF) as_warn("End of file in '/' '*' string: */ inserted"); (*unget)(' '); goto flushchar; } else { if(IS_COMMENT('/') || (state==0 && IS_LINE_COMMENT('/'))) { (*unget)(ch); ch='/'; goto deal_misc; } if(ch!=EOF) (*unget)(ch); return '/'; } break; case '"': old_state=state; state=5; return '"'; break; case '\'': ch=(*get)(); if(ch==EOF) { as_warn("End-of-file after a ': \000 inserted"); ch=0; } sprintf(out_buf,"(%d)",ch&0xff); old_state=state; state= -1; out_string=out_buf; return *out_string++; case ':': if(state!=3) state=0; return ch; case '\n': if(add_newlines) { --add_newlines; (*unget)(ch); } case ';': 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"); state=0; return '\n'; } else if(state==0) { state=2; return ch; } else if(state==1) { state=2; return ch; } else { return ch; } case EOF: if(state==0) return ch; as_warn("End-of-File not at end of a line"); } return -1; } #ifdef TEST char comment_chars[] = "|"; char line_comment_chars[] = "#"; main() { int ch; app_begin(); while((ch=do_scrub_next_char(stdin))!=EOF) putc(ch,stdout); } as_warn(str) char *str; { fputs(str,stderr); putc('\n',stderr); } #endif