"I am a person who works hard and plays hard."

Yuan Wei
Second Year Graduate Student Department of Computer Science
University of Virginia Charlottesville, VA 22903
Email: yw3f@cs.virginia.edu


Source Code Analysis

Main Page   Compound List   File List   Compound Members   File Members  

libexo.c

Go to the documentation of this file.
00001 /*
00002  * libexo.c - EXO library main line routines
00003  *
00004  * This file is a part of the SimpleScalar tool suite written by
00005  * Todd M. Austin as a part of the Multiscalar Research Project.
00006  *
00007  * The tool suite is currently maintained by Doug Burger and Todd M. Austin.
00008  *
00009  * Copyright (C) 1997 by Todd M. Austin
00010  *
00011  * This source file is distributed "as is" in the hope that it will be
00012  * useful.  The tool set comes with no warranty, and no author or
00013  * distributor accepts any responsibility for the consequences of its
00014  * use. 
00015  *
00016  * Everyone is granted permission to copy, modify and redistribute
00017  * this tool set under the following conditions:
00018  *
00019  *    This source code is distributed for non-commercial use only. 
00020  *    Please contact the maintainer for restrictions applying to 
00021  *    commercial use.
00022  *
00023  *    Permission is granted to anyone to make or distribute copies
00024  *    of this source code, either as received or modified, in any
00025  *    medium, provided that all copyright notices, permission and
00026  *    nonwarranty notices are preserved, and that the distributor
00027  *    grants the recipient permission for further redistribution as
00028  *    permitted by this document.
00029  *
00030  *    Permission is granted to distribute this file in compiled
00031  *    or executable form under the same conditions that apply for
00032  *    source code, provided that either:
00033  *
00034  *    A. it is accompanied by the corresponding machine-readable
00035  *       source code,
00036  *    B. it is accompanied by a written offer, with no time limit,
00037  *       to give anyone a machine-readable copy of the corresponding
00038  *       source code in return for reimbursement of the cost of
00039  *       distribution.  This written offer must permit verbatim
00040  *       duplication by anyone, or
00041  *    C. it is distributed by someone who received only the
00042  *       executable form, and is accompanied by a copy of the
00043  *       written offer of source code that they received concurrently.
00044  *
00045  * In other words, you are welcome to use, share and improve this
00046  * source file.  You are forbidden to forbid anyone else to use, share
00047  * and improve what you give them.
00048  *
00049  * INTERNET: dburger@cs.wisc.edu
00050  * US Mail:  1210 W. Dayton Street, Madison, WI 53706
00051  *
00052  * $Id: libexo.c,v 1.1.1.1 2000/05/26 15:21:53 taustin Exp $
00053  *
00054  * $Log: libexo.c,v $
00055  * Revision 1.1.1.1  2000/05/26 15:21:53  taustin
00056  * SimpleScalar Tool Set
00057  *
00058  *
00059  * Revision 1.2  1999/12/31 18:54:50  taustin
00060  * quad_t naming conflicts removed
00061  *
00062  * Revision 1.1  1998/08/27 08:55:06  taustin
00063  * Initial revision
00064  *
00065  * Revision 1.1  1998/08/27 08:51:36  taustin
00066  * Initial revision
00067  *
00068  *
00069  */
00070 
00071 #include <stdio.h>
00072 #include <stdlib.h>
00073 #include <stdarg.h>
00074 #include <ctype.h>
00075 #include <limits.h>
00076 #include <errno.h>
00077 #include <assert.h>
00078 
00079 #include "../host.h"
00080 #include "../misc.h"
00081 #include "../machine.h"
00082 #include "libexo.h"
00083 
00084 /* EXO term classes print strings */
00085 char *exo_class_str[ec_NUM] = {
00086   "integer",
00087   "address",
00088   "float",
00089   "char",
00090   "string"
00091   "list",
00092   "array",
00093   "token",
00094   "blob"
00095 };
00096 
00097 /* return the value of an escape sequence, ESCAPE is a pointer to the first
00098    character following '\', sets NEXT to first character after escape */
00099 /* A2.5.2 */
00100 static int
00101 intern_escape(char *esc, char **next)
00102 {
00103   int c, value, empty, count;
00104 
00105   switch (c = *esc++) {
00106   case 'x':
00107     /* \xhh hex value */
00108     value = 0;
00109     empty = TRUE;
00110     while (1)
00111       {
00112         c = *esc++;
00113         if (!(c >= 'a' && c <= 'f')
00114             && !(c >= 'A' && c <= 'F')
00115             && !(c >= '0' && c <= '9'))
00116           {
00117             esc--;
00118             break;
00119           }
00120         value *=16;
00121         if (c >= 'a' && c <= 'f')
00122           value += c - 'a' + 10;
00123         if (c >= 'A' && c <= 'F')
00124           value += c - 'A' + 10;
00125         if (c >= '0' && c <= '9')
00126           value += c - '0';
00127         empty = FALSE;
00128       }
00129     if (empty)
00130       fatal("\\x used with no trailing hex digits");
00131     break;
00132 
00133   case '0': case '1': case '2': case '3':
00134   case '4': case '5': case '6': case '7':
00135     /* \ooo octal value */
00136     value = 0;
00137     count = 0;
00138     while ((c <= '7') && (c >= '0') && (count++ < 3))
00139       {
00140         value = (value * 8) + (c - '0');
00141         c = *esc++;
00142       }
00143     esc--;
00144     break;
00145 
00146   case '\\':
00147   case '\'':
00148   case '"':
00149     value = c;
00150     break;
00151 
00152   case 'n':
00153     value = '\n';
00154     break;
00155 
00156   case 't':
00157     value = '\t';
00158     break;
00159 
00160   case 'r':
00161     value = '\r';
00162     break;
00163 
00164   case 'f':
00165     value = '\f';
00166     break;
00167 
00168   case 'b':
00169     value = '\b';
00170     break;
00171 
00172   case 'a':
00173     value = '\a';
00174     break;
00175 
00176   case 'v':
00177     value = '\v';
00178     break;
00179 
00180   case '?':
00181     value = c;
00182     break;
00183 
00184   case '(':
00185   case '{':
00186   case '[':
00187   case '%':
00188     value = c;
00189     warn("non-ANSI escape sequence `\\%c'", c);
00190     break;
00191 
00192   default:
00193     fatal("unknown escape, '\\' followed by char %x (`%c')", (int)c, c);
00194   }
00195 
00196   if (*next)
00197     *next = esc;
00198 
00199   return value;
00200 }
00201 
00202 /* return the value of an character literal sequence */
00203 /* A2.5.2 */
00204 static int
00205 intern_char(char *s, char **next)
00206 {
00207   unsigned char value;
00208 
00209   if (s[0] != '\'' || s[strlen(s)-1] != '\'')
00210     panic("mal-formed string constant");
00211 
00212   if (s[1] != '\\')
00213     {
00214       value = (unsigned)s[1];
00215       if (s[2] != '\'')
00216         panic("mal-formed string constant");
00217       if (next)
00218         *next = s + 2;
00219     }
00220   else
00221     {
00222       /* escaped char constant */
00223       value = intern_escape(s+2, next);
00224     }
00225 
00226   /* map to a signed char value */
00227   value = (signed int)((unsigned char)((unsigned char)((unsigned int)value)));
00228 
00229   if (UCHAR_MAX < value)
00230     fatal("character constant out of range");
00231 
00232   return value;
00233 }
00234 
00235 static void
00236 print_char(unsigned char c, FILE *stream)
00237 {
00238   switch (c)
00239     {
00240     case '\n':
00241       fprintf(stream, "\\n");
00242       break;
00243 
00244     case '\\':
00245       fprintf(stream, "\\\\");
00246       break;
00247 
00248     case '\'':
00249       fprintf(stream, "\\'");
00250       break;
00251 
00252     case '\t':
00253       fprintf(stream, "\\t");
00254       break;
00255 
00256     case '\r':
00257       fprintf(stream, "\\r");
00258       break;
00259 
00260     case '\f':
00261       fprintf(stream, "\\f");
00262       break;
00263 
00264     case '\b':
00265       fprintf(stream, "\\b");
00266       break;
00267 
00268     case '\a':
00269       fprintf(stream, "\\a");
00270       break;
00271 
00272     case '\v':
00273       fprintf(stream, "\\v");
00274       break;
00275 
00276     default:
00277       if (isprint(c))
00278         fprintf(stream, "%c", c);
00279       else
00280         fprintf(stream, "\\x%02x", c);
00281     }
00282 }
00283 
00284 /* expand all escapes in string STR, return pointer to allocation w/ result */
00285 static char *
00286 intern_string(char *str)
00287 {
00288   char *s, *istr;
00289 
00290   /* resulting string cannot be longer than STR */
00291   s = istr = malloc(strlen(str)+1);
00292 
00293   if (!str || !*str || *str != '\"') /* " */
00294     panic("mal-formed string constant");
00295 
00296   /* skip `"' */ /* " */
00297   str++;
00298 
00299   while (*str)
00300     {
00301       if (*str == '\\')
00302         *s++ = intern_escape(str+1, &str);
00303       else
00304         {
00305           /* A2.6 */
00306           if (*str == '\n')
00307             warn("ANSI C forbids newline in character constant");
00308           /* A2.6 */
00309           if (*str == '"' && str[1] != '\0')
00310             panic("encountered `\"' embedded in string constant");
00311 
00312           if (*str != '\"') /* " */
00313             *s++ = *str;
00314           str++;
00315         }
00316     }
00317   *s = '\0';
00318   return istr;
00319 }
00320 
00321 static void
00322 print_string(unsigned char *s, FILE *stream)
00323 {
00324   while (*s)
00325     {
00326       print_char(*s, stream);
00327       s++;
00328     }
00329 }
00330 
00331 /* bogus token value */
00332 #define TOKEN_BOGON             0
00333 
00334 static int token_id = TOKEN_BOGON + 1;
00335 
00336 #define TOKEN_HASH_SIZE         1024
00337 struct exo_token_t *token_hash[TOKEN_HASH_SIZE];
00338 
00339 /* hash a string */
00340 static unsigned long
00341 hash_str(char *s)
00342 {
00343   unsigned h = 0;
00344   while (*s)
00345     h = (h << 1) + *s++;
00346   return (h % TOKEN_HASH_SIZE);
00347 }
00348 
00349 /* intern token TOKEN_STR */
00350 struct exo_token_t *
00351 exo_intern(char *token_str)             /* string to intern */
00352 {
00353   int index;
00354   struct exo_token_t *ent;
00355 
00356   index = hash_str(token_str);
00357 
00358   for (ent=token_hash[index]; ent != NULL; ent=ent->next)
00359     {
00360       if (!strcmp(token_str, ent->str))
00361         {
00362           /* got a match, return token entry */
00363           return ent;
00364         }
00365     }
00366 
00367   /* not found, create a new entry */
00368   ent = (struct exo_token_t *)calloc(1, sizeof(struct exo_token_t));
00369   if (!ent)
00370     fatal("out of virtual memory");
00371 
00372   ent->str = mystrdup(token_str);
00373   ent->token = token_id++;
00374   ent->next = token_hash[index];
00375   token_hash[index] = ent;
00376 
00377   return ent;
00378 }
00379 
00380 /* intern token TOKEN_STR as value TOKEN */
00381 struct exo_token_t *
00382 exo_intern_as(char *token_str,          /* string to intern */
00383               int token)                /* internment value */
00384 {
00385   struct exo_token_t *ent;
00386 
00387 #if 0
00388   if (token_id > token)
00389     fatal("token value is already in use");
00390 #endif
00391 
00392   ent = exo_intern(token_str);
00393   /* overide the default value */
00394   ent->token = token;
00395 
00396 #if 0
00397   if (ent->token != token)
00398     fatal("symbol `%s' was previously interned", token_str);
00399 #endif
00400 
00401   return ent;
00402 }
00403 
00404 /* allocate an EXO node, fill in its type */
00405 static struct exo_term_t *
00406 exo_alloc(enum exo_class_t ec)
00407 {
00408   struct exo_term_t *exo;
00409 
00410   exo = (struct exo_term_t *)calloc(1, sizeof(struct exo_term_t));
00411   if (!exo)
00412     fatal("out of virtual memory");
00413   exo->next = NULL;
00414   exo->ec = ec;
00415 
00416   return exo;
00417 }
00418 
00419 
00420 /*
00421  * create a new EXO term, usage:
00422  *
00423  *      exo_new(ec_integer, (exo_integer_t)<int>);
00424  *      exo_new(ec_address, (exo_integer_t)<int>);
00425  *      exo_new(ec_float, (exo_float_t)<float>);
00426  *      exo_new(ec_char, (int)<char>);
00427  *      exo_new(ec_string, "<string>");
00428  *      exo_new(ec_list, <list_ent>..., NULL);
00429  *      exo_new(ec_array, <size>, <array_ent>..., NULL);
00430  *      exo_new(ec_token, "<token>"); 
00431 */
00432 struct exo_term_t *
00433 exo_new(enum exo_class_t ec, ...)
00434 {
00435   struct exo_term_t *exo;
00436   va_list v;
00437   va_start(v, ec);
00438 
00439   exo = exo_alloc(ec);
00440   switch (ec)
00441     {
00442     case ec_integer:
00443       exo->as_integer.val = va_arg(v, exo_integer_t);
00444       break;
00445 
00446     case ec_address:
00447       exo->as_address.val = va_arg(v, exo_address_t);
00448       break;
00449 
00450     case ec_float:
00451       exo->as_float.val = va_arg(v, exo_float_t);
00452       break;
00453 
00454     case ec_char:
00455       exo->as_char.val = va_arg(v, int);
00456       break;
00457 
00458     case ec_string:
00459       {
00460         char *str;
00461 
00462         str = va_arg(v, char *);
00463         exo->as_string.str = (unsigned char *)mystrdup(str);
00464       }
00465       break;
00466 
00467     case ec_list:
00468       {
00469         struct exo_term_t *ent;
00470 
00471         exo->as_list.head = NULL;
00472         do {
00473           ent = va_arg(v, struct exo_term_t *);
00474           exo->as_list.head = exo_chain(exo->as_list.head, ent);
00475         } while (ent != NULL);
00476       }
00477       break;
00478 
00479     case ec_array:
00480       {
00481         int i;
00482         struct exo_term_t *ent;
00483 
00484         exo->as_array.size = va_arg(v, int);
00485         exo->as_array.array = (struct exo_term_t **)
00486           calloc(exo->as_array.size, sizeof(struct exo_term_t *));
00487         if (!exo->as_array.array)
00488           fatal("out of virtual memory");
00489         i = 0;
00490         do {
00491           ent = va_arg(v, struct exo_term_t *);
00492           if (ent != NULL)
00493             {
00494               if (i == exo->as_array.size)
00495                 fatal("array constructor overflow");
00496               SET_EXO_ARR(exo, i, ent);
00497             }
00498           i++;
00499         } while (ent != NULL);
00500       }
00501       break;
00502 
00503     case ec_token:
00504       {
00505         char *str;
00506 
00507         str = va_arg(v, char *);
00508         exo->as_token.ent = exo_intern(str);
00509       }
00510       break;
00511 
00512     case ec_blob:
00513       {
00514         unsigned size;
00515         unsigned char *data;
00516 
00517         size = va_arg(v, unsigned);
00518         data = va_arg(v, unsigned char *);
00519 
00520         exo->as_blob.size = size;
00521         exo->as_blob.data = malloc(size);
00522         if (data != NULL)
00523           memcpy(exo->as_blob.data, data, size);
00524         else
00525           memset(exo->as_blob.data, 0, size);
00526       }
00527       break;
00528 
00529     case ec_null:
00530       break;
00531 
00532     default:
00533       panic("bogus EXO class");
00534     }
00535 
00536   va_end(v);
00537   return exo;
00538 }
00539 
00540 /* release an EXO term */
00541 void
00542 exo_delete(struct exo_term_t *exo)
00543 {
00544   exo->next = NULL;
00545 
00546   switch (exo->ec)
00547     {
00548     case ec_integer:
00549       /* no extra storage */
00550       exo->as_integer.val = 0;
00551       break;
00552 
00553     case ec_address:
00554       /* no extra storage */
00555       exo->as_address.val = 0;
00556       break;
00557 
00558     case ec_float:
00559       /* no extra storage */
00560       exo->as_float.val = 0.0;
00561       break;
00562 
00563     case ec_char:
00564       /* no extra storage */
00565       exo->as_char.val = '\0';
00566       break;
00567 
00568     case ec_string:
00569       free(exo->as_string.str);
00570       exo->as_string.str = NULL;
00571       break;
00572 
00573     case ec_list:
00574       {
00575         struct exo_term_t *ent, *next_ent;
00576 
00577         for (ent=exo->as_list.head; ent != NULL; ent = next_ent)
00578           {
00579             next_ent = ent->next;
00580             exo_delete(ent);
00581           }
00582         exo->as_list.head = NULL;
00583       }
00584       break;
00585 
00586     case ec_array:
00587       {
00588         int i;
00589 
00590         for (i=0; i < exo->as_array.size; i++)
00591           {
00592             if (exo->as_array.array[i] != NULL)
00593               exo_delete(exo->as_array.array[i]);
00594           }
00595         free(exo->as_array.array);
00596         exo->as_array.array = NULL;
00597         exo->as_array.size = 0;
00598       }
00599       break;
00600 
00601     case ec_token:
00602       /* no extra storage */
00603       exo->as_token.ent = NULL;
00604       break;
00605 
00606     case ec_blob:
00607       /* free the blob data */
00608       free(exo->as_blob.data);
00609       exo->as_blob.data = NULL;
00610       break;
00611 
00612     case ec_null:
00613       /* no extra storage */
00614       break;
00615 
00616     default:
00617       panic("bogus EXO class");
00618     }
00619   exo->ec = (enum exo_class_t)0;
00620 
00621   /* release the node */
00622   free(exo);
00623 }
00624 
00625 /* chain two EXO lists together, FORE is attached on the end of AFT */
00626 struct exo_term_t *
00627 exo_chain(struct exo_term_t *fore, struct exo_term_t *aft)
00628 {
00629   struct exo_term_t *exo, *prev;
00630 
00631   if (!fore && !aft)
00632     return NULL;
00633 
00634   if (!fore)
00635     return aft;
00636 
00637   /* find the tail of FORE */
00638   for (prev=NULL,exo=fore; exo != NULL; prev=exo,exo=exo->next)
00639     /* nada */;
00640   assert(prev);
00641 
00642   /* link onto the tail of FORE */
00643   prev->next = aft;
00644 
00645   return fore;
00646 }
00647 
00648 /* copy an EXO node */
00649 struct exo_term_t *
00650 exo_copy(struct exo_term_t *exo)
00651 {
00652   struct exo_term_t *new_exo;
00653 
00654   /* NULL copy */
00655   if (!exo)
00656     return NULL;
00657 
00658   new_exo = exo_alloc(exo->ec);
00659   *new_exo = *exo;
00660 
00661   /* the next link is always blown away on a copy */
00662   new_exo->next = NULL;
00663 
00664   switch (new_exo->ec)
00665     {
00666     case ec_integer:
00667     case ec_address:
00668     case ec_float:
00669     case ec_char:
00670     case ec_string:
00671     case ec_list:
00672     case ec_token:
00673       /* no internal parts to copy */
00674       break;
00675 
00676     case ec_array:
00677       {
00678         int i;
00679 
00680         /* copy the array */
00681         new_exo->as_array.array = (struct exo_term_t **)
00682           calloc(new_exo->as_array.size, sizeof(struct exo_term_t *));
00683 
00684         for (i=0; i<new_exo->as_array.size; i++)
00685           {
00686             SET_EXO_ARR(new_exo, i, EXO_ARR(exo, i));
00687           }
00688       }
00689       break;
00690 
00691     case ec_blob:
00692       new_exo->as_blob.data = malloc(new_exo->as_array.size);
00693       memcpy(new_exo->as_blob.data, exo->as_blob.data, new_exo->as_array.size);
00694       break;
00695 
00696     default:
00697       panic("bogus EXO class");
00698     }
00699 
00700   return new_exo;
00701 }
00702 
00703 /* deep copy an EXO structure */
00704 struct exo_term_t *
00705 exo_deepcopy(struct exo_term_t *exo)
00706 {
00707   struct exo_term_t *new_exo;
00708 
00709   /* NULL copy */
00710   if (!exo)
00711     return NULL;
00712 
00713   new_exo = exo_copy(exo);
00714   switch (new_exo->ec)
00715     {
00716     case ec_integer:
00717     case ec_address:
00718     case ec_float:
00719     case ec_char:
00720     case ec_token:
00721       /* exo_copy() == exo_deepcopy() for these node classes */
00722       break;
00723 
00724     case ec_string:
00725       /* copy the referenced string */
00726       new_exo->as_string.str =
00727         (unsigned char *)mystrdup((char *)exo->as_string.str);
00728       break;
00729 
00730     case ec_list:
00731       /* copy all list elements */
00732       {
00733         struct exo_term_t *elt, *new_elt, *new_list;
00734 
00735         new_list = NULL;
00736         for (elt=new_exo->as_list.head; elt != NULL; elt=elt->next)
00737           {
00738             new_elt = exo_deepcopy(elt);
00739             new_list = exo_chain(new_list, new_elt);
00740           }
00741         new_exo->as_list.head = new_list;
00742       }
00743       break;
00744 
00745     case ec_array:
00746       /* copy all array elements */
00747       {
00748         int i;
00749 
00750         for (i=0; i<new_exo->as_array.size; i++)
00751           {
00752             SET_EXO_ARR(new_exo, i, exo_deepcopy(EXO_ARR(exo, i)));
00753           }
00754       }
00755       break;
00756 
00757     case ec_blob:
00758       new_exo->as_blob.data = malloc(new_exo->as_array.size);
00759       memcpy(new_exo->as_blob.data, exo->as_blob.data, new_exo->as_array.size);
00760       break;
00761 
00762     default:
00763       panic("bogus EXO class");
00764     }
00765 
00766   return new_exo;
00767 }
00768 
00769 /* print an EXO term */
00770 void
00771 exo_print(struct exo_term_t *exo, FILE *stream)
00772 {
00773   if (!stream)
00774     stream = stderr;
00775 
00776   switch (exo->ec)
00777     {
00778     case ec_integer:
00779       if (sizeof(exo_integer_t) == 4)
00780         myfprintf(stream, "%u", exo->as_integer.val);
00781       else
00782         myfprintf(stream, "%lu", exo->as_integer.val);
00783       break;
00784 
00785     case ec_address:
00786       if (sizeof(exo_address_t) == 4)
00787         myfprintf(stream, "0x%x", exo->as_integer.val);
00788       else
00789         myfprintf(stream, "0x%lx", exo->as_integer.val);
00790       break;
00791 
00792     case ec_float:
00793       fprintf(stream, "%f", exo->as_float.val);
00794       break;
00795 
00796     case ec_char:
00797       fprintf(stream, "'");
00798       print_char(exo->as_char.val, stream);
00799       fprintf(stream, "'");
00800       break;
00801 
00802     case ec_string:
00803       fprintf(stream, "\"");
00804       print_string(exo->as_string.str, stream);
00805       fprintf(stream, "\"");
00806       break;
00807 
00808     case ec_list:
00809       {
00810         struct exo_term_t *ent;
00811 
00812         fprintf(stream, "(");
00813         for (ent=exo->as_list.head; ent != NULL; ent=ent->next)
00814           {
00815             exo_print(ent, stream);
00816             if (ent->next)
00817               fprintf(stream, ", ");
00818           }
00819         fprintf(stream, ")");
00820       }
00821       break;
00822 
00823     case ec_array:
00824       {
00825         int i, last;
00826 
00827         /* search for last first non-NULL entry */
00828         for (last=exo->as_array.size-1; last >= 0; last--)
00829           {
00830             if (EXO_ARR(exo, last) != NULL)
00831               break;
00832           }
00833         /* LAST == index of last non-NULL array entry */
00834 
00835         fprintf(stream, "{%d}[", exo->as_array.size);
00836         for (i=0; i<exo->as_array.size && i <= last; i++)
00837           {
00838             if (exo->as_array.array[i] != NULL)
00839               exo_print(exo->as_array.array[i], stream);
00840             else
00841               fprintf(stream, " ");
00842             if (i != exo->as_array.size-1 && i != last)
00843               fprintf(stream, ", ");
00844           }
00845         fprintf(stream, "]");
00846       }
00847       break;
00848 
00849     case ec_token:
00850       fprintf(stream, "%s", exo->as_token.ent->str);
00851       break;
00852 
00853     case ec_blob:
00854       {
00855         int i, cr;
00856 
00857         fprintf(stream, "{%d}<\n", exo->as_blob.size);
00858         for (i=0; i < exo->as_blob.size; i++)
00859           {
00860             cr = FALSE;
00861             if (i != 0 && (i % 38) == 0)
00862               {
00863                 fprintf(stream, "\n");
00864                 cr = TRUE;
00865               }
00866             fprintf(stream, "%02x", exo->as_blob.data[i]);
00867           }
00868         if (!cr)
00869           fprintf(stream, "\n");
00870         fprintf(stream, ">");
00871       }
00872       break;
00873 
00874     default:
00875       panic("bogus EXO class");
00876     }
00877 }
00878 
00879 /* (f)lex external defs */
00880 extern int yylex(void);
00881 extern int yy_nextchar(void);
00882 extern char *yytext;
00883 extern FILE *yyin;
00884 
00885 static void
00886 exo_err(char *err)
00887 {
00888   extern int line;
00889 
00890   fprintf(stderr, "EXO parse error: line %d: %s\n", line, err);
00891   exit(1);
00892 }
00893 
00894 /* read one EXO term from STREAM */
00895 struct exo_term_t *
00896 exo_read(FILE *stream)
00897 {
00898   int tok;
00899   char tok_buf[1024], *endp;
00900   struct exo_term_t *ent = NULL;
00901   extern int errno;
00902   extern void yy_setstream(FILE *);
00903 
00904   /* make sure we have a valid stream */
00905   if (!stream)
00906     stream = stdin;
00907   yy_setstream(stream);
00908 
00909   /* make local copies of everything, allows arbitrary recursion */
00910   tok = yylex();
00911   strcpy(tok_buf, yytext);
00912 
00913   switch (tok)
00914     {
00915     case lex_integer:
00916       {
00917         exo_integer_t int_val;
00918 
00919         /* attempt integer conversion */
00920         errno = 0;
00921 #ifdef HOST_HAS_QWORD
00922         int_val = myatoq(tok_buf, &endp, /* parse base */10);
00923 #else /* !HOST_HAS_QWORD */
00924         int_val = strtoul(tok_buf, &endp, /* parse base */10);
00925 #endif /* HOST_HAS_QWORD */
00926         if (!errno && !*endp)
00927           {
00928             /* good conversion */
00929             ent = exo_new(ec_integer, int_val);
00930           }
00931         else
00932           exo_err("cannot parse integer literal");
00933       }
00934       break;
00935 
00936     case lex_address:
00937       {
00938         exo_address_t addr_val;
00939 
00940         /* attempt address conversion */
00941         errno = 0;
00942 #ifdef HOST_HAS_QWORD
00943         addr_val = myatoq(tok_buf, &endp, /* parse base */16);
00944 #else /* !HOST_HAS_QWORD */
00945         addr_val = strtoul(tok_buf, &endp, /* parse base */16);
00946 #endif /* HOST_HAS_QWORD */
00947         if (!errno && !*endp)
00948           {
00949             /* good conversion */
00950             ent = exo_new(ec_address, addr_val);
00951           }
00952         else
00953           exo_err("cannot parse address literal");
00954       }
00955       break;
00956 
00957     case lex_float:
00958       {
00959         exo_float_t float_val;
00960 
00961         /* attempt double conversion */
00962         errno = 0;
00963         float_val = strtod(tok_buf, &endp);
00964         if (!errno && !*endp)
00965           {
00966             /* good conversion */
00967             ent = exo_new(ec_float, float_val);
00968           }
00969         else
00970           exo_err("cannot parse floating point literal");
00971       }
00972       break;
00973 
00974     case lex_char:
00975       {
00976         int c;
00977 
00978         c = intern_char(tok_buf, &endp);
00979         if (!endp)
00980           exo_err("cannot convert character literal");
00981         ent = exo_new(ec_char, c);
00982       }
00983       break;
00984 
00985     case lex_string:
00986       {
00987         char *s;
00988 
00989         s = intern_string(tok_buf);
00990         ent = exo_new(ec_string, s);
00991         free(s);
00992       }
00993       break;
00994 
00995     case lex_token:
00996       ent = exo_new(ec_token, tok_buf);
00997       break;
00998 
00999     case lex_byte:
01000       exo_err("unexpected blob byte encountered");
01001       break;
01002 
01003     case '(':
01004       {
01005         struct exo_term_t *elt;
01006 
01007         ent = exo_new(ec_list, NULL);
01008 
01009         if (yy_nextchar() != ')')
01010           {
01011             /* not an empty list */
01012             do {
01013               elt = exo_read(stream);
01014               if (!elt)
01015                 exo_err("unexpected end-of-file");
01016               ent->as_list.head =
01017                 exo_chain(ent->as_list.head, elt);
01018 
01019               /* consume optional commas */
01020               if (yy_nextchar() == ',')
01021                 yylex();
01022             } while (yy_nextchar() != ')');
01023           }
01024 
01025         /* read tail delimiter */
01026         tok = yylex();
01027         if (tok != ')')
01028           exo_err("expected ')'");
01029       }
01030       break;
01031 
01032     case ')':
01033       exo_err("unexpected ')' encountered");
01034       break;
01035 
01036     case '<':
01037       exo_err("unexpected '<' encountered");
01038       break;
01039 
01040     case '>':
01041       exo_err("unexpected '>' encountered");
01042       break;
01043 
01044     case '{':
01045       {
01046         int cnt, size;
01047         struct exo_term_t *elt;
01048 
01049         /* get the size */
01050         elt = exo_read(stream);
01051         if (!elt || elt->ec != ec_integer)
01052           exo_err("badly formed array size");
01053 
01054         /* record the size of the array/blob */
01055         size = (int)elt->as_integer.val;
01056 
01057         /* done with the EXO integer */
01058         exo_delete(elt);
01059 
01060         /* read the array delimiters */
01061         tok = yylex();
01062         if (tok != '}')
01063           exo_err("expected '}'");
01064 
01065         tok = yylex();
01066         switch (tok)
01067           {
01068           case '[': /* array definition */
01069             /* allocate an array definition */
01070             ent = exo_new(ec_array, size, NULL);
01071 
01072             /* read until array is full or tail delimiter encountered */
01073             if (yy_nextchar() != ']')
01074               {
01075                 /* not an empty array */
01076                 cnt = 0;
01077                 do {
01078                   if (cnt == ent->as_array.size)
01079                     exo_err("too many initializers for array");
01080 
01081                   /* NULL element? */
01082                   if (yy_nextchar() == ',')
01083                     {
01084                       elt = NULL;
01085                     }
01086                   else
01087                     {
01088                       elt = exo_read(stream);
01089                       if (!elt)
01090                         exo_err("unexpected end-of-file");
01091                     }
01092                   SET_EXO_ARR(ent, cnt, elt);
01093                   cnt++;
01094 
01095                   /* consume optional commas */
01096                   if (yy_nextchar() == ',')
01097                     yylex();
01098                 } while (yy_nextchar() != ']');
01099               }
01100 
01101             /* read tail delimiter */
01102             tok = yylex();
01103             if (tok != ']')
01104               exo_err("expected ']'");
01105             break;
01106 
01107           case '<': /* blob definition */
01108             /* allocate an array definition */
01109             ent = exo_new(ec_blob, size, /* zero contents */NULL);
01110 
01111             /* read until blob is full */
01112             if (yy_nextchar() != '>')
01113               {
01114                 unsigned int byte_val;
01115 
01116                 /* not an empty array */
01117                 cnt = 0;
01118                 for (;;) {
01119                   /* read next blob byte */
01120                   tok = yylex();
01121 
01122                   if (tok == lex_byte)
01123                     {
01124                       if (cnt == ent->as_blob.size)
01125                         exo_err("too many initializers for blob");
01126 
01127                       /* attempt hex conversion */
01128                       errno = 0;
01129                       byte_val = strtoul(yytext, &endp, /* parse base */16);
01130                       if (errno != 0 || *endp != '\0')
01131                         exo_err("cannot parse blob byte literal");
01132                       if (byte_val > 255)
01133                         panic("bogus byte value");
01134                       ent->as_blob.data[cnt] = byte_val;
01135                       cnt++;
01136                     }
01137                   else if (tok == '>')
01138                     break;
01139                   else
01140                     exo_err("unexpected character in blob");
01141                 }
01142               }
01143 
01144 #if 0 /* zero tail is OK... */
01145             if (cnt != ent->as_blob.size)
01146               exo_err("not enough initializers for blob");
01147 #endif
01148             break;
01149 
01150           default:
01151             exo_err("expected '[' or '<'");
01152           }
01153       }
01154       break;
01155 
01156     case '}':
01157       exo_err("unexpected '}' encountered");
01158       break;
01159 
01160     case ',':
01161       exo_err("unexpected ',' encountered");
01162       break;
01163 
01164     case '[':
01165       {
01166         int i, cnt;
01167         struct exo_term_t *list, *elt, *next_elt;
01168 
01169         /* compute the array size */
01170         list = NULL;
01171         if (yy_nextchar() == ']')
01172           exo_err("unsized array has no initializers");
01173 
01174         cnt = 0;
01175         do {
01176           /* NULL element? */
01177           if (yy_nextchar() == ',')
01178             {
01179               elt = exo_new(ec_null);
01180             }
01181           else
01182             {
01183               elt = exo_read(stream);
01184               if (!elt)
01185                 exo_err("unexpected end-of-file");
01186             }
01187           cnt++;
01188           list = exo_chain(list, elt);
01189 
01190           /* consume optional commas */
01191           if (yy_nextchar() == ',')
01192             yylex();
01193         } while (yy_nextchar() != ']');
01194 
01195         /* read tail delimiter */
01196         tok = yylex();
01197         if (tok != ']')
01198           exo_err("expected ']'");
01199 
01200         /* create the array */
01201         assert(cnt > 0);
01202         ent = exo_new(ec_array, cnt, NULL);
01203 
01204         /* fill up the array */
01205         for (i=0,elt=list; i<cnt; i++,elt=next_elt)
01206           {
01207             assert(elt != NULL);
01208             next_elt = elt->next;
01209             if (elt->ec == ec_null)
01210               {
01211                 SET_EXO_ARR(ent, cnt, NULL);
01212                 exo_delete(ent);
01213               }
01214             else
01215               {
01216                 SET_EXO_ARR(ent, cnt, elt);
01217                 elt->next = NULL;
01218               }
01219           }
01220       }
01221       break;
01222 
01223     case ']':
01224       exo_err("unexpected ']' encountered");
01225       break;
01226 
01227     case lex_eof:
01228       /* nothing to read */
01229       ent = NULL;
01230       break;
01231 
01232     default:
01233       panic("bogus token");
01234     }
01235 
01236   return ent;
01237 }


UVa CS Department of Computer Science
School of Engineering, University of Virginia
151 Engineer's Way, P.O. Box 400740
Charlottesville, Virginia 22904-4740

(434) 982-2200  Fax: (434) 982-2214