libevtr: add support for string literals
authorAggelos Economopoulos <aoiko@cc.ece.ntua.gr>
Sun, 23 May 2010 12:44:36 +0000 (15:44 +0300)
committerAggelos Economopoulos <aoiko@cc.ece.ntua.gr>
Wed, 26 May 2010 13:21:48 +0000 (16:21 +0300)
lib/libevtr/evtr.c
lib/libevtr/internal.h
lib/libevtr/ktrfmt.l
lib/libevtr/ktrfmt.tab.c
lib/libevtr/ktrfmt.y
lib/libevtr/ktrfmt.yy.c

index 235bff0..c49cbab 100644 (file)
@@ -692,7 +692,6 @@ strhash_insert(struct hashtab_str *strtab, const char *str, uint16_t *id)
        return 0;
 }
 
-static
 struct symtab *
 symtab_new(void)
 {
@@ -704,7 +703,6 @@ symtab_new(void)
        return symtab;
 }
 
-static
 void
 symtab_destroy(struct symtab *symtab)
 {
index 5acfeb4..2344777 100644 (file)
@@ -35,8 +35,11 @@ enum debug_flags {
 TAILQ_HEAD(evtr_value_list, evtr_variable_value);
 typedef struct evtr_value_list *evtr_value_list_t;
 
+struct symtab *symtab_new(void);
 struct evtr_variable * symtab_find(const struct symtab *, const char *);
 int symtab_insert(struct symtab *, const char *, struct evtr_variable *);
+void symtab_destroy(struct symtab *);
+
 
 int parse_string(evtr_event_t, struct symtab *, const char *);
 int parse_var(const char *, struct symtab *, struct evtr_variable **);
index 336e585..d830a58 100644 (file)
@@ -12,6 +12,7 @@ enum {
 
 static struct token tokens[NR_TOKENS];
 static int curr_tok;
+static struct symtab *strtab;
 
 struct token *
 tok_new(void)
@@ -33,6 +34,24 @@ tok_free(struct token *tok)
        --curr_tok;
 }
 
+/*
+ * We keep track of strings we've seen before so string comparison
+ * can be done w/ a simple pointer comparison
+ */
+static
+char *
+newstr(const char *s)
+{
+       void *r;
+       if (!strtab)
+               strtab = symtab_new();  /* XXX: oom */
+       if ((r = symtab_find(strtab, s)))
+               return r;
+       r = strdup(s);
+       symtab_insert(strtab, r, r);
+       return r;
+}
+
 %}
 
 %option prefix="__ktrfmt"
@@ -47,11 +66,21 @@ ID  [a-zA-Z_$][a-zA-Z0-9_]*
 
 %%
 {WHITE}+ { /* ignore */ }
+\"(\\\"|[^"\n])+\" {
+       size_t len;
+       yylval->tok = tok_new();
+       yylval->tok->type = TOK_STR;
+       len = strlen(yytext);
+       yytext[len - 1] = '\0'; /* kill trailing quote */
+       yylval->tok->str = newstr(yytext + 1);
+       printd(LEX, "TOK_STR\n");
+       return TOK_STR;
+       }
 {ID} {
        yylval->tok = tok_new();
        yylval->tok->type = TOK_ID;
        printd(LEX, "tok %p TOK_ID %p:%s\n", yylval->tok, yytext, yytext);
-       yylval->tok->str = strdup(yytext);
+       yylval->tok->str = strdup(yytext);      /* XXX: oom */
        return TOK_ID;
        }
 {INT} {
index 664394b..a45b883 100644 (file)
@@ -412,7 +412,7 @@ union yyalloc
 #endif
 
 /* YYFINAL -- State number of the termination state.  */
-#define YYFINAL  13
+#define YYFINAL  12
 /* YYLAST -- Last index in YYTABLE.  */
 #define YYLAST   14
 
@@ -421,9 +421,9 @@ union yyalloc
 /* YYNNTS -- Number of nonterminals.  */
 #define YYNNTS  9
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  13
+#define YYNRULES  14
 /* YYNRULES -- Number of states.  */
-#define YYNSTATES  18
+#define YYNSTATES  20
 
 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
 #define YYUNDEFTOK  2
@@ -470,23 +470,23 @@ static const yytype_uint8 yytranslate[] =
 static const yytype_uint8 yyprhs[] =
 {
        0,     0,     3,     5,     7,     9,    11,    13,    15,    17,
-      22,    24,    26,    30
+      22,    26,    28,    30,    34
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS.  */
 static const yytype_int8 yyrhs[] =
 {
       11,     0,    -1,    12,    -1,    16,    -1,    18,    -1,     4,
-      -1,     5,    -1,     3,    -1,    13,    -1,     3,     7,    15,
-       8,    -1,    14,    -1,    15,    -1,    16,     6,    13,    -1,
-      17,    -1
+      -1,     5,    -1,     3,    -1,    13,    -1,    14,     7,    15,
+       8,    -1,    14,     9,     3,    -1,    14,    -1,    15,    -1,
+      16,     6,    13,    -1,    17,    -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint8 yyrline[] =
 {
        0,    88,    88,    90,    93,    95,   104,   118,   131,   135,
-     182,   186,   190,   198
+     193,   196,   200,   204,   212
 };
 #endif
 
@@ -515,14 +515,14 @@ static const yytype_uint16 yytoknum[] =
 static const yytype_uint8 yyr1[] =
 {
        0,    10,    11,    12,    12,    13,    13,    14,    14,    15,
-      15,    16,    17,    18
+      15,    15,    16,    17,    18
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
 static const yytype_uint8 yyr2[] =
 {
        0,     2,     1,     1,     1,     1,     1,     1,     1,     4,
-       1,     1,     3,     1
+       3,     1,     1,     3,     1
 };
 
 /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
@@ -530,8 +530,8 @@ static const yytype_uint8 yyr2[] =
    means the default is an error.  */
 static const yytype_uint8 yydefact[] =
 {
-       0,     7,     5,     6,     0,     2,     8,    10,    11,     3,
-      13,     4,     0,     1,     0,     0,    12,     9
+       0,     7,     5,     6,     0,     2,     8,    11,    12,     3,
+      14,     4,     1,     0,     0,     0,     0,    10,    13,     9
 };
 
 /* YYDEFGOTO[NTERM-NUM].  */
@@ -545,14 +545,14 @@ static const yytype_int8 yydefgoto[] =
 #define YYPACT_NINF -6
 static const yytype_int8 yypact[] =
 {
-      -3,    -2,    -6,    -6,     6,    -6,    -6,    -6,    -6,     1,
-      -6,    -6,    -3,    -6,    -1,     0,    -6,    -6
+      -3,    -6,    -6,    -6,     4,    -6,    -6,    -4,    -6,     3,
+      -6,    -6,    -6,    -3,     5,     2,     6,    -6,    -6,    -6
 };
 
 /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int8 yypgoto[] =
 {
-      -6,    -6,    -6,    -5,    -6,     2,    -6,    -6,    -6
+      -6,    -6,    -6,    -5,    -6,    -2,    -6,    -6,    -6
 };
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
@@ -562,14 +562,14 @@ static const yytype_int8 yypgoto[] =
 #define YYTABLE_NINF -1
 static const yytype_uint8 yytable[] =
 {
-       1,     2,     3,     2,     3,    12,    13,    14,    17,    16,
-       0,     0,     0,     0,    15
+       1,     2,     3,    13,    12,    14,     2,     3,    17,    15,
+      18,    16,     0,     0,    19
 };
 
 static const yytype_int8 yycheck[] =
 {
-       3,     4,     5,     4,     5,     7,     0,     6,     8,    14,
-      -1,    -1,    -1,    -1,    12
+       3,     4,     5,     7,     0,     9,     4,     5,     3,     6,
+      15,    13,    -1,    -1,     8
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
@@ -577,7 +577,7 @@ static const yytype_int8 yycheck[] =
 static const yytype_uint8 yystos[] =
 {
        0,     3,     4,     5,    11,    12,    13,    14,    15,    16,
-      17,    18,     7,     0,     6,    15,    13,     8
+      17,    18,     0,     7,     9,     6,    15,     3,    13,     8
 };
 
 #define yyerrok                (yyerrstatus = 0)
@@ -1424,8 +1424,8 @@ yyreduce:
     {
        evtr_var_t var;
        var = evtr_var_new(uniq_varname());
-       var->val.type = EVTR_VAL_INT;
-       var->val.str = strdup((yyvsp[(1) - (1)].tok)->str);
+       var->val.type = EVTR_VAL_STR;
+       var->val.str = (yyvsp[(1) - (1)].tok)->str;
        if (!var->val.str) {
                fprintf(stderr, "oom\n");
                YYABORT;
@@ -1470,48 +1470,59 @@ yyreduce:
     {
        evtr_var_t hsh, var;
        evtr_variable_value_t val;
-       hsh = symtab_find(ctx->symtab, (yyvsp[(1) - (4)].tok)->str);
+       uintptr_t ret, key;
+       hsh = symtab_find(ctx->symtab, (yyvsp[(1) - (4)].var)->name);
+#if 0
        if (!hsh) {
-               printd(PARSE, "creating hash: %s\n", (yyvsp[(1) - (4)].tok)->str);
-               hsh = evtr_var_new((yyvsp[(1) - (4)].tok)->str);
+               printd(PARSE, "creating hash: %s\n", (yyvsp[(1) - (4)].var)->name);
+               hsh = evtr_var_new((yyvsp[(1) - (4)].var)->name);
                hsh->val.type = EVTR_VAL_HASH;
                hsh->val.hashtab = hash_new();
-               symtab_insert(ctx->symtab, (yyvsp[(1) - (4)].tok)->str, hsh);
+               symtab_insert(ctx->symtab, (yyvsp[(1) - (4)].var)->str, hsh);
        }
-       if (hsh->val.type != EVTR_VAL_HASH) {
-               printd(PARSE, "variable %s does not contain a hash\n", hsh->name);
+#endif
+       if (hsh->val.type == EVTR_VAL_NIL) {
+               /* it's probably the first time we see this "variable" */
+               printd(PARSE, "creating hash for %s\n", hsh->name);
+               hsh->val.type = EVTR_VAL_HASH;
+               hsh->val.hashtab = hash_new();
+       } else if (hsh->val.type != EVTR_VAL_HASH) {
+               printd(PARSE, "trying to use type %d as hash\n", hsh->val.type);
                YYABORT;
        }
        val = &(yyvsp[(3) - (4)].var)->val;
        if (val->type == EVTR_VAL_INT) {
-               uintptr_t ret;
-               uintptr_t key = val->num;
-               printd(PARSE, "looking up %s[%jd] in %p\n", (yyvsp[(1) - (4)].tok)->str, val->num, hsh->val.hashtab);
-               /* XXX: should definitely be using uintptr_t for keys/values */
-               if (hash_find(hsh->val.hashtab, key, &ret)) {
-                       printd(PARSE, "didn't find it\n");
-                       var = evtr_var_new(uniq_varname());
-                       if (var) {
-                               printd(PARSE, "inserting it as %s\n", var->name);
-                               if (!hash_insert(hsh->val.hashtab, key, (uintptr_t)var)) {
-                                       fprintf(stderr, "can't insert tmp "
-                                               "variable into hash\n");
-                                       YYABORT;
-                               }
+               key = val->num;
+               printd(PARSE, "looking up %s[%jd] in %p\n", hsh->name, val->num, hsh->val.hashtab);
+       } else if (val->type == EVTR_VAL_STR) {
+               key = (uintptr_t)val->str;
+               printd(PARSE, "looking up %s[\"%s\"] in %p\n", hsh->name, val->str, hsh->val.hashtab);
+       } else {
+               fprintf(stderr, "trying to index hash w/ non-supported value\n");
+               YYABORT;
+       }
+
+       if (hash_find(hsh->val.hashtab, key, &ret)) {
+               printd(PARSE, "didn't find it\n");
+               var = evtr_var_new(uniq_varname());
+               if (var) {
+                       printd(PARSE, "inserting it as %s\n", var->name);
+                       if (!hash_insert(hsh->val.hashtab, key, (uintptr_t)var)) {
+                               fprintf(stderr, "can't insert tmp "
+                                       "variable into hash\n");
+                               YYABORT;
                        }
                } else {
-                       var = (struct evtr_variable *)ret;
+                       /* XXX: oom */
                }
        } else {
-               fprintf(stderr, "trying to index hash w/ non-integral value\n");
-               YYABORT;
+               var = (struct evtr_variable *)ret;
        }
        if (!var) {
                fprintf(stderr, "no var!\n");
                YYABORT;
                /* XXX */
        }
-       tok_free((yyvsp[(1) - (4)].tok));
        (yyval.var) = var;
  ;}
     break;
@@ -1519,16 +1530,16 @@ yyreduce:
   case 10:
 
 /* Line 1455 of yacc.c  */
-#line 182 "ktrfmt.y"
+#line 193 "ktrfmt.y"
     {
-       (yyval.var) = (yyvsp[(1) - (1)].var);
+       /* XXX */
  ;}
     break;
 
   case 11:
 
 /* Line 1455 of yacc.c  */
-#line 186 "ktrfmt.y"
+#line 196 "ktrfmt.y"
     {
        (yyval.var) = (yyvsp[(1) - (1)].var);
  ;}
@@ -1537,7 +1548,16 @@ yyreduce:
   case 12:
 
 /* Line 1455 of yacc.c  */
-#line 190 "ktrfmt.y"
+#line 200 "ktrfmt.y"
+    {
+       (yyval.var) = (yyvsp[(1) - (1)].var);
+ ;}
+    break;
+
+  case 13:
+
+/* Line 1455 of yacc.c  */
+#line 204 "ktrfmt.y"
     {
        (yyvsp[(1) - (3)].var)->val = (yyvsp[(3) - (3)].var)->val;
        ctx->ev->type = EVTR_TYPE_STMT;
@@ -1547,10 +1567,10 @@ yyreduce:
  ;}
     break;
 
-  case 13:
+  case 14:
 
 /* Line 1455 of yacc.c  */
-#line 198 "ktrfmt.y"
+#line 212 "ktrfmt.y"
     {
        (yyval.na) = (yyvsp[(1) - (1)].na);
  ;}
@@ -1559,7 +1579,7 @@ yyreduce:
 
 
 /* Line 1455 of yacc.c  */
-#line 1563 "ktrfmt.tab.c"
+#line 1583 "ktrfmt.tab.c"
       default: break;
     }
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
@@ -1771,7 +1791,7 @@ yyreturn:
 
 
 /* Line 1675 of yacc.c  */
-#line 203 "ktrfmt.y"
+#line 217 "ktrfmt.y"
 
 
 void * __ktrfmt_scan_string(const char *);
index 531ac03..f0b3099 100644 (file)
@@ -104,8 +104,8 @@ constant: TOK_INT {
        | TOK_STR {
        evtr_var_t var;
        var = evtr_var_new(uniq_varname());
-       var->val.type = EVTR_VAL_INT;
-       var->val.str = strdup($1->str);
+       var->val.type = EVTR_VAL_STR;
+       var->val.str = $1->str;
        if (!var->val.str) {
                fprintf(stderr, "oom\n");
                YYABORT;
@@ -132,53 +132,67 @@ primary_expr: TOK_ID {
        $$ = $1;
   }
 ;
-postfix_expr: TOK_ID TOK_LEFT_BRACK postfix_expr TOK_RIGHT_BRACK {
+postfix_expr: primary_expr TOK_LEFT_BRACK postfix_expr TOK_RIGHT_BRACK {
        evtr_var_t hsh, var;
        evtr_variable_value_t val;
-       hsh = symtab_find(ctx->symtab, $1->str);
+       uintptr_t ret, key;
+       hsh = symtab_find(ctx->symtab, $1->name);
+#if 0
        if (!hsh) {
-               printd(PARSE, "creating hash: %s\n", $1->str);
-               hsh = evtr_var_new($1->str);
+               printd(PARSE, "creating hash: %s\n", $1->name);
+               hsh = evtr_var_new($1->name);
                hsh->val.type = EVTR_VAL_HASH;
                hsh->val.hashtab = hash_new();
                symtab_insert(ctx->symtab, $1->str, hsh);
        }
-       if (hsh->val.type != EVTR_VAL_HASH) {
-               printd(PARSE, "variable %s does not contain a hash\n", hsh->name);
+#endif
+       if (hsh->val.type == EVTR_VAL_NIL) {
+               /* it's probably the first time we see this "variable" */
+               printd(PARSE, "creating hash for %s\n", hsh->name);
+               hsh->val.type = EVTR_VAL_HASH;
+               hsh->val.hashtab = hash_new();
+       } else if (hsh->val.type != EVTR_VAL_HASH) {
+               printd(PARSE, "trying to use type %d as hash\n", hsh->val.type);
                YYABORT;
        }
        val = &$3->val;
        if (val->type == EVTR_VAL_INT) {
-               uintptr_t ret;
-               uintptr_t key = val->num;
-               printd(PARSE, "looking up %s[%jd] in %p\n", $1->str, val->num, hsh->val.hashtab);
-               /* XXX: should definitely be using uintptr_t for keys/values */
-               if (hash_find(hsh->val.hashtab, key, &ret)) {
-                       printd(PARSE, "didn't find it\n");
-                       var = evtr_var_new(uniq_varname());
-                       if (var) {
-                               printd(PARSE, "inserting it as %s\n", var->name);
-                               if (!hash_insert(hsh->val.hashtab, key, (uintptr_t)var)) {
-                                       fprintf(stderr, "can't insert tmp "
-                                               "variable into hash\n");
-                                       YYABORT;
-                               }
+               key = val->num;
+               printd(PARSE, "looking up %s[%jd] in %p\n", hsh->name, val->num, hsh->val.hashtab);
+       } else if (val->type == EVTR_VAL_STR) {
+               key = (uintptr_t)val->str;
+               printd(PARSE, "looking up %s[\"%s\"] in %p\n", hsh->name, val->str, hsh->val.hashtab);
+       } else {
+               fprintf(stderr, "trying to index hash w/ non-supported value\n");
+               YYABORT;
+       }
+
+       if (hash_find(hsh->val.hashtab, key, &ret)) {
+               printd(PARSE, "didn't find it\n");
+               var = evtr_var_new(uniq_varname());
+               if (var) {
+                       printd(PARSE, "inserting it as %s\n", var->name);
+                       if (!hash_insert(hsh->val.hashtab, key, (uintptr_t)var)) {
+                               fprintf(stderr, "can't insert tmp "
+                                       "variable into hash\n");
+                               YYABORT;
                        }
                } else {
-                       var = (struct evtr_variable *)ret;
+                       /* XXX: oom */
                }
        } else {
-               fprintf(stderr, "trying to index hash w/ non-integral value\n");
-               YYABORT;
+               var = (struct evtr_variable *)ret;
        }
        if (!var) {
                fprintf(stderr, "no var!\n");
                YYABORT;
                /* XXX */
        }
-       tok_free($1);
        $$ = var;
  }
+| primary_expr TOK_DOT TOK_ID {
+       /* XXX */
+ }
             | primary_expr {
        $$ = $1;
  }
index de95311..c924c06 100644 (file)
@@ -391,8 +391,8 @@ static void yy_fatal_error (yyconst char msg[]  );
        *yy_cp = '\0'; \
        (yy_c_buf_p) = yy_cp;
 
-#define YY_NUM_RULES 7
-#define YY_END_OF_BUFFER 8
+#define YY_NUM_RULES 8
+#define YY_END_OF_BUFFER 9
 /* This struct is not used in this scanner,
    but its presence is necessary. */
 struct yy_trans_info
@@ -400,28 +400,28 @@ struct yy_trans_info
        flex_int32_t yy_verify;
        flex_int32_t yy_nxt;
        };
-static yyconst flex_int16_t yy_accept[15] =
+static yyconst flex_int16_t yy_accept[20] =
     {   0,
-        0,    0,    8,    7,    1,    2,    3,    4,    5,    6,
-        1,    2,    3,    0
+        0,    0,    9,    8,    1,    8,    3,    4,    5,    6,
+        7,    1,    0,    0,    3,    4,    2,    2,    0
     } ;
 
 static yyconst flex_int32_t yy_ec[256] =
     {   0,
-        1,    1,    1,    1,    1,    1,    1,    1,    2,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
         1,    1,    2,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    2,    1,    1,    1,    3,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    4,    4,    4,
-        4,    4,    4,    4,    4,    4,    4,    1,    1,    1,
-        5,    1,    1,    1,    6,    6,    6,    6,    6,    6,
-        6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
-        6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
-        7,    1,    8,    1,    6,    1,    6,    6,    6,    6,
-
-        6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
-        6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
-        6,    6,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    2,    1,    4,    1,    5,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    6,    6,    6,
+        6,    6,    6,    6,    6,    6,    6,    1,    1,    1,
+        7,    1,    1,    1,    8,    8,    8,    8,    8,    8,
+        8,    8,    8,    8,    8,    8,    8,    8,    8,    8,
+        8,    8,    8,    8,    8,    8,    8,    8,    8,    8,
+        9,   10,   11,    1,    8,    1,    8,    8,    8,    8,
+
+        8,    8,    8,    8,    8,    8,    8,    8,    8,    8,
+        8,    8,    8,    8,    8,    8,    8,    8,    8,    8,
+        8,    8,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
@@ -438,35 +438,40 @@ static yyconst flex_int32_t yy_ec[256] =
         1,    1,    1,    1,    1
     } ;
 
-static yyconst flex_int32_t yy_meta[9] =
+static yyconst flex_int32_t yy_meta[12] =
     {   0,
-        1,    1,    1,    2,    1,    2,    1,    1
+        1,    1,    2,    2,    1,    3,    1,    3,    1,    1,
+        1
     } ;
 
-static yyconst flex_int16_t yy_base[16] =
+static yyconst flex_int16_t yy_base[22] =
     {   0,
-        0,    0,   14,   15,   11,    0,    8,   15,   15,   15,
-        9,    0,    6,   15,    7
+        0,    0,   23,   24,   20,   10,    0,   11,   24,   24,
+       24,   14,    8,   11,    0,    8,   24,    0,   24,   18,
+       10
     } ;
 
-static yyconst flex_int16_t yy_def[16] =
+static yyconst flex_int16_t yy_def[22] =
     {   0,
-       14,    1,   14,   14,   14,   15,   14,   14,   14,   14,
-       14,   15,   14,    0,   14
+       19,    1,   19,   19,   19,   20,   21,   19,   19,   19,
+       19,   19,   20,   13,   21,   19,   19,   13,    0,   19,
+       19
     } ;
 
-static yyconst flex_int16_t yy_nxt[24] =
+static yyconst flex_int16_t yy_nxt[36] =
     {   0,
-        4,    5,    6,    7,    8,    6,    9,   10,   12,   13,
-       11,   13,   11,   14,    3,   14,   14,   14,   14,   14,
-       14,   14,   14
+        4,    5,    4,    6,    7,    8,    9,    7,   10,    4,
+       11,   17,   15,   16,   18,   12,   16,   14,   13,   14,
+       13,   12,   19,    3,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19
     } ;
 
-static yyconst flex_int16_t yy_chk[24] =
+static yyconst flex_int16_t yy_chk[36] =
     {   0,
-        1,    1,    1,    1,    1,    1,    1,    1,   15,   13,
-       11,    7,    5,    3,   14,   14,   14,   14,   14,   14,
-       14,   14,   14
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,   13,   21,   16,   14,   12,    8,   13,   20,    6,
+       20,    5,    3,   19,   19,   19,   19,   19,   19,   19,
+       19,   19,   19,   19,   19
     } ;
 
 static yy_state_type yy_last_accepting_state;
@@ -498,6 +503,7 @@ enum {
 
 static struct token tokens[NR_TOKENS];
 static int curr_tok;
+static struct symtab *strtab;
 
 struct token *
 tok_new(void)
@@ -519,7 +525,25 @@ tok_free(struct token *tok)
        --curr_tok;
 }
 
-#line 523 "ktrfmt.yy.c"
+/*
+ * We keep track of strings we've seen before so string comparison
+ * can be done w/ a simple pointer comparison
+ */
+static
+char *
+newstr(const char *s)
+{
+       void *r;
+       if (!strtab)
+               strtab = symtab_new();  /* XXX: oom */
+       if ((r = symtab_find(strtab, s)))
+               return r;
+       r = strdup(s);
+       symtab_insert(strtab, r, r);
+       return r;
+}
+
+#line 547 "ktrfmt.yy.c"
 
 #define INITIAL 0
 
@@ -712,9 +736,9 @@ YY_DECL
     
         YYSTYPE * yylval;
     
-#line 48 "ktrfmt.l"
+#line 67 "ktrfmt.l"
 
-#line 718 "ktrfmt.yy.c"
+#line 742 "ktrfmt.yy.c"
 
     yylval = yylval_param;
 
@@ -769,13 +793,13 @@ yy_match:
                        while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
                                {
                                yy_current_state = (int) yy_def[yy_current_state];
-                               if ( yy_current_state >= 15 )
+                               if ( yy_current_state >= 20 )
                                        yy_c = yy_meta[(unsigned int) yy_c];
                                }
                        yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
                        ++yy_cp;
                        }
-               while ( yy_base[yy_current_state] != 15 );
+               while ( yy_base[yy_current_state] != 24 );
 
 yy_find_action:
                yy_act = yy_accept[yy_current_state];
@@ -801,23 +825,37 @@ do_action:        /* This label is used only to access EOF actions. */
 
 case 1:
 YY_RULE_SETUP
-#line 49 "ktrfmt.l"
+#line 68 "ktrfmt.l"
 { /* ignore */ }
        YY_BREAK
 case 2:
 YY_RULE_SETUP
-#line 50 "ktrfmt.l"
+#line 69 "ktrfmt.l"
+{
+       size_t len;
+       yylval->tok = tok_new();
+       yylval->tok->type = TOK_STR;
+       len = strlen(__ktrfmttext);
+       __ktrfmttext[len - 1] = '\0';   /* kill trailing quote */
+       yylval->tok->str = newstr(__ktrfmttext + 1);
+       printd(LEX, "TOK_STR\n");
+       return TOK_STR;
+       }
+       YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 79 "ktrfmt.l"
 {
        yylval->tok = tok_new();
        yylval->tok->type = TOK_ID;
        printd(LEX, "tok %p TOK_ID %p:%s\n", yylval->tok, __ktrfmttext, __ktrfmttext);
-       yylval->tok->str = strdup(__ktrfmttext);
+       yylval->tok->str = strdup(__ktrfmttext);        /* XXX: oom */
        return TOK_ID;
        }
        YY_BREAK
-case 3:
+case 4:
 YY_RULE_SETUP
-#line 57 "ktrfmt.l"
+#line 86 "ktrfmt.l"
 {
        yylval->tok = tok_new();
        yylval->tok->type = TOK_INT;
@@ -826,39 +864,39 @@ YY_RULE_SETUP
        return TOK_INT;
        }
        YY_BREAK
-case 4:
+case 5:
 YY_RULE_SETUP
-#line 64 "ktrfmt.l"
+#line 93 "ktrfmt.l"
 {
        yylval = NULL;
        printd(LEX, "TOK_EQ\n");
        return TOK_EQ;
        }
        YY_BREAK
-case 5:
+case 6:
 YY_RULE_SETUP
-#line 69 "ktrfmt.l"
+#line 98 "ktrfmt.l"
 {
        yylval = NULL;
        printd(LEX, "TOK_LEFT_BRACK\n");
        return TOK_LEFT_BRACK;
        }
        YY_BREAK
-case 6:
+case 7:
 YY_RULE_SETUP
-#line 74 "ktrfmt.l"
+#line 103 "ktrfmt.l"
 {
        yylval = NULL;
        printd(LEX, "TOK_RIGHT_BRACK\n");
        return TOK_RIGHT_BRACK;
        }
        YY_BREAK
-case 7:
+case 8:
 YY_RULE_SETUP
-#line 80 "ktrfmt.l"
+#line 109 "ktrfmt.l"
 ECHO;
        YY_BREAK
-#line 862 "ktrfmt.yy.c"
+#line 900 "ktrfmt.yy.c"
 case YY_STATE_EOF(INITIAL):
        yyterminate();
 
@@ -1150,7 +1188,7 @@ static int yy_get_next_buffer (void)
                while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
                        {
                        yy_current_state = (int) yy_def[yy_current_state];
-                       if ( yy_current_state >= 15 )
+                       if ( yy_current_state >= 20 )
                                yy_c = yy_meta[(unsigned int) yy_c];
                        }
                yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
@@ -1178,11 +1216,11 @@ static int yy_get_next_buffer (void)
        while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
                {
                yy_current_state = (int) yy_def[yy_current_state];
-               if ( yy_current_state >= 15 )
+               if ( yy_current_state >= 20 )
                        yy_c = yy_meta[(unsigned int) yy_c];
                }
        yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-       yy_is_jam = (yy_current_state == 14);
+       yy_is_jam = (yy_current_state == 19);
 
        return yy_is_jam ? 0 : yy_current_state;
 }
@@ -1819,6 +1857,6 @@ void __ktrfmtfree (void * ptr )
 
 #define YYTABLES_NAME "yytables"
 
-#line 80 "ktrfmt.l"
+#line 109 "ktrfmt.l"