Chinaunix首页 | 论坛 | 博客
  • 博客访问: 222340
  • 博文数量: 136
  • 博客积分: 2919
  • 博客等级: 少校
  • 技术积分: 1299
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-11 09:08
文章分类

全部博文(136)

文章存档

2013年(1)

2011年(135)

我的朋友

分类: 系统运维

2011-05-05 08:46:04

The next step (a small one) is to add "memory" to hoc1, to make hoc2. The memory is 26 variables, named a through z. We 'll also add some error handling. If you try hoc1, you'll recognize that its approach to syntax errors is to print message and die, and its treatment of arithmetic errors like division by zero is reprehensible.

The lexical analyzer yylex has to recognize letters as variables; the grammar has to include productions of the form

  1. expr: VAR
  2.         | VAR '=' expr

An expression can contain an assignment, which permits multiple assignments like
  1. x = y = z = 0

The easiest way to store the values of the variables is in a 26-element array;the single-letter variable name can be used to index tye array. But if the grammar is to process both variable names and values in the same stack, yacc has to be told that its stack contains a union of a double and an int, not just a double. This is done with a %union declaration near the top. A #define or a typedef is fine for setting the stack to a basic type like double, but the %union mechanism is required for union types because yacc checks for consistency in expressions like $$=$2.

Error handling comes in several pieces. The obvious one is a test for a zero divisor; if one occurs, an error routine execerror is called.

A second test is to catch the "floating point exception" signal that occurs what a floating point number overflows. The signal is set in main.

The final part of error recovery is the addition of a production for error. "error" is a reserved work in a yacc grammar; it provides a way to anticipate and recover from a syntax error.
  1. %{
  2. double mem[26]; /* memory for variables 'a'..'z' */
  3. %}
  4. %union { /* stack type */
  5.     double val; /* actual value */
  6.     int index; /* index into mem[] */
  7. }
  8. %token <val> NUMBER
  9. %token <index> VAR
  10. %type <val> expr
  11. %right '='
  12. %left '+' '-' /* left associative, same precedence */
  13. %left '*' '/' /* left assoc., higher precedence */
  14. %left UNARYMINUS /* new */
  15. %%
  16. list: /* nothing */
  17.       | list '\n'
  18.       | list expr '\n' {printf("\t%.8g\n", $2);}
  19.       | list error '\n' {yyerrok;}
  20.       ;
  21. expr: NUMBER
  22.       | VAR {$$ = mem[$1]; }
  23.       | VAR '=' expr {$$=mem[$1]=$3;}
  24.       | '-' expr %prec UNARYMINUS {$$ = -$2; } /* new */
  25.       | expr '+' expr {$$ = $1 + $3;}
  26.       | expr '-' expr {$$ = $1 - $3;}
  27.       | expr '*' expr {$$ = $1 * $3;}
  28.       | expr '/' expr {
  29.      if ($3 == 0.0)
  30.      execerror("division by zero", "");
  31.      $$ = $1 / $3;}
  32.       | '(' expr ')' { $$ = $2;}
  33.       ;
  34. %%
  35. /* end of grammar */

  36. #include <stdio.h>
  37. #include <ctype.h>
  38. #include <signal.h>
  39. #include <setjmp.h>
  40. jmp_buf begin;
  41. char *progname; /* for error messages */
  42. int lineno = 1;
  43. int fpecatch();
  44. main(int argc, char* argv[])
  45. {
  46.     progname = argv[0];
  47.     setjmp(begin);
  48.     signal(SIGFPE, fpecatch);
  49.     yyparse();
  50. }

  51. execerror(char *s, char *t) /* recover from run-time error */
  52. {
  53.     warning(s, t);
  54.     longjmp(begin, 0);
  55. }

  56. fpecatch() /* catch floating point exceptions */
  57. {
  58.     execerror("floating point exeption", (char *)0);
  59. }
  60. yylex()
  61. {
  62.     int c;
  63.     while ((c=getchar()) == ' ' || c == '\t')
  64.      ;
  65.     if (c == EOF)
  66.      return 0;
  67.     if (c == '.' || isdigit(c))
  68.     {
  69.         ungetc(c, stdin);
  70.         scanf("%lf", &yylval.val);
  71.         return NUMBER;
  72.     }
  73.     if (islower(c))
  74.     {
  75.      yylval.index = c - 'a'; /* ASCII only */
  76.      return VAR;
  77.     }
  78.     if (c == '\n')
  79.      lineno++;
  80.     return c;
  81. }

  82. yyerror(char *s)
  83. {
  84.     warning (s, (char *)0);
  85. }

  86. warning (char *s, char *t)
  87. {
  88.     fprintf(stderr, "%s: %s", progname, s);
  89.     if (t)
  90.      fprintf(stderr, "%s", t);
  91.     fprintf(stderr, " near line %d\n", lineno);
  92. }

阅读(550) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~