home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / listings / v_07_03 / v7n3105b.txt < prev    next >
Text File  |  1989-03-17  |  8KB  |  346 lines

  1.  
  2. #include <stdio.h>
  3. #include <ctype.h>
  4.  
  5. #define MAX_LINE 32
  6. #define MAXCP MAX_LINE - 1
  7.  
  8. #define SKIP 1
  9. #define ECHO 2
  10.  
  11. #define YES 1
  12. #define NO 0
  13.  
  14. #define PREAMBLE 1
  15. #define CODE 2
  16. #define MACHINE 3
  17. #define SEMI 4
  18. #define SCANNER 5
  19. #define NAME 6
  20. #define RTN_TOK 7
  21. #define TRANS 8
  22. #define END 9
  23. #define TYPE 10
  24. #define BRACE 11
  25.  
  26. #define ACCEPT(n,word) if ((ltok=ntok()) != word) report(n, "word")
  27.  
  28. /* functions declared in this file*/
  29. int ntok();
  30. void gen_tab_hd(), gen_tab_end();
  31. void gen_fsm_def(char *, char *, char *);
  32. void semi_cd(int);
  33. void echo_code();
  34. void report(int, char *);
  35.  
  36. /* globally available data structures */
  37. char lexval[MAX_LINE];
  38. int line_no, char_no;
  39.  
  40. int main()
  41. {
  42. int ltok;
  43. int count;
  44. int tabsize;
  45. long filemark;
  46.  
  47.  
  48. char scan_name[MAX_LINE];
  49. char rtn_name[MAX_LINE];
  50. char fsm_name[MAX_LINE];
  51.  
  52. line_no = 1; /* initialize globals */
  53. char_no = 1;
  54. tabsize = 0;
  55. lexval[0] = '\0';
  56.  
  57. ACCEPT(10,PREAMBLE);   /* accept PREAMBLE keyword      */
  58.      /* get table def*/
  59.    printf("#include \"fsm.h\"\n\n"); 
  60.    printf("\n/* Preamble */\n");
  61.    echo_code();   /* and following code block */
  62.  
  63. ACCEPT(40,SCANNER);/* accept SCANNER keyword   */
  64. ACCEPT(45,NAME);   /* collect and save name    */
  65.    strncpy(scan_name, lexval, MAXCP);
  66. ACCEPT(47,SEMI);
  67.  
  68. ACCEPT(30,MACHINE);/* accept MACHINE keyword   */
  69. ACCEPT(35,NAME);   /* and save fsm name        */
  70.    strcpy(fsm_name,lexval,MAXCP);
  71. ACCEPT(37,SEMI);   /* accept statement term.   */
  72.  
  73. ACCEPT(50,RTN_TOK); /* accept RETURN keyword    */
  74. ACCEPT(55,NAME);    /* collect and save name    */
  75.    strncpy(rtn_name, lexval, MAXCP);
  76. ACCEPT(57,SEMI);
  77.  
  78. ACCEPT(90,TYPE);    /* accept TYPE keyword      */
  79. printf("\ntypedef ");
  80. semi_cd(ECHO);      /* copy through type def    */
  81. printf(";\n");
  82. ACCEPT(97,SEMI);
  83.  
  84. ACCEPT(60,TRANS);   /* accept TRANSITIONS keyword */
  85.    count = 0;  /* used to enumerate defines   */
  86.  
  87. printf("\n\n/*Defines for Symbol names*/\n");
  88. while ((ltok=ntok()) == NAME) { 
  89.    printf("#define %s %d\n",lexval,count++);
  90.    }
  91. if (ltok != SEMI) report(65,"SEMI");
  92. tabsize = count; /* save symbol count */
  93.  
  94. filemark = ftell(stdin);   /* so we can make a second pass */
  95. count = 0;
  96. printf("\n\n/* Defines for State Names */\n");
  97. while ((ltok = ntok()) == NAME){
  98.    printf("#define %s %d\n",lexval,count++);
  99.    semi_cd(SKIP);
  100.    ACCEPT(75,SEMI);
  101.    }
  102. if (count == 0) report(70,"STATE NAME"); 
  103. else if (ltok != CODE) report(80,"CODE");
  104.  
  105. /* now rewind and process table definition */
  106. fseek(stdin,filemark,0);
  107. gen_tab_hd(tabsize);
  108. while ((ltok = ntok()) == NAME){
  109.    printf("\n  { /*%s*/",lexval);
  110.    semi_cd(ECHO);
  111.    ACCEPT(77,SEMI);
  112.    --count;
  113.    if (count !=0)
  114.       printf("},\n",lexval);
  115.    else
  116.       printf("}\n",lexval);
  117.    }
  118. if (count != 0) report(78,"STATE NAME 2ND SCAN");
  119. if (ltok != CODE) report(82,"CODE, 2ND SCAN");
  120. printf("\n  };\n"); /* close table */
  121. gen_fsm_def(fsm_name, scan_name, rtn_name);
  122.  
  123. /* now process CODE -- keyword already scanned */
  124.    printf("\n/* Code Section */\n");
  125.    echo_code();   /* and following code block */
  126. ACCEPT(90,END);
  127.  
  128.  
  129. exit(0);
  130. }
  131.  
  132. /* error handler -- print error message and exit 
  133.    Input is error number and expected token
  134.    Reads globals line_no and char_no for position
  135.    information, and lexval for bad input token.
  136. */
  137.  
  138. void report(num, msg)
  139.    int num;
  140.    char *msg;
  141. {
  142. printf("fsmgen:\n");
  143. printf("  Error %d at character %d on line %d\n",
  144.           num,char_no,line_no);
  145. printf("  Expected %s, found %s\n",msg,lexval);
  146. exit(num);
  147. }
  148.  
  149.  
  150. void gen_tab_hd(wid)
  151. int wid;
  152. {
  153. printf("\n\n/*Transition Table*/\n");
  154. printf("struct trans s_table[][%d] = {\n",wid);
  155. }
  156.  
  157. void gen_fsm_def(name, scan, rtn)
  158.    char *name;
  159.    char *scan; 
  160.    char *rtn;
  161.    
  162. {
  163. printf("\nstatic int state, token;");
  164. printf("\n\n/* Code for main()*/\n");
  165. printf("FSMTYPE %s()\n",name);
  166. printf("{\n");
  167. printf("state = start;\n");
  168. printf("token = EMPTY;\n\n");
  169. printf("while (state != stop){\n");
  170. printf("  TRACE;\n");
  171. printf("  token = %s();\n",scan);
  172. printf("  (*s_table[state][token].act)();\n");
  173. printf("  state = s_table[state][token].nextstate;\n");
  174. printf("  }\n");
  175. printf("return %s;\n",rtn);
  176. printf("}\n\n");
  177. }
  178.  
  179. /* scans everything up to the next semicolon. 
  180.    If mode is ECHO, all scanned text is copied to 
  181.    standard output. Otherwise it is just consumed.
  182. */
  183. void semi_cd(mode)
  184.    int mode;
  185. {
  186. int ch;
  187.  
  188. while((ch = getchar())!=';'){
  189.    if (ch == EOF) return;
  190.    if (ch == '\n'){
  191.       line_no++;
  192.       char_no = 1;
  193.       }
  194.    else char_no++;
  195.    if (mode == ECHO) putchar(ch);
  196.    }
  197. ungetc(ch,stdin); /*save the semi */
  198. }
  199.  
  200. /*
  201.   scan the next token. A token is an arbitrary string of characters
  202.   terminated by a semi-colon or whitespace. If the terminator is
  203.   whitespace it is consumed. If it is a semi-colon, it is not
  204.   consumed!
  205.  
  206.   Returns: the type of the token.
  207.   Side Effects:
  208.      the token text is captured in lexval.
  209.  
  210. */
  211.  
  212. int ntok()
  213. {
  214. char *ptr = lexval;
  215. char ch;
  216.  
  217. /* skip leading whitespace */
  218. while (isspace(ch = getchar()));
  219. if (ch == EOF) return EOF;
  220. ungetc(ch,stdin); /* position for while */
  221. /* collect token text */
  222. while (is_term(ch = getchar()) == NO){
  223. /*   printf("in ntok while read %c\n",ch);*/
  224.    if (ch == '\n'){
  225.       line_no++;
  226.       char_no = 1;
  227.       }
  228.    else char_no++;
  229.    *ptr++ = ch;          
  230.    }
  231.  
  232. *ptr = '\0';   
  233.   /* consume the semi if it's the next token */
  234.   /*else fix-up special cases */
  235. if ((ch == ';') && (lexval[0] == '\0')) {
  236.   strncpy(lexval,";",2);
  237.   return SEMI;
  238.   }
  239. if ((ch == '{') && (lexval[0] == '\0')) {
  240.   strncpy(lexval,"{",2);
  241.   return BRACE;
  242.   }
  243.   /* leave the semi or brace if  they
  244.     just terminates something else*/
  245. else if ((ch == ';')||(ch== '{')) ungetc(ch,stdin);  
  246.  
  247.  
  248. if (!strncmp("PREAMBLE",lexval,8)) return PREAMBLE;
  249. if (!strncmp("CODE",lexval,4)) return CODE;
  250. if (!strncmp("MACHINE",lexval,7)) return MACHINE;
  251. if (!strncmp("SCANNER",lexval,7)) return SCANNER;
  252. if (!strncmp("RETURNS",lexval,7)) return RTN_TOK;
  253. if (!strncmp("TRANSITIONS",lexval,11)) return TRANS;
  254. if (!strncmp("END",lexval,3)) return END;
  255. if (!strncmp("TYPE",lexval,4)) return TYPE;
  256. return NAME;
  257. }
  258.  
  259. int is_term(c)
  260.    char c;
  261. {
  262. if (isspace(c) || (c == ';') || (c=='{')) return YES;
  263. else return NO;
  264. }
  265.  
  266.  
  267. /* accept a curly brace enclosed block of C code.
  268.    Doesn't check code syntax, just relies on properties
  269.    to find closing curly brace. Consumes all input up
  270.    to and including the closing curly brace.
  271.    Echoes all accepted text to standard output.
  272.    No provision for trigraphs.
  273. */
  274. void echo_code()
  275. {
  276. int state;
  277. int ch;
  278. int depth;
  279.  
  280. depth = 0;
  281. if ((ch = getchar()) != '{'){
  282.     lexval[0] = ch;
  283.     lexval[1] = '\0';
  284.     report(101,"{ code");
  285.     }
  286.  
  287. plain: 
  288.    switch(ch=getchar()){
  289.       case '\'': putchar(ch);
  290.                  goto squote;
  291.       case '\"': putchar(ch);
  292.                  goto dquote;
  293.       case '/':  putchar(ch);
  294.                  goto cmnt1;
  295.       case EOF : strncpy(lexval,"EOF",4);
  296.                  return;
  297.       case '{' : depth += 1;
  298.                  putchar(ch);
  299.                  goto plain;
  300.       case '}' : if (depth == 0) return;
  301.                  depth -= 1;
  302.       default:   putchar(ch);
  303.                  goto plain;
  304.       }
  305. squote:
  306.    putchar(ch=getchar());
  307.    switch(ch){
  308.       case '\\': ch = getchar();
  309.                  putchar(ch);
  310.                  goto squote;
  311.       case '\'': goto plain;
  312.       default:   goto squote;
  313.       }
  314. dquote:
  315.    ch = getchar();
  316.    putchar(ch);
  317.    switch(ch){
  318.       case '\"': goto plain;
  319.       case '\\': ch=getchar();
  320.                  putchar(ch);
  321.       default:   goto dquote;
  322.       }
  323. /* found opening slash of possible comment */
  324. cmnt1:
  325.    ch = getchar();
  326.    putchar(ch);
  327.    if (ch == '/') goto cmnt1;
  328.    else if (ch != '*') goto plain;
  329.  
  330. /* inside comment */
  331. cmnt2:
  332.    ch = getchar();
  333.    putchar(ch);
  334.    if (ch != '*') goto cmnt2;
  335.  
  336. /* found opening * of comment terminator */
  337. cmnt3:
  338.    ch = getchar();
  339.    putchar(ch);
  340.    if (ch == '*') goto cmnt3;
  341.    else if (ch != '/') goto cmnt2;
  342.    else goto plain;
  343.  
  344. }
  345.  
  346.