home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 196.lha / APP / app.c < prev    next >
C/C++ Source or Header  |  1988-12-27  |  9KB  |  409 lines

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