home *** CD-ROM | disk | FTP | other *** search
- /* app.c - 68000 assembly pre-processor
- *
- * written by Karl Lehenbauer (uunet!sugar!karl or karl@sugar.hackercorp.com)
- * original release Dec-08-1988
- *
- * PUBLIC DOMAIN -- no warranties of usefulness, suitabilitiy, correctness
- *
- * Jan-09-1990 Brett Bourbin (Selgus Limited) changed input/output file
- * handling, incorrect text strings and added the dbra construct.
- *
- * April-28-1990 Release 2.0
- * Rewrote filename-handling code to provide the -o option with backward
- * compatibility. Updated the docs plus converted to ANSI C.
- */
-
- #include <stdio.h>
- #include <assert.h>
-
- #include "app.pro"
-
- #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(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(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(void)
- {
- 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(int new_construct_type,int label,int 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(void)
- {
- if (current_nest_level >= 0)
- --current_nest_level;
- else
- panic("'endif', 'enddo' or 'dbra' without a matching 'if' or 'do'");
- }
-
- /* generate and return new label number */
- newlabel(void)
- {
- 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(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(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(char *s)
- {
- while (*s != '\0')
- {
- if (*s == '.')
- return(YES);
-
- if (*s != ' ' && *s != '\t')
- return(NO);
-
- s++;
- }
- return(NO);
- }
-
- usage()
- {
- fprintf(stderr,"\nThis program converts high-level structured assembly code\n");
- fprintf(stderr,"into regular assembly code. See the README file for details.\n\n");
- fprintf(stderr,"usage: app [ -o outputfile] filename.app\n");
- fprintf(stderr," (if -o is not specified, .app extension is required\n");
- fprintf(stderr," and output will have a .asm extension).\n\n");
- fprintf(stderr,"Hackercorp, 3918 Panorama, Missouri City, TX 77459 USA\n");
- fprintf(stderr,"tel# 713-438-4964, Usenet: uunet!sugar!karl\n");
- fprintf(stderr,"Internet/BITNET: karl@sugar.hackercorp.com\n\n");
- exit(1);
- }
-
- int main(int argc,char *argv[])
- {
- fprintf(stderr,"Hackercorp public domain 68000 assembly preprocessor 2.0 28-April-1990\n");
-
- if (argc == 4)
- {
- if (strcmp(argv[1],"-o") != MATCH)
- usage();
-
- output_filename = argv[2];
- input_filename = argv[3];
- }
- else if (argc == 2)
- {
- input_filename = argv[1];
- output_filename = NULL;
- }
- else
- usage();
-
- if (!output_filename)
- {
- 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);
- }
-
- /* create output filename if necessary, by overwriting input name */
- if (!output_filename)
- {
- strcpy(input_extension,".asm");
- output_filename = input_filename;
- }
-
- if (freopen(output_filename,"w",stdout) == NULL)
- {
- perror(output_filename);
- exit(5);
- }
-
- preprocess_file();
- return(0);
- }
-
- preprocess_file(void)
- {
- 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,".dbra") == MATCH)
- {
- np = &nesting_data[current_nest_level];
-
- if (np->construct_type != DO_STATEMENT_TYPE)
- panic("'dbra' without 'do'");
-
- printf("\tdbra\t%s,L%d\n",operands,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("'until' 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");
- }
-
-