/* * Copyright (c)2004-2010 Cat's Eye Technologies. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Cat's Eye Technologies nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * parse.c * Recursive-descent parser for 2Iota. * $Id: parse.c 518 2010-04-28 17:48:38Z cpressey $ */ #include #include #include #include "scan.h" #include "parse.h" #include "symbol.h" #include "symstr.h" #include "alphabet.h" #include "event.h" #include "etime.h" #include "2iota.h" /* ---------------- EVENT STRUCTURE (beta-Juliet) ----------------*/ void two_iota(struct scan_st *sc) { decl(sc); while (tokeq(sc, ";")) { scan(sc); decl(sc); } scan_expect(sc, "."); } void decl(struct scan_st *sc) { if (tokeq(sc, "alphabet")) { struct symbol *sym; struct alphabet *alpha; alpha = alphabet_new(); scan(sc); sym = symbol_name(sc, astab, SYM_TYPE_ALPHABET, SYM_LOOKUP_UNIQUE); sym->alpha = alpha; while(tokeq(sc, ",")) { scan(sc); sym = symbol_name(sc, gstab, SYM_TYPE_SYMBOL, SYM_LOOKUP_DEFINE); alphabet_append(alpha, sym); } } else if (tokeq(sc, "event")) { struct event *e; e = event_new(event_table); /* XXX global? */ scan(sc); event_decl_name(sc, e); while(tokeq(sc, ",")) { scan(sc); property(sc, e); } } else scan_error(sc, "Expected 'alphabet' or 'event'"); } void property(struct scan_st *sc, struct event *e) { if (tokeq(sc, "causes")) { struct consequence *c; struct symstr *ss; struct etime et = etime_zero; scan(sc); ss = event_appl_name(sc, e); if (tokeq(sc, "after")) { scan(sc); time_spec(sc, &et); } c = event_consequence_append(e, ss, &et); while(tokeq(sc, "when")) { scan(sc); when_term(sc, e); } } else scan_error(sc, "Expected 'causes'"); } void when_term(struct scan_st *sc, struct event *e) { struct symstr *earlier, *later; later = event_appl_name(sc, e); scan_expect(sc, ">"); earlier = event_appl_name(sc, e); consequence_condition_append(e->head, earlier, later); } void time_spec(struct scan_st *sc, struct etime *et) { double n, f; long secs, msecs; char unit[16]; while (isdigit((int)sc->token[0])) { n = atof(sc->token); scan(sc); strncpy(unit, sc->token, 16); scan(sc); if (!strcmp(unit, "d")) { f = (3600.0 * 24.0); } else if (!strcmp(unit, "h")) { f = 3600.0; } else if (!strcmp(unit, "m")) { f = 60.0; } else if (!strcmp(unit, "s")) { f = 1.0; } else if (!strcmp(unit, "ms")) { f = 0.001; } else { scan_error(sc, "Expected 'd', 'h', 'm', 's', or 'ms'"); break; } secs = f * n; msecs = ((f * n) - secs) * 1000; etime_add(et, 0, 0, 0, secs, msecs, 0); } } /* -------------------- EVENT NAMES (Portia) --------------------*/ void event_decl_name(struct scan_st *sc, struct event *e) { struct symbol *sym; while (tokne(sc, ",") && tokne(sc, ";") && tokne(sc, ".")) { if (tokeq(sc, "(")) { scan(sc); sym = symbol_name(sc, e->params, SYM_TYPE_PARAMETER, SYM_LOOKUP_UNIQUE); scan_expect(sc, "="); match_expr(sc, e, sym); scan_expect(sc, ")"); } else { sym = symbol_name(sc, gstab, SYM_TYPE_LITERAL, SYM_LOOKUP_DEFINE); symstr_append(e->name, sym, NULL, 0, SYMSTR_OP_NOP); } } } void match_expr(struct scan_st *sc, struct event *e, struct symbol *param_sym) { int many = 0; struct symbol *alpha_sym; alpha_sym = symbol_name(sc, astab, SYM_TYPE_ALPHABET, SYM_LOOKUP_EXTANT); if (tokeq(sc, "+")) { scan(sc); many = 1; } symstr_append(e->name, param_sym, alpha_sym, many, SYMSTR_OP_NOP); /* * Also set the alphabet on the parameter, so that we * know what to do when we later succ() or pred() it. */ param_sym->alpha = alpha_sym->alpha; } struct symstr * event_appl_name(struct scan_st *sc, struct event *e) { struct symstr *ss; struct symbol *sym; ss = symstr_new(); while (tokne(sc, ",") && tokne(sc, ";") && tokne(sc, ".") && tokne(sc, ">") && tokne(sc, "after") && tokne(sc, "when")) { if (tokeq(sc, "(")) { scan(sc); alphabet_expr(sc, e, ss); scan_expect(sc, ")"); } else { sym = symbol_name(sc, gstab, SYM_TYPE_LITERAL, SYM_LOOKUP_DEFINE); symstr_append(ss, sym, NULL, 0, SYMSTR_OP_NOP); } } return(ss); } void alphabet_expr(struct scan_st *sc, struct event *e, struct symstr *ss) { struct symstr *fm_ss; struct symstr_component *psymc, *nsymc; psymc = alphabet_term(sc, e, ss); while (tokeq(sc, "|")) { scan(sc); fm_ss = symstr_new(); nsymc = alphabet_term(sc, e, fm_ss); psymc->fmode = fm_ss; psymc = nsymc; } } struct symstr_component * alphabet_term(struct scan_st *sc, struct event *e, struct symstr *ss) { struct symbol *sym; struct symstr_component *symc = NULL; if (tokeq(sc, "succ")) { scan(sc); sym = symbol_name(sc, e->params, SYM_TYPE_PARAMETER, SYM_LOOKUP_EXTANT); symc = symstr_append(ss, sym, NULL, 0, SYMSTR_OP_SUCC); } else if (tokeq(sc, "pred")) { scan(sc); sym = symbol_name(sc, e->params, SYM_TYPE_PARAMETER, SYM_LOOKUP_EXTANT); symc = symstr_append(ss, sym, NULL, 0, SYMSTR_OP_PRED); } else if (tokeq(sc, "prev")) { scan(sc); sym = symbol_name(sc, e->params, SYM_TYPE_PARAMETER, SYM_LOOKUP_EXTANT); symc = symstr_append(ss, sym, NULL, 0, SYMSTR_OP_PREV); } else if (tokeq(sc, "next")) { scan(sc); sym = symbol_name(sc, e->params, SYM_TYPE_PARAMETER, SYM_LOOKUP_EXTANT); symc = symstr_append(ss, sym, NULL, 0, SYMSTR_OP_NEXT); } else if (tokeq(sc, "first")) { scan(sc); sym = symbol_name(sc, astab, SYM_TYPE_ALPHABET, SYM_LOOKUP_EXTANT); sym = alphabet_first(sym->alpha); symc = symstr_append(ss, sym, NULL, 0, SYMSTR_OP_NOP); } else if (tokeq(sc, "last")) { scan(sc); sym = symbol_name(sc, astab, SYM_TYPE_ALPHABET, SYM_LOOKUP_EXTANT); sym = alphabet_last(sym->alpha); symc = symstr_append(ss, sym, NULL, 0, SYMSTR_OP_NOP); } else { sym = symbol_name(sc, gstab, SYM_TYPE_LITERAL, SYM_LOOKUP_DEFINE); symc = symstr_append(ss, sym, NULL, 0, SYMSTR_OP_NOP); } return(symc); } /* ------------ BASIC NAMES ------------- */ struct symbol * symbol_name(struct scan_st *sc, struct symbol_table *stab, int type, int lookup) { char name[128]; struct symbol * sym; strncpy(name, sc->token, 128); scan(sc); sym = symbol_lookup(stab, name); if (lookup == SYM_LOOKUP_UNIQUE) { if (sym != NULL) { scan_error(sc, "Symbol '%s' already defined", name); return(NULL); } else { sym = symbol_define(stab, name, type); return(sym); } } else if (lookup == SYM_LOOKUP_DEFINE) { if (sym != NULL) { return(sym); } else { sym = symbol_define(stab, name, type); return(sym); } } else if (lookup == SYM_LOOKUP_EXTANT) { if (sym == NULL) { scan_error(sc, "Symbol '%s' not defined", name); return(NULL); } else { return(sym); } } /* internal error */ return(NULL); }