lib/asParse.c

Go to the documentation of this file.
00001 /* asParse - parse out an autoSql .as file. */
00002 
00003 #include "common.h"
00004 #include "linefile.h"
00005 #include "tokenizer.h"
00006 #include "asParse.h"
00007 
00008 static char const rcsid[] = "$Id: asParse.c,v 1.6 2007/02/11 21:43:15 kent Exp $";
00009 
00010 /* n.b. switched double/float from %f to %g to partially address losing
00011  * precision.  Values like 2e-12 were being rounded to 0.0 with %f.  While %g
00012  * doesn't match the precision of the database fields, specifying a larger
00013  * precision with %g resulted in numbers like 1.9999999999999999597733e-12,
00014  *  which might impact load time.  THis issue needs more investigation.*/
00015 struct asTypeInfo asTypes[] = {
00016     {t_double,  "double",  FALSE, FALSE, "double",           "double",        "Double", "Double", "%g"},
00017     {t_float,   "float",   FALSE, FALSE, "float",            "float",         "Float",  "Float",  "%g"},
00018     {t_char,    "char",    FALSE, FALSE, "char",             "char",          "Char",   "Char",   "%c"},
00019     {t_int,     "int",     FALSE, FALSE, "int",              "int",           "Signed", "Signed", "%d"},
00020     {t_uint,    "uint",    TRUE,  FALSE, "int unsigned",     "unsigned",      "Unsigned","Unsigned", "%u"},
00021     {t_short,   "short",   FALSE, FALSE, "smallint",         "short",         "Short",  "Signed", "%d"},
00022     {t_ushort,  "ushort",  TRUE,  FALSE, "smallint unsigned","unsigned short","Ushort", "Unsigned", "%u"},
00023     {t_byte,    "byte",    FALSE, FALSE, "tinyint",          "signed char",   "Byte",   "Signed", "%d"},
00024     {t_ubyte,   "ubyte",   TRUE,  FALSE, "tinyint unsigned", "unsigned char", "Ubyte",  "Unsigned", "%u"},
00025     {t_off,     "bigint",  FALSE,  FALSE,"bigint",           "long long",     "LongLong", "LongLong", "%lld"},
00026     {t_string,  "string",  FALSE, TRUE,  "varchar(255)",     "char *",        "String", "String", "%s"},
00027     {t_lstring,    "lstring",    FALSE, TRUE,  "longblob",   "char *",        "String", "String", "%s"},
00028     {t_enum,    "enum",    FALSE, FALSE, "enum",             "!error!",       "Enum",   "Enum", NULL},
00029     {t_set,     "set",     FALSE, FALSE, "set",              "unsigned",      "Set",    "Set", NULL},
00030     {t_object,  "object",  FALSE, FALSE, "longblob",         "!error!",       "Object", "Object", NULL},
00031     {t_object,  "table",   FALSE, FALSE, "longblob",         "!error!",       "Object", "Object", NULL},
00032     {t_simple,  "simple",  FALSE, FALSE, "longblob",         "!error!",       "Simple", "Simple", NULL},
00033 };
00034 
00035 static struct asTypeInfo *findLowType(struct tokenizer *tkz)
00036 /* Return low type info.  Squawk and die if s doesn't
00037  * correspond to one. */
00038 {
00039 char *s = tkz->string;
00040 int i;
00041 for (i=0; i<ArraySize(asTypes); ++i)
00042     {
00043     if (sameWord(asTypes[i].name, s))
00044         return &asTypes[i];
00045     }
00046 tokenizerErrAbort(tkz, "Unknown type '%s'", s);
00047 return NULL;
00048 }
00049 
00050 static struct asColumn *mustFindColumn(struct asObject *table, char *colName)
00051 /* Return column or die. */
00052 {
00053 struct asColumn *col;
00054 
00055 for (col = table->columnList; col != NULL; col = col->next)
00056     {
00057     if (sameWord(col->name, colName))
00058         return col;
00059     }
00060 errAbort("Couldn't find column %s", colName);
00061 return NULL;
00062 }
00063 
00064 static struct asObject *findObType(struct asObject *objList, char *obName)
00065 /* Find object with given name. */
00066 {
00067 struct asObject *obj;
00068 for (obj = objList; obj != NULL; obj = obj->next)
00069     {
00070     if (sameWord(obj->name, obName))
00071         return obj;
00072     }
00073 return NULL;
00074 }
00075 
00076 static void asParseColArraySpec(struct tokenizer *tkz, struct asObject *obj,
00077                                 struct asColumn *col)
00078 /* parse the array length specification for a column */
00079 {
00080 if (col->lowType->type == t_simple)
00081     col->isArray = TRUE;
00082 else
00083     col->isList = TRUE;
00084 tokenizerMustHaveNext(tkz);
00085 if (isdigit(tkz->string[0]))
00086     {
00087     col->fixedSize = atoi(tkz->string);
00088     tokenizerMustHaveNext(tkz);
00089     }
00090 else if (isalpha(tkz->string[0]))
00091     {
00092 #ifdef OLD
00093     if (obj->isSimple)
00094         tokenizerErrAbort(tkz, "simple objects can't include variable length arrays\n");
00095 #endif /* OLD */
00096     col->linkedSizeName = cloneString(tkz->string);
00097     col->linkedSize = mustFindColumn(obj, col->linkedSizeName);
00098     col->linkedSize->isSizeLink = TRUE;
00099     tokenizerMustHaveNext(tkz);
00100     }
00101 else
00102     tokenizerErrAbort(tkz, "must have column name or integer inside []'s\n");
00103 tokenizerMustMatch(tkz, "]");
00104 }
00105 
00106 static void asParseColSymSpec(struct tokenizer *tkz, struct asObject *obj,
00107                               struct asColumn *col)
00108 /* parse the enum or set symbolic values for a column */
00109 {
00110 tokenizerMustHaveNext(tkz);
00111 while (tkz->string[0] != ')')
00112     {
00113     slSafeAddHead(&col->values, slNameNew(tkz->string));
00114     /* look for `,' or `)', but allow `,' after last token */
00115     tokenizerMustHaveNext(tkz);
00116     if (!((tkz->string[0] == ',') || (tkz->string[0] == ')')))
00117         tokenizerErrAbort(tkz, "expected `,' or `)' got `%s'", tkz->string);
00118     if (tkz->string[0] != ')')
00119         tokenizerMustHaveNext(tkz);
00120     }
00121 tokenizerMustMatch(tkz, ")");
00122 slReverse(&col->values);
00123 }
00124 
00125 static void asParseColDef(struct tokenizer *tkz, struct asObject *obj)
00126 /* Parse a column definintion */
00127 {
00128 struct asColumn *col;
00129 AllocVar(col);
00130 
00131 col->lowType = findLowType(tkz);
00132 tokenizerMustHaveNext(tkz);
00133 
00134 if (col->lowType->type == t_object || col->lowType->type == t_simple)
00135     {
00136     col->obName = cloneString(tkz->string);
00137     tokenizerMustHaveNext(tkz);
00138     }
00139 
00140 if (tkz->string[0] == '[')
00141     asParseColArraySpec(tkz, obj, col);
00142 else if (tkz->string[0] == '(')
00143     asParseColSymSpec(tkz, obj, col);
00144 
00145 col->name = cloneString(tkz->string);
00146 tokenizerMustHaveNext(tkz);
00147 tokenizerMustMatch(tkz, ";");
00148 col->comment = cloneString(tkz->string);
00149 tokenizerMustHaveNext(tkz);
00150 if (col->lowType->type == t_char && col->fixedSize != 0)
00151     col->isList = FALSE;        /* It's not really a list... */
00152 slAddHead(&obj->columnList, col);
00153 }
00154 
00155 static struct asObject *asParseTableDef(struct tokenizer *tkz)
00156 /* Parse a table or object definintion */
00157 {
00158 struct asObject *obj;
00159 AllocVar(obj);
00160 if (sameWord(tkz->string, "table"))
00161     obj->isTable = TRUE;
00162 else if (sameWord(tkz->string, "simple"))
00163     obj->isSimple = TRUE;
00164 else if (sameWord(tkz->string, "object"))
00165     ;
00166 else
00167     tokenizerErrAbort(tkz, "Expecting 'table' or 'object' got '%s'", tkz->string);
00168 tokenizerMustHaveNext(tkz);
00169 obj->name = cloneString(tkz->string);
00170 tokenizerMustHaveNext(tkz);
00171 obj->comment = cloneString(tkz->string);
00172 
00173 /* parse columns */
00174 tokenizerMustHaveNext(tkz);
00175 tokenizerMustMatch(tkz, "(");
00176 while (tkz->string[0] != ')')
00177     asParseColDef(tkz, obj);
00178 slReverse(&obj->columnList);
00179 return obj;
00180 }
00181 
00182 static void asLinkEmbeddedObjects(struct asObject *obj, struct asObject *objList)
00183 /* Look up any embedded objects. */
00184 {
00185 struct asColumn *col;
00186 for (col = obj->columnList; col != NULL; col = col->next)
00187     {
00188     if (col->obName != NULL)
00189         {
00190         if ((col->obType = findObType(objList, col->obName)) == NULL)
00191             errAbort("%s used but not defined", col->obName);
00192         if (obj->isSimple)
00193             {
00194             if (!col->obType->isSimple)
00195                 errAbort("Simple object %s with embedded non-simple object %s",
00196                     obj->name, col->name);
00197             }
00198         }
00199     }
00200 }
00201 
00202 static struct asObject *asParseTokens(struct tokenizer *tkz)
00203 /* Parse file into a list of objects. */
00204 {
00205 struct asObject *objList = NULL;
00206 struct asObject *obj;
00207 
00208 while (tokenizerNext(tkz))
00209     {
00210     obj = asParseTableDef(tkz);
00211     if (findObType(objList, obj->name))
00212         tokenizerErrAbort(tkz, "Duplicate definition of %s", obj->name);
00213     slAddTail(&objList, obj);
00214     }
00215 
00216 for (obj = objList; obj != NULL; obj = obj->next)
00217     asLinkEmbeddedObjects(obj, objList);
00218 
00219 return objList;
00220 }
00221 
00222 static struct asObject *asParseLineFile(struct lineFile *lf)
00223 /* Parse open line file.  Closes lf as a side effect. */
00224 {
00225 struct tokenizer *tkz = tokenizerOnLineFile(lf);
00226 struct asObject *objList = asParseTokens(tkz);
00227 tokenizerFree(&tkz);
00228 return objList;
00229 }
00230 
00231 struct asObject *asParseFile(char *fileName)
00232 /* Parse autoSql .as file. */
00233 {
00234 return asParseLineFile(lineFileOpen(fileName, TRUE));
00235 }
00236 
00237 
00238 struct asObject *asParseText(char *text)
00239 /* Parse autoSql from text (as opposed to file). */
00240 {
00241 char *dupe = cloneString(text);
00242 struct lineFile *lf = lineFileOnString("text", TRUE, dupe);
00243 struct asObject *objList = asParseLineFile(lf);
00244 return objList;
00245 }
00246 

Generated on Tue Dec 25 18:39:30 2007 for blat by  doxygen 1.5.2