home *** CD-ROM | disk | FTP | other *** search
- /* 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
- # <number> <filename> <garbage> into a .line <number>;.file <filename> pair.
- This needs better error-handling.
- */
- #include <stdio.h>
- #include <string.h>
- #include "as.h"
- #include "md.h"
- #include "app.h"
- #include "messages.h"
-
- FILE *scrub_file = NULL;
- char *scrub_string = NULL;
- char *scrub_last_string = NULL;
-
- #ifdef NeXT /* .include feature */
- /* These are moved out of do_scrub() so save_scrub_context() can save them */
- static state;
- static old_state;
- static char *out_string;
- static char out_buf[20];
- static add_newlines = 0;
- #endif /* NeXT .include feature */
-
- static char lex [256];
- static char symbol_chars[] =
- "$._ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
-
- #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(
- void)
- {
- char *p;
- const char *q;
-
- memset(lex, '\0', sizeof(lex)); /* Trust NOBODY! */
- lex [' '] |= LEX_IS_WHITESPACE;
- lex ['\t'] |= LEX_IS_WHITESPACE;
- for (p =symbol_chars;*p;++p)
- lex [(int)*p] |= LEX_IS_SYMBOL_COMPONENT;
- lex ['\n'] |= LEX_IS_LINE_SEPERATOR;
- #ifndef DONTDEF
- #ifdef NeXT
- /*
- * This DOES not cause ':' to be a LINE SEPERATOR but does make the
- * second if logic after flushchar: in do_scrub_next_char() to handle
- * "foo :" and strip the blanks. This is the way has always been and
- * must be this way to work.
- */
- #endif /* NeXT */
- lex [':'] |= LEX_IS_LINE_SEPERATOR;
- #endif /* !defined(DONTDEF) */
-
- #if defined(M88K) || defined(M98K) || defined(HPPA)
- lex ['@'] |= LEX_IS_LINE_SEPERATOR;
- #else
- lex [';'] |= LEX_IS_LINE_SEPERATOR;
- #endif
- for (q=md_comment_chars;*q;q++)
- lex[(int)*q] |= LEX_IS_COMMENT_START;
- for (q=md_line_comment_chars;*q;q++)
- lex[(int)*q] |= LEX_IS_LINE_COMMENT_START;
- }
-
- int
- scrub_from_file(
- void)
- {
- return getc(scrub_file);
- }
-
- void
- scrub_to_file(
- int ch)
- {
- ungetc(ch, scrub_file);
- }
-
- int
- scrub_from_string(
- void)
- {
- return scrub_string == scrub_last_string ? EOF : *scrub_string++;
- }
-
- void
- scrub_to_string(
- int ch)
- {
- *--scrub_string = ch;
- }
-
- int
- do_scrub_next_char(
- int (*get)(void),
- void (*unget)(int ch))
- /* 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
- */
-
- #ifndef NeXT /* .include feature */
- static state;
- static old_state;
- static char *out_string;
- static char out_buf[20];
- static add_newlines = 0;
- #endif /* NeXT .include feature */
- 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);
- #if defined(M88K) || defined(M98K) || defined(HPPA)
- out_string="@ .file ";
- #else
- out_string="; .file ";
- #endif
- old_state=7;
- state= -1;
- return *out_string++;
- } else {
- while(ch!=EOF && ch!='\n')
- ch=(*get)();
- #ifdef NeXT
- /* bug fix for bug #8918, which was when
- * a full line comment line this:
- * # 40 MP1 = M + 1
- * got confused with a cpp output like:
- * # 1 "hello.c" 1
- */
- state = 0;
- #endif /* NeXT */
- 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 defined(I860) || defined(M88K) || defined(M98K) || defined(I386) || \
- defined(HPPA) || defined (SPARC)
- if (ch == '/') {
- do {
- ch=(*get)();
- } while (ch != EOF && (ch != '\n'));
- if (ch == EOF)
- as_warn("End of file before newline in // comment");
- if ( ch == '\n' ) /* Push NL back so we can complete state */
- (*unget)(ch);
- goto flushchar;
- }
- #endif
- 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);
- }
- /* Fall through. */
- #if defined(M88K) || defined(M98K) || defined(HPPA)
- case '@':
- #else
- case ';':
- #endif
- 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') {
- do ch=(*get)();
- while(ch!=EOF && ch!='\n');
- 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 NeXT /* .include feature */
- void
- save_scrub_context(
- scrub_context_data *save_buffer_ptr)
- {
- save_buffer_ptr->last_scrub_file = scrub_file;
- save_buffer_ptr->last_state = state;
- save_buffer_ptr->last_old_state = old_state;
- save_buffer_ptr->last_out_string = out_string;
- memcpy(save_buffer_ptr->last_out_buf, out_buf, sizeof(out_buf));
- save_buffer_ptr->last_add_newlines = add_newlines;
-
- state = 0;
- old_state = 0;
- out_string = NULL;
- memset(out_buf, '\0', sizeof(out_buf));
- add_newlines = 0;
- }
-
- void
- restore_scrub_context(
- scrub_context_data *save_buffer_ptr)
- {
- scrub_file = save_buffer_ptr->last_scrub_file;
- state = save_buffer_ptr->last_state;
- old_state = save_buffer_ptr->last_old_state;
- out_string = save_buffer_ptr->last_out_string;
- memcpy(out_buf, save_buffer_ptr->last_out_buf, sizeof(out_buf));
- add_newlines = save_buffer_ptr->last_add_newlines;
- }
- #endif /* NeXT .include feature */
-
- #ifdef TEST
-
- const char md_comment_chars[] = "|";
- const char md_line_comment_chars[] = "#";
-
- int
- get(
- void)
- {
- return(getc(stdin));
- }
-
- void
- unget(
- int ch)
- {
- ungetc(ch, stdin);
- }
-
- void
- main(
- int argc,
- char *argv[],
- char *envp[])
- {
- int ch;
-
- while((ch = do_scrub_next_char(get, unget)) != EOF)
- putc(ch, stdout);
- }
-
- void
- as_warn(
- const char *format,
- ...)
- {
- va_list ap;
-
- va_start(ap, format);
- vfprintf(stderr, format, ap);
- fprintf(stderr, "\n");
- va_end(ap);
- }
- #endif /* TEST */
-