home *** CD-ROM | disk | FTP | other *** search
- /* app.c - 68000 assembly pre-processor
- *
- * written by Karl Lehenbauer (uunet!sugar!karl or karl@sugar.uu.net) 12-8-88
- * PUBLIC DOMAIN -- no warranties of usefulness, suitabilitiy, correctness
- *
- * There're README and make files that go along with this. If you don't
- * have them, you've been ripped off.
- */
-
- #include <stdio.h>
- #include <assert.h>
-
- #define YES 1
- #define NO 0
-
- #define MATCH 0
-
- int current_nest_level = -1;
- int master_label_number = 0;
- unsigned int line_number = 0;
-
- char *label;
- char *opcode;
- char *operands;
- char *comment;
-
- char *input_filename, *input_extension, *output_filename;
-
- panic(s)
- char *s;
- {
- fprintf(stderr,"app: %s at line %d\n",s,line_number);
- fclose(stdout);
- unlink(output_filename);
- exit(1);
- }
-
- /* given a pointer to a line, make the global character pointers "label",
- * "opcode", "operands" and "comment" point to the various fields within
- * the line, or NULL for any that aren't present. Note that crackline
- * butchers the line up by writing null bytes into it.
- */
- crackline(s)
- register char *s;
- {
- register char *p = s;
-
- label = NULL;
- opcode = NULL;
- operands = NULL;
- comment = NULL;
-
- /* suck up leading blanks */
- while ((*p == ' ') || (*p == '\t'))
- p++;
-
- /* if end of line, return -- it's an empty line */
- if (*p == '\0')
- return;
-
- /* if the first nonblank char is a semicolon, it's a comment */
- if (*p == ';')
- {
- comment = s;
- return;
- }
-
- /* if the very first char isn't blank (and we already know it's
- not a semicolon), it's a label
- */
- if ((*s != ' ') && (*s != '\t'))
- {
- label = s;
- p = s + 1;
- while (*p != ' ' && *p != '\t' && *p != '\0') p++;
- if ((*p == ' ') || (*p == '\t'))
- {
- *p = '\0';
- p++;
- }
- else
- return;
- }
- else /* there isn't a label, suck up spaces to next parm */
- {
- p = s;
- while ((*p == ' ' || *p == '\t')) p++;
- if (*p == '\0')
- return;
- }
-
- /* if the next parm is a comment, assign and we're done */
- if (*p == ';')
- {
- comment = p;
- return;
- }
-
- /* we're at the opcode, assign it and terminate with \0 if spaces
- * follow, else we're done */
- opcode = p;
- while (*p != ' ' && *p != '\t' && *p != '\0') p++;
- if ((*p == ' ') || (*p == '\t'))
- {
- *p = '\0';
- p++;
- }
- else
- return;
-
- /* if the next parm is a comment, assign and we're done */
- if (*p == ';')
- {
- comment = p;
- return;
- }
-
- operands = p;
- while (*p != ' ' && *p != '\t' && *p != '\0') p++;
- if ((*p == ' ') || (*p == '\t'))
- {
- *p = '\0';
- p++;
- }
- else
- return;
-
- comment = p;
-
- }
-
- #ifdef DEBUG
- dumpit()
- {
- printf("label: %s, opcode %s, operands %s, comment %s\n",label,opcode,operands,comment);
- }
- #endif
-
- char s[255], ssave[255];
-
- #define IF_STATEMENT_TYPE 1
- #define ELSE_STATEMENT_TYPE 2
- #define DO_STATEMENT_TYPE 3
-
- #define MAX_NESTING_LEVELS 32
-
- struct nesting_context
- {
- int construct_type;
- int label_number;
- int second_label_number;
- };
-
- struct nesting_context nesting_data[MAX_NESTING_LEVELS];
-
- /* push - push a nesting construct context, executed on .if and .do */
- push(new_construct_type,label,second_label)
- int new_construct_type, label,second_label;
- {
- struct nesting_context *np;
-
- if (++current_nest_level >= MAX_NESTING_LEVELS)
- panic("too many nesting levels");
-
- np = &nesting_data[current_nest_level];
- np->construct_type = new_construct_type;
- np->label_number = label;
- np->second_label_number = second_label;
- }
-
- /* pop - discard the top nesting context, checking for underflow
- * called when conditionals have been successfully closed
- */
- pop()
- {
- if (current_nest_level >= 0)
- --current_nest_level;
- else
- panic("'endif' or 'enddo' without a matching 'if' or 'do'");
- }
-
- /* generate and return new label number */
- newlabel()
- {
- return(master_label_number++);
- }
-
- /* structure in support of reversing the sense of conditionals */
- struct condition_code_struct
- {
- char *condition;
- char *reverse_condition;
- };
-
- #define N_CONDITION_TYPES 14
-
- struct condition_code_struct condition_code_array[N_CONDITION_TYPES] =
- {
- {"ne", "eq"},
- {"eq", "ne"},
- {"lt", "ge"},
- {"ge", "lt"},
- {"le", "gt"},
- {"gt", "le"},
- {"cc", "cs"},
- {"cs", "cc"},
- {"vc", "vs"},
- {"vs", "vc"},
- {"hi", "ls"},
- {"ls", "hi"},
- {"pl", "mi"},
- {"mi", "pl"},
- };
-
- /* given a pointer to text containing a condition code, returns the
- * a pointer to text containing a condition with reverse sense of
- * the one passed as an argument. Bombs if the sense doesn't make sense
- */
- char *reverse_sense_of(s)
- char *s;
- {
- struct condition_code_struct *ccp;
- int i;
-
- for (i = 0, ccp = condition_code_array; i < N_CONDITION_TYPES; i++, ccp++)
-
- if (strcmp(s,ccp->condition) == MATCH)
- return(ccp->reverse_condition);
-
- panic("invalid condition code in 'if', 'elseif', 'while' or 'until'");
- }
-
- /* print the label name corresponding to the number specified, should be
- * called in more places in the program where printf is used instead, so
- * you have to change it in several places if you want to change what the
- * labels look like
- */
- print_label(i)
- int i;
- {
- printf("L%d\n",i);
- }
-
- /* to prevent parsing every line, looks_promising is a quick hack to see
- * if its a line we're interested in or not. If the line doesn't have
- * a period as the first non-space or tab char, it's not promising, so
- * we don't crack the line with the full blown line parses. This is a
- * performance hack.
- */
- looks_promising(s)
- char *s;
- {
- while (*s != '\0')
- {
- if (*s == '.')
- return(YES);
-
- if (*s != ' ' && *s != '\t')
- return(NO);
-
- s++;
- }
- return(NO);
- }
-
- usage()
- {
- fprintf(stderr,"usage: app filename.app\n");
- exit(1);
- }
-
- main(argc,argv)
- int argc;
- char *argv[];
- {
- fprintf(stderr,"Hackercorp public domain 68000 assembly preprocessor 0.0 12-9-88\n");
-
- if (argc != 2)
- usage();
-
- input_filename = argv[1];
- input_extension = input_filename + strlen(input_filename) - 4;
- if (strcmp(".app",input_extension) != MATCH)
- usage();
-
- if (freopen(input_filename,"r",stdin) == NULL)
- {
- perror(input_filename);
- exit(5);
- }
-
- /* kludgily create output filename */
- output_filename = input_filename;
- strcpy(input_extension,".asm");
-
- if (freopen(input_filename,"w",stdout) == NULL)
- {
- perror(input_filename);
- exit(5);
- }
-
- preprocess_file();
- }
-
- preprocess_file()
- {
- struct nesting_context *np;
- int i;
-
- /* for all lines in the file */
- while (gets(s) != NULL)
- {
- line_number++; /* count the line */
-
- /* if it's not promising, copy it to output and go on */
- if (!looks_promising(s))
- {
- printf("%s\n",s);
- goto more;
- }
-
- strcpy(ssave,s);
- crackline(s);
-
- if (strcmp(opcode,".if") == MATCH)
- {
- printf("\tb%s\tL%d\n",reverse_sense_of(operands),i = newlabel());
- push(IF_STATEMENT_TYPE,i,-1);
- }
- else if (strcmp(opcode,".else") == MATCH)
- {
- np = &nesting_data[current_nest_level];
-
- if (np->construct_type != IF_STATEMENT_TYPE)
- panic("'else' without 'if'");
-
- printf("\tbra\tL%d\n",i = newlabel());
- /* print the label from the top context */
- print_label(np->label_number);
- np->label_number = i;
- np->construct_type = ELSE_STATEMENT_TYPE;
- }
- else if (strcmp(opcode,".endif") == MATCH)
- {
- np = &nesting_data[current_nest_level];
-
- if ((np->construct_type != IF_STATEMENT_TYPE)
- && (np->construct_type != ELSE_STATEMENT_TYPE))
- panic("'endif' without 'if' or 'else'");
-
- print_label(np->label_number);
- pop();
- }
- else if (strcmp(opcode,".elseif") == MATCH)
- {
- np = &nesting_data[current_nest_level];
-
- if (np->construct_type != IF_STATEMENT_TYPE)
- panic("'else' without 'if'");
-
- printf("\tbra\tL%d\n",i = newlabel());
- /* print the label from the top context */
- print_label(np->label_number);
- np->label_number = i;
- printf("\tb%s\tL%d\n",reverse_sense_of(operands),i);
- }
- else if (strcmp(opcode,".do") == MATCH)
- {
- print_label(i = newlabel());
- push(DO_STATEMENT_TYPE,i,newlabel());
- }
- else if (strcmp(opcode,".while") == MATCH)
- {
- np = &nesting_data[current_nest_level];
-
- if (np->construct_type != DO_STATEMENT_TYPE)
- panic("'while' without 'do'");
-
- printf("\tb%s\tL%d\n",reverse_sense_of(operands),np->second_label_number);
- }
- else if (strcmp(opcode,".enddo") == MATCH)
- {
- np = &nesting_data[current_nest_level];
-
- if (np->construct_type != DO_STATEMENT_TYPE)
- panic("'enddo' without 'do'");
-
- printf("\tbra\tL%d\n",np->label_number);
- print_label(np->second_label_number);
- pop();
-
- }
- else if (strcmp(opcode,".until") == MATCH)
- {
- np = &nesting_data[current_nest_level];
-
- if (np->construct_type != DO_STATEMENT_TYPE)
- panic("'while' without 'do'");
-
- printf("\tb%s\tL%d\n",operands,np->second_label_number);
- }
- else
- printf("%s\n",ssave);
- more: ;
- }
- if (current_nest_level >= 0)
- panic("didn't close all your control structures");
- }
-