home *** CD-ROM | disk | FTP | other *** search
/ back2roots/padua / padua.7z / padua / lang / app20.lzh / app.c next >
Encoding:
C/C++ Source or Header  |  1990-07-09  |  9.8 KB  |  448 lines

  1. /* app.c - 68000 assembly pre-processor
  2.  *
  3.  * written by Karl Lehenbauer (uunet!sugar!karl or karl@sugar.hackercorp.com)
  4.  * original release Dec-08-1988
  5.  *
  6.  * PUBLIC DOMAIN -- no warranties of usefulness, suitabilitiy, correctness
  7.  *
  8.  * Jan-09-1990    Brett Bourbin (Selgus Limited) changed input/output file
  9.  *        handling, incorrect text strings and added the dbra construct.
  10.  *
  11.  * April-28-1990  Release 2.0
  12.  *  Rewrote filename-handling code to provide the -o option with backward
  13.  *   compatibility. Updated the docs plus converted to ANSI C.
  14.  */
  15.  
  16. #include <stdio.h>
  17. #include <assert.h>
  18.  
  19. #include "app.pro"
  20.  
  21. #define YES 1
  22. #define NO 0
  23.  
  24. #define MATCH 0
  25.  
  26. int current_nest_level = -1;
  27. int master_label_number = 0;
  28. unsigned int line_number = 0;
  29.  
  30. char *label;
  31. char *opcode;
  32. char *operands;
  33. char *comment;
  34.  
  35. char *input_filename, *input_extension, *output_filename;
  36.  
  37. panic(char *s)
  38. {
  39.     fprintf(stderr,"app: %s at line %d\n",s,line_number);
  40.     fclose(stdout);
  41.     unlink(output_filename);
  42.     exit(1);
  43. }
  44.  
  45. /* given a pointer to a line, make the global character pointers "label",
  46.  * "opcode", "operands" and "comment" point to the various fields within
  47.  * the line, or NULL for any that aren't present.  Note that crackline
  48.  * butchers the line up by writing null bytes into it.
  49.  */
  50. crackline(char *s)
  51. {
  52.     register char *p = s;
  53.  
  54.     label = NULL;
  55.     opcode = NULL;
  56.     operands = NULL;
  57.     comment = NULL;
  58.  
  59.     /* suck up leading blanks */
  60.     while ((*p == ' ') || (*p == '\t'))
  61.         p++;
  62.  
  63.     /* if end of line, return -- it's an empty line */
  64.     if (*p == '\0')
  65.         return;
  66.  
  67.     /* if the first nonblank char is a semicolon, it's a comment */
  68.     if (*p == ';')
  69.     {
  70.         comment = s;
  71.         return;
  72.     }
  73.  
  74.     /* if the very first char isn't blank (and we already know it's
  75.        not a semicolon), it's a label
  76.      */
  77.     if ((*s != ' ') && (*s != '\t'))
  78.     {
  79.         label = s;
  80.         p = s + 1;
  81.         while (*p != ' ' && *p != '\t' && *p != '\0') p++;
  82.         if ((*p == ' ') || (*p == '\t'))
  83.         {
  84.             *p = '\0';
  85.             p++;
  86.         }
  87.         else
  88.             return;
  89.     }
  90.     else    /* there isn't a label, suck up spaces to next parm */
  91.     {
  92.         p = s;
  93.         while ((*p == ' ' || *p == '\t')) p++;
  94.         if (*p == '\0')
  95.             return;
  96.     }
  97.  
  98.     /* if the next parm is a comment, assign and we're done */
  99.     if (*p == ';')
  100.     {
  101.         comment = p;
  102.         return;
  103.     }
  104.  
  105.     /* we're at the opcode, assign it and terminate with \0 if spaces
  106.      * follow, else we're done */
  107.     opcode = p;
  108.     while (*p != ' ' && *p != '\t' && *p != '\0') p++;
  109.     if ((*p == ' ') || (*p == '\t'))
  110.     {
  111.         *p = '\0';
  112.         p++;
  113.     }
  114.     else
  115.         return;
  116.  
  117.     /* if the next parm is a comment, assign and we're done */
  118.     if (*p == ';')
  119.     {
  120.         comment = p;
  121.         return;
  122.     }
  123.  
  124.     operands = p;
  125.     while (*p != ' ' && *p != '\t' && *p != '\0') p++;
  126.     if ((*p == ' ') || (*p == '\t'))
  127.     {
  128.         *p = '\0';
  129.         p++;
  130.     }
  131.     else
  132.         return;
  133.  
  134.     comment = p;
  135.  
  136. }
  137.  
  138. #ifdef DEBUG
  139. dumpit(void)
  140. {
  141.     printf("label: %s, opcode %s, operands %s, comment %s\n",label,opcode,operands,comment);
  142. }
  143. #endif
  144.  
  145. char s[255], ssave[255];
  146.  
  147. #define IF_STATEMENT_TYPE 1
  148. #define ELSE_STATEMENT_TYPE 2
  149. #define DO_STATEMENT_TYPE 3
  150.  
  151. #define MAX_NESTING_LEVELS 32
  152.  
  153. struct nesting_context
  154. {
  155.     int construct_type;
  156.     int label_number;
  157.     int second_label_number;
  158. };
  159.  
  160. struct nesting_context nesting_data[MAX_NESTING_LEVELS];
  161.  
  162. /* push - push a nesting construct context, executed on .if and .do */
  163. push(int new_construct_type,int label,int second_label)
  164. {
  165.     struct nesting_context *np;
  166.  
  167.     if (++current_nest_level >= MAX_NESTING_LEVELS)
  168.         panic("too many nesting levels");
  169.  
  170.     np = &nesting_data[current_nest_level];
  171.     np->construct_type = new_construct_type;
  172.     np->label_number = label;
  173.     np->second_label_number = second_label;
  174. }
  175.  
  176. /* pop - discard the top nesting context, checking for underflow
  177.  *  called when conditionals have been successfully closed
  178.  */
  179. pop(void)
  180. {
  181.     if (current_nest_level >= 0)
  182.         --current_nest_level;
  183.     else
  184.         panic("'endif', 'enddo' or 'dbra' without a matching 'if' or 'do'");
  185. }
  186.  
  187. /* generate and return new label number */
  188. newlabel(void)
  189. {
  190.     return(master_label_number++);
  191. }
  192.  
  193. /* structure in support of reversing the sense of conditionals */
  194. struct condition_code_struct
  195. {
  196.     char *condition;
  197.     char *reverse_condition;
  198. };
  199.  
  200. #define N_CONDITION_TYPES 14
  201.  
  202. struct condition_code_struct condition_code_array[N_CONDITION_TYPES] =
  203. {
  204.     {"ne", "eq"},
  205.     {"eq", "ne"},
  206.     {"lt", "ge"},
  207.     {"ge", "lt"},
  208.     {"le", "gt"},
  209.     {"gt", "le"},
  210.     {"cc", "cs"},
  211.     {"cs", "cc"},
  212.     {"vc", "vs"},
  213.     {"vs", "vc"},
  214.     {"hi", "ls"},
  215.     {"ls", "hi"},
  216.     {"pl", "mi"},
  217.     {"mi", "pl"},
  218. };
  219.  
  220. /* given a pointer to text containing a condition code, returns the 
  221.  * a pointer to text containing a condition with reverse sense of
  222.  * the one passed as an argument. Bombs if the sense doesn't make sense
  223.  */
  224. char *reverse_sense_of(char *s)
  225. {
  226.     struct condition_code_struct *ccp;
  227.     int i;
  228.  
  229.     for (i = 0, ccp = condition_code_array; i < N_CONDITION_TYPES; i++, ccp++)
  230.  
  231.         if (strcmp(s,ccp->condition) == MATCH)
  232.             return(ccp->reverse_condition);
  233.  
  234.     panic("invalid condition code in 'if', 'elseif', 'while' or 'until'");
  235. }
  236.  
  237. /* print the label name corresponding to the number specified, should be
  238.  * called in more places in the program where printf is used instead, so
  239.  * you have to change it in several places if you want to change what the
  240.  * labels look like
  241.  */
  242. print_label(int i)
  243. {
  244.     printf("L%d\n",i);
  245. }
  246.  
  247. /* to prevent parsing every line, looks_promising is a quick hack to see
  248.  * if its a line we're interested in or not.  If the line doesn't have
  249.  * a period as the first non-space or tab char, it's not promising, so
  250.  * we don't crack the line with the full blown line parses.  This is a
  251.  * performance hack.
  252.  */
  253. looks_promising(char *s)
  254. {
  255.     while (*s != '\0')
  256.     {
  257.         if (*s == '.')
  258.             return(YES);
  259.  
  260.         if (*s != ' ' && *s != '\t')
  261.             return(NO);
  262.  
  263.         s++;
  264.     }
  265.     return(NO);
  266. }
  267.  
  268. usage()
  269. {
  270.     fprintf(stderr,"\nThis program converts high-level structured assembly code\n");
  271.     fprintf(stderr,"into regular assembly code.  See the README file for details.\n\n");
  272.     fprintf(stderr,"usage:  app [ -o outputfile] filename.app\n");
  273.     fprintf(stderr," (if -o is not specified, .app extension is required\n");
  274.     fprintf(stderr,"  and output will have a .asm extension).\n\n");
  275.     fprintf(stderr,"Hackercorp, 3918 Panorama, Missouri City, TX 77459 USA\n");
  276.     fprintf(stderr,"tel# 713-438-4964, Usenet: uunet!sugar!karl\n");
  277.     fprintf(stderr,"Internet/BITNET: karl@sugar.hackercorp.com\n\n");
  278.     exit(1);
  279. }
  280.  
  281. int main(int argc,char *argv[])
  282. {
  283.     fprintf(stderr,"Hackercorp public domain 68000 assembly preprocessor 2.0 28-April-1990\n");
  284.  
  285.     if (argc == 4)
  286.     {
  287.         if (strcmp(argv[1],"-o") != MATCH)
  288.             usage();
  289.  
  290.         output_filename = argv[2];
  291.         input_filename = argv[3];
  292.     }
  293.     else if (argc == 2)
  294.     {
  295.         input_filename = argv[1];
  296.         output_filename = NULL;
  297.     }
  298.     else
  299.         usage();
  300.  
  301.     if (!output_filename)
  302.     {
  303.         input_extension = input_filename + strlen(input_filename) - 4;
  304.         if (strcmp(".app",input_extension) != MATCH)
  305.             usage();
  306.     }
  307.  
  308.     if (freopen(input_filename,"r",stdin) == NULL)
  309.     {
  310.         perror(input_filename);
  311.         exit(5);
  312.     }
  313.  
  314.     /* create output filename if necessary, by overwriting input name */
  315.     if (!output_filename)
  316.     {
  317.         strcpy(input_extension,".asm");
  318.         output_filename = input_filename;
  319.     }
  320.  
  321.     if (freopen(output_filename,"w",stdout) == NULL)
  322.     {
  323.         perror(output_filename);
  324.         exit(5);
  325.     }
  326.  
  327.     preprocess_file();
  328.     return(0);
  329. }
  330.  
  331. preprocess_file(void)
  332. {
  333.     struct nesting_context *np;
  334.     int i;
  335.  
  336.     /* for all lines in the file */
  337.     while (gets(s) != NULL)
  338.     {
  339.         line_number++;    /* count the line */
  340.  
  341.         /* if it's not promising, copy it to output and go on */
  342.         if (!looks_promising(s))
  343.         {
  344.             printf("%s\n",s);
  345.             goto more;
  346.         }
  347.  
  348.         strcpy(ssave,s);
  349.         crackline(s);
  350.  
  351.         if (strcmp(opcode,".if") == MATCH)
  352.         {
  353.             printf("\tb%s\tL%d\n",reverse_sense_of(operands),i = newlabel());
  354.             push(IF_STATEMENT_TYPE,i,-1);
  355.         }
  356.         else if (strcmp(opcode,".else") == MATCH)
  357.         {
  358.             np = &nesting_data[current_nest_level];
  359.  
  360.             if (np->construct_type != IF_STATEMENT_TYPE)
  361.                 panic("'else' without 'if'");
  362.  
  363.             printf("\tbra\tL%d\n",i = newlabel());
  364.             /* print the label from the top context */
  365.             print_label(np->label_number);
  366.             np->label_number = i;
  367.             np->construct_type = ELSE_STATEMENT_TYPE;
  368.         }
  369.         else if (strcmp(opcode,".endif") == MATCH)
  370.         {
  371.             np = &nesting_data[current_nest_level];
  372.  
  373.             if ((np->construct_type != IF_STATEMENT_TYPE)
  374.               && (np->construct_type != ELSE_STATEMENT_TYPE))
  375.                 panic("'endif' without 'if' or 'else'");
  376.  
  377.             print_label(np->label_number);
  378.             pop();
  379.         }
  380.         else if (strcmp(opcode,".elseif") == MATCH)
  381.         {
  382.             np = &nesting_data[current_nest_level];
  383.  
  384.             if (np->construct_type != IF_STATEMENT_TYPE)
  385.                 panic("'else' without 'if'");
  386.  
  387.             printf("\tbra\tL%d\n",i = newlabel());
  388.             /* print the label from the top context */
  389.             print_label(np->label_number);
  390.             np->label_number = i;
  391.             printf("\tb%s\tL%d\n",reverse_sense_of(operands),i);
  392.         }
  393.         else if (strcmp(opcode,".do") == MATCH)
  394.         {
  395.             print_label(i = newlabel());
  396.             push(DO_STATEMENT_TYPE,i,newlabel());
  397.         }
  398.         else if (strcmp(opcode,".while") == MATCH)
  399.         {
  400.             np = &nesting_data[current_nest_level];
  401.  
  402.             if (np->construct_type != DO_STATEMENT_TYPE)
  403.                 panic("'while' without 'do'");
  404.  
  405.             printf("\tb%s\tL%d\n",reverse_sense_of(operands),np->second_label_number);
  406.         }
  407.         else if (strcmp(opcode,".enddo") == MATCH)
  408.         {
  409.             np = &nesting_data[current_nest_level];
  410.  
  411.             if (np->construct_type != DO_STATEMENT_TYPE)
  412.                 panic("'enddo' without 'do'");
  413.  
  414.             printf("\tbra\tL%d\n",np->label_number);
  415.             print_label(np->second_label_number);
  416.             pop();
  417.  
  418.         }
  419.         else if (strcmp(opcode,".dbra") == MATCH)
  420.         {
  421.             np = &nesting_data[current_nest_level];
  422.  
  423.             if (np->construct_type != DO_STATEMENT_TYPE)
  424.                 panic("'dbra' without 'do'");
  425.  
  426.             printf("\tdbra\t%s,L%d\n",operands,np->label_number);
  427.             print_label(np->second_label_number);
  428.             pop();
  429.  
  430.         }
  431.         else if (strcmp(opcode,".until") == MATCH)
  432.         {
  433.             np = &nesting_data[current_nest_level];
  434.  
  435.             if (np->construct_type != DO_STATEMENT_TYPE)
  436.                 panic("'until' without 'do'");
  437.  
  438.             printf("\tb%s\tL%d\n",operands,np->second_label_number);
  439.         }
  440.         else
  441.             printf("%s\n",ssave);
  442.     more: ;
  443.     }
  444.     if (current_nest_level >= 0)
  445.         panic("didn't close all your control structures");
  446. }
  447.  
  448.