⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bison_5.htm

📁 Lex和Yacc的Manual
💻 HTM
📖 第 1 页 / 共 3 页
字号:
2.3000000000%</PRE><P>Note that multiple assignment and nested function calls are permitted.</P><H3><A NAME="SEC30" HREF="index.html#SEC30">Declarations for <CODE>mfcalc</CODE></A></H3><P>Here are the C and Bison declarations for the multi-function calculator.</P><PRE>%{#include &#60;math.h&#62;  /* For math functions, cos(), sin(), etc. */#include "calc.h"  /* Contains definition of `symrec'        */%}%union {double     val;  /* For returning numbers.                   */symrec  *tptr;   /* For returning symbol-table pointers      */}%token &#60;val&#62;  NUM        /* Simple double precision number   */%token &#60;tptr&#62; VAR FNCT   /* Variable and Function            */%type  &#60;val&#62;  exp%right '='%left '-' '+'%left '*' '/'%left NEG     /* Negation--unary minus */%right '^'    /* Exponentiation        *//* Grammar follows */%%</PRE><P>The above grammar introduces only two new features of the Bison language.These features allow semantic values to have various data types(see section <A HREF="bison_6.html#SEC45">More Than One Value Type</A>).</P><P>The <CODE>%union</CODE> declaration specifies the entire list of possible types;this is instead of defining <CODE>YYSTYPE</CODE>.  The allowable types are nowdouble-floats (for <CODE>exp</CODE> and <CODE>NUM</CODE>) and pointers to entries inthe symbol table.  See section <A HREF="bison_6.html#SEC52">The Collection of Value Types</A>.</P><P>Since values can now have various types, it is necessary to associate atype with each grammar symbol whose semantic value is used.  These symbolsare <CODE>NUM</CODE>, <CODE>VAR</CODE>, <CODE>FNCT</CODE>, and <CODE>exp</CODE>.  Theirdeclarations are augmented with information about their data type (placedbetween angle brackets).</P><P>The Bison construct <CODE>%type</CODE> is used for declaring nonterminal symbols,just as <CODE>%token</CODE> is used for declaring token types.  We have not used<CODE>%type</CODE> before because nonterminal symbols are normally declaredimplicitly by the rules that define them.  But <CODE>exp</CODE> must be declaredexplicitly so we can specify its value type.  See section <A HREF="bison_6.html#SEC53">Nonterminal Symbols</A>.</P><H3><A NAME="SEC31" HREF="index.html#SEC31">Grammar Rules for <CODE>mfcalc</CODE></A></H3><P>Here are the grammar rules for the multi-function calculator.Most of them are copied directly from <CODE>calc</CODE>; three rules,those which mention <CODE>VAR</CODE> or <CODE>FNCT</CODE>, are new.</P><PRE>input:   /* empty */        | input line;line:          '\n'        | exp '\n'   { printf ("\t%.10g\n", $1); }        | error '\n' { yyerrok;                  };exp:      NUM                { $$ = $1;                         }        | VAR                { $$ = $1-&#62;value.var;              }        | VAR '=' exp        { $$ = $3; $1-&#62;value.var = $3;     }        | FNCT '(' exp ')'   { $$ = (*($1-&#62;value.fnctptr))($3); }        | exp '+' exp        { $$ = $1 + $3;                    }        | exp '-' exp        { $$ = $1 - $3;                    }        | exp '*' exp        { $$ = $1 * $3;                    }        | exp '/' exp        { $$ = $1 / $3;                    }        | '-' exp  %prec NEG { $$ = -$2;                        }        | exp '^' exp        { $$ = pow ($1, $3);               }        | '(' exp ')'        { $$ = $2;                         };/* End of grammar */%%</PRE><H3><A NAME="SEC32" HREF="index.html#SEC32">The <CODE>mfcalc</CODE> Symbol Table</A></H3><P><A NAME="IDX48"></A></P><P>The multi-function calculator requires a symbol table to keep track of thenames and meanings of variables and functions.  This doesn't affect thegrammar rules (except for the actions) or the Bison declarations, but itrequires some additional C functions for support.</P><P>The symbol table itself consists of a linked list of records.  Itsdefinition, which is kept in the header <TT>`calc.h'</TT>, is as follows.  Itprovides for either functions or variables to be placed in the table.</P><PRE>/* Data type for links in the chain of symbols.      */struct symrec{  char *name;  /* name of symbol                     */  int type;    /* type of symbol: either VAR or FNCT */  union {    double var;           /* value of a VAR          */    double (*fnctptr)();  /* value of a FNCT         */  } value;  struct symrec *next;    /* link field              */};typedef struct symrec symrec;/* The symbol table: a chain of `struct symrec'.     */extern symrec *sym_table;symrec *putsym ();symrec *getsym ();</PRE><P>The new version of <CODE>main</CODE> includes a call to <CODE>init_table</CODE>, afunction that initializes the symbol table.  Here it is, and<CODE>init_table</CODE> as well:</P><PRE>#include &#60;stdio.h&#62;main (){  init_table ();  yyparse ();}yyerror (s)  /* Called by yyparse on error */     char *s;{  printf ("%s\n", s);}struct init{  char *fname;  double (*fnct)();};struct init arith_fncts[]  = {      "sin", sin,      "cos", cos,      "atan", atan,      "ln", log,      "exp", exp,      "sqrt", sqrt,      0, 0    };/* The symbol table: a chain of `struct symrec'.  */symrec *sym_table = (symrec *)0;init_table ()  /* puts arithmetic functions in table. */{  int i;  symrec *ptr;  for (i = 0; arith_fncts[i].fname != 0; i++)    {      ptr = putsym (arith_fncts[i].fname, FNCT);      ptr-&#62;value.fnctptr = arith_fncts[i].fnct;    }}</PRE><P>By simply editing the initialization list and adding the necessary includefiles, you can add additional functions to the calculator.</P><P>Two important functions allow look-up and installation of symbols in thesymbol table.  The function <CODE>putsym</CODE> is passed a name and the type(<CODE>VAR</CODE> or <CODE>FNCT</CODE>) of the object to be installed.  The object islinked to the front of the list, and a pointer to the object is returned.The function <CODE>getsym</CODE> is passed the name of the symbol to look up.  Iffound, a pointer to that symbol is returned; otherwise zero is returned.</P><PRE>symrec *putsym (sym_name,sym_type)     char *sym_name;     int sym_type;{  symrec *ptr;  ptr = (symrec *) malloc (sizeof (symrec));  ptr-&#62;name = (char *) malloc (strlen (sym_name) + 1);  strcpy (ptr-&#62;name,sym_name);  ptr-&#62;type = sym_type;  ptr-&#62;value.var = 0; /* set value to 0 even if fctn.  */  ptr-&#62;next = (struct symrec *)sym_table;  sym_table = ptr;  return ptr;}symrec *getsym (sym_name)     char *sym_name;{  symrec *ptr;  for (ptr = sym_table; ptr != (symrec *) 0;       ptr = (symrec *)ptr-&#62;next)    if (strcmp (ptr-&#62;name,sym_name) == 0)      return ptr;  return 0;}</PRE><P>The function <CODE>yylex</CODE> must now recognize variables, numeric values, andthe single-character arithmetic operators.  Strings of alphanumericcharacters with a leading nondigit are recognized as either variables orfunctions depending on what the symbol table says about them.</P><P>The string is passed to <CODE>getsym</CODE> for look up in the symbol table.  Ifthe name appears in the table, a pointer to its location and its type(<CODE>VAR</CODE> or <CODE>FNCT</CODE>) is returned to <CODE>yyparse</CODE>.  If it is notalready in the table, then it is installed as a <CODE>VAR</CODE> using<CODE>putsym</CODE>.  Again, a pointer and its type (which must be <CODE>VAR</CODE>) isreturned to <CODE>yyparse</CODE>.</P><P>No change is needed in the handling of numeric values and arithmeticoperators in <CODE>yylex</CODE>.</P><PRE>#include &#60;ctype.h&#62;yylex (){  int c;  /* Ignore whitespace, get first nonwhite character.  */  while ((c = getchar ()) == ' ' || c == '\t');  if (c == EOF)    return 0;  /* Char starts a number =&#62; parse the number.         */  if (c == '.' || isdigit (c))    {      ungetc (c, stdin);      scanf ("%lf", &#38;yylval.val);      return NUM;    }  /* Char starts an identifier =&#62; read the name.       */  if (isalpha (c))    {      symrec *s;      static char *symbuf = 0;      static int length = 0;      int i;      /* Initially make the buffer long enough         for a 40-character symbol name.  */      if (length == 0)        length = 40, symbuf = (char *)malloc (length + 1);      i = 0;      do        {          /* If buffer is full, make it bigger.        */          if (i == length)            {              length *= 2;              symbuf = (char *)realloc (symbuf, length + 1);            }          /* Add this character to the buffer.         */          symbuf[i++] = c;          /* Get another character.                    */          c = getchar ();        }      while (c != EOF &#38;&#38; isalnum (c));      ungetc (c, stdin);      symbuf[i] = '\0';      s = getsym (symbuf);      if (s == 0)        s = putsym (symbuf, VAR);      yylval.tptr = s;      return s-&#62;type;    }  /* Any other character is a token by itself.        */  return c;}</PRE><P>This program is both powerful and flexible. You may easily add newfunctions, and it is a simple job to modify this code to install predefinedvariables such as <CODE>pi</CODE> or <CODE>e</CODE> as well.</P><H2><A NAME="SEC33" HREF="index.html#SEC33">Exercises</A></H2><P><A NAME="IDX49"></A></P><OL><LI>Add some new functions from <TT>`math.h'</TT> to the initialization list.<LI>Add another array that contains constants and their values.  Thenmodify <CODE>init_table</CODE> to add these constants to the symbol table.It will be easiest to give the constants type <CODE>VAR</CODE>.<LI>Make the program report an error if the user refers to anuninitialized variable in any way except to store a value in it.</OL><HR>Go to the <A HREF="bison_1.html">first</A>, <A HREF="bison_4.html">previous</A>, <A HREF="bison_6.html">next</A>, <A HREF="bison_15.html">last</A> section, <A HREF="index.html">table of contents</A>.</BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -