Add pipelining mechanism to language
authorerg <devnull@localhost>
Tue, 30 Jun 2009 02:17:55 +0000 (02:17 +0000)
committererg <devnull@localhost>
Tue, 30 Jun 2009 02:17:55 +0000 (02:17 +0000)
lib/gvpr/compile.c
lib/gvpr/compile.h
lib/gvpr/gvpr.c
lib/gvpr/parse.c
lib/gvpr/parse.h

index 1a8c6a7b5c08d6b4849fbbe98562fc31438ca105..6319dd9b4006174b3610bf579e664f31ff439a8f 100644 (file)
@@ -2203,6 +2203,59 @@ static case_stmt *mkStmts(Expr_t * prog, char *src, case_info * sp,
     return cs;
 }
 
+/* mkBlocks:
+ */
+static int mkBlock(comp_block* bp, Expr_t * prog, char *src, parse_block *inp, Sfio_t* tmps, int i)
+{
+    int rv = 0;
+
+    codePhase = 1;
+    if (inp->begg_stmt) {
+       sfprintf(tmps, "_begin_g_%d", i);
+       symbols[0].type = T_graph;
+       tchk[V_this][1] = Y(G);
+       bp->begg_stmt = compile(prog, src, inp->begg_stmt,
+                              inp->l_beging, sfstruse(tmps), 0, VOIDTYPE);
+       if (getErrorErrors())
+           goto finishBlk;
+       rv |= BEGG;
+    }
+
+    codePhase = 2;
+    if (inp->node_stmts) {
+       symbols[0].type = T_node;
+       tchk[V_this][1] = Y(V);
+       bp->n_nstmts = inp->n_nstmts;
+       bp->node_stmts = mkStmts(prog, src, inp->node_stmts,
+                               inp->n_nstmts, "_nd", tmps);
+       if (getErrorErrors())
+           goto finishBlk;
+       bp->walks |= WALKSG;
+    }
+
+    codePhase = 3;
+    if (inp->edge_stmts) {
+       symbols[0].type = T_edge;
+       tchk[V_this][1] = Y(E);
+       bp->n_estmts = inp->n_estmts;
+       bp->edge_stmts = mkStmts(prog, src, inp->edge_stmts,
+                               inp->n_estmts, "_eg", tmps);
+       if (getErrorErrors())
+           goto finishBlk;
+       bp->walks |= WALKSG;
+    }
+
+    finishBlk:
+    if (getErrorErrors()) {
+       free (bp->node_stmts);
+       free (bp->edge_stmts);
+       bp->node_stmts = 0;
+       bp->edge_stmts = 0;
+    }
+
+    return (rv | bp->walks);
+}
+
 /* doFlags:
  * Convert command line flags to actions in END_G.
  */
@@ -2224,6 +2277,7 @@ comp_prog *compileProg(parse_prog * inp, Gpr_t * state, int flags)
     comp_prog *p;
     Sfio_t *tmps = state->tmp;
     char *endg_sfx = 0;
+    int i, useflags = 0;
 
     /* Make sure we have enough bits for types */
     assert(BITS_PER_BYTE * sizeof(tctype) >= (1 << TBITS));
@@ -2256,37 +2310,23 @@ comp_prog *compileProg(parse_prog * inp, Gpr_t * state, int flags)
            goto finish;
     }
 
-    codePhase = 1;
-    if (inp->begg_stmt) {
-       symbols[0].type = T_graph;
-       tchk[V_this][1] = Y(G);
-       p->begg_stmt = compile(p->prog, inp->source, inp->begg_stmt,
-                              inp->l_beging, "_begin_g", 0, VOIDTYPE);
-       if (getErrorErrors())
-           goto finish;
-    }
+    if (inp->blocks) {
+       comp_block* bp;
+       parse_block* ibp = inp->blocks;
 
-    codePhase = 2;
-    if (inp->node_stmts) {
-       symbols[0].type = T_node;
-       tchk[V_this][1] = Y(V);
-       p->n_nstmts = inp->n_nstmts;
-       p->node_stmts = mkStmts(p->prog, inp->source, inp->node_stmts,
-                               inp->n_nstmts, "_nd", tmps);
-       if (getErrorErrors())
-           goto finish;
-    }
+       p->blocks = bp = newof(0, comp_block, inp->n_blocks, 0);
 
-    codePhase = 3;
-    if (inp->edge_stmts) {
-       symbols[0].type = T_edge;
-       tchk[V_this][1] = Y(E);
-       p->n_estmts = inp->n_estmts;
-       p->edge_stmts = mkStmts(p->prog, inp->source, inp->edge_stmts,
-                               inp->n_estmts, "_eg", tmps);
-       if (getErrorErrors())
-           goto finish;
+       for (i = 0; i < inp->n_blocks; bp++, i++) {
+           useflags |= mkBlock (bp, p->prog, inp->source, ibp, tmps, i);
+           if (getErrorErrors())
+               goto finish;
+           else {
+               ibp = ibp->next;
+               p->n_blocks++;
+           }
+       }
     }
+    p->flags = useflags;
 
     codePhase = 4;
     if (inp->endg_stmt || endg_sfx) {
@@ -2308,6 +2348,9 @@ comp_prog *compileProg(parse_prog * inp, Gpr_t * state, int flags)
     }
     setErrorLine (0); /* execution errors have no line numbers */
 
+    if (p->end_stmt)
+       p->flags |= ENDG;
+
     finish:
     if (getErrorErrors()) {
        freeCompileProg (p);
@@ -2320,20 +2363,27 @@ comp_prog *compileProg(parse_prog * inp, Gpr_t * state, int flags)
 void
 freeCompileProg (comp_prog *p)
 {
+    comp_block* bp;
+    int i;
+
     if (!p) return;
 
     exclose (p->prog, 1);
-    free (p->node_stmts);
-    free (p->edge_stmts);
+    for (i = 0; i < p->n_blocks; i++) {
+       bp = p->blocks + i;
+       free (bp->node_stmts);
+       free (bp->edge_stmts);
+    }
+    free (p->blocks);
     free (p);
 }
 
 /* walksGraph;
- * Returns true if program actually has node or edge statements.
+ * Returns true if block actually has node or edge statements.
  */
-int walksGraph(comp_prog * p)
+int walksGraph(comp_block * p)
 {
-    return (p->n_nstmts || p->n_estmts);
+    return (p->walks);
 }
 
 /* usesGraph;
@@ -2342,7 +2392,7 @@ int walksGraph(comp_prog * p)
  */
 int usesGraph(comp_prog * p)
 {
-    return (walksGraph(p) || p->begg_stmt || p->endg_stmt);
+    return (p->flags);
 }
 
 void ptchk(void)
index 588d73ae02c455966f8b3b3b14b433f5da1bdb43..5c2e7e3720af90fe1528ed1db0de00d51ff1a97d 100644 (file)
@@ -64,14 +64,25 @@ extern "C" {
 #define INDUCE    0x2
 #define CLONE     0x4
 
+#define WALKSG    0x1
+#define BEGG      0x2
+#define ENDG      0x4
+
     typedef struct {
-       Expr_t *prog;
-       Exnode_t *begin_stmt;
        Exnode_t *begg_stmt;
+       int walks;
        int n_nstmts;
        int n_estmts;
        case_stmt *node_stmts;
        case_stmt *edge_stmts;
+    } comp_block; 
+
+    typedef struct {
+       int flags;
+       Expr_t *prog;
+       Exnode_t *begin_stmt;
+       int n_blocks;
+       comp_block  *blocks;
        Exnode_t *endg_stmt;
        Exnode_t *end_stmt;
     } comp_prog;
@@ -79,7 +90,7 @@ extern "C" {
     extern comp_prog *compileProg(parse_prog *, Gpr_t *, int);
     extern void freeCompileProg (comp_prog *p);
     extern int usesGraph(comp_prog *);
-    extern int walksGraph(comp_prog *);
+    extern int walksGraph(comp_block *);
     extern Agraph_t *readG(Sfio_t * fp);
     extern Agraph_t *openG(char *name, Agdesc_t);
     extern Agraph_t *openSubg(Agraph_t * g, char *name);
index 497ea9018af1ef6bd5f89493ab868ad3c0b27820..620117201f233f6f0777ee852fddb1c070af41e0 100644 (file)
@@ -419,7 +419,7 @@ static options* scanArgs(int argc, char **argv, gvpropts* uopts)
     return opts;
 }
 
-static void evalEdge(Gpr_t * state, comp_prog * xprog, Agedge_t * e)
+static void evalEdge(Gpr_t * state, Expr_t* prog, comp_block * xprog, Agedge_t * e)
 {
     int i;
     case_stmt *cs;
@@ -429,19 +429,19 @@ static void evalEdge(Gpr_t * state, comp_prog * xprog, Agedge_t * e)
     for (i = 0; i < xprog->n_estmts; i++) {
        cs = xprog->edge_stmts + i;
        if (cs->guard)
-           okay = (exeval(xprog->prog, cs->guard, state)).integer;
+           okay = (exeval(prog, cs->guard, state)).integer;
        else
            okay = 1;
        if (okay) {
            if (cs->action)
-               exeval(xprog->prog, cs->action, state);
+               exeval(prog, cs->action, state);
            else
                agsubedge(state->target, e, TRUE);
        }
     }
 }
 
-static void evalNode(Gpr_t * state, comp_prog * xprog, Agnode_t * n)
+static void evalNode(Gpr_t * state, Expr_t* prog, comp_block * xprog, Agnode_t * n)
 {
     int i;
     case_stmt *cs;
@@ -451,12 +451,12 @@ static void evalNode(Gpr_t * state, comp_prog * xprog, Agnode_t * n)
     for (i = 0; i < xprog->n_nstmts; i++) {
        cs = xprog->node_stmts + i;
        if (cs->guard)
-           okay = (exeval(xprog->prog, cs->guard, state)).integer;
+           okay = (exeval(prog, cs->guard, state)).integer;
        else
            okay = 1;
        if (okay) {
            if (cs->action)
-               exeval(xprog->prog, cs->action, state);
+               exeval(prog, cs->action, state);
            else
                agsubnode(state->target, n, TRUE);
        }
@@ -505,7 +505,7 @@ static trav_fns DFSfns = { agfstedge, agnxtedge, 1, 0 };
 static trav_fns FWDfns = { agfstout, (nxttedgefn_t) agnxtout, 0, 0 };
 static trav_fns REVfns = { agfstin, (nxttedgefn_t) agnxtin, 0, 0 };
 
-static void travBFS(Gpr_t * state, comp_prog * xprog)
+static void travBFS(Gpr_t * state, Expr_t* prog, comp_block * xprog)
 {
     nodestream nodes;
     queue *q;
@@ -527,13 +527,13 @@ static void travBFS(Gpr_t * state, comp_prog * xprog)
            nd = nData(n);
            MARK(nd);
            POP(nd);
-           evalNode(state, xprog, n);
+           evalNode(state, prog, xprog, n);
            for (cure = agfstedge(g, n); cure;
                 cure = agnxtedge(g, cure, n)) {
                nd = nData(cure->node);
                if (MARKED(nd))
                    continue;
-               evalEdge(state, xprog, cure);
+               evalEdge(state, prog, xprog, cure);
                if (!ONSTACK(nd)) {
                    push(q, cure->node);
                    PUSH(nd);
@@ -544,7 +544,7 @@ static void travBFS(Gpr_t * state, comp_prog * xprog)
     freeQ(q);
 }
 
-static void travDFS(Gpr_t * state, comp_prog * xprog, trav_fns * fns)
+static void travDFS(Gpr_t * state, Expr_t* prog, comp_block * xprog, trav_fns * fns)
 {
     Agnode_t *n;
     queue *stk;
@@ -571,7 +571,7 @@ static void travDFS(Gpr_t * state, comp_prog * xprog, trav_fns * fns)
        MARK(nd);
        PUSH(nd);
        if (fns->visit & PRE_VISIT)
-           evalNode(state, xprog, n);
+           evalNode(state, prog, xprog, n);
        more = 1;
        while (more) {
            if (cure)
@@ -589,23 +589,23 @@ static void travDFS(Gpr_t * state, comp_prog * xprog, trav_fns * fns)
                     */
                    if (fns->undirected) {
                        if (ONSTACK(nd))
-                           evalEdge(state, xprog, cure);
+                           evalEdge(state, prog, xprog, cure);
                    } else
-                       evalEdge(state, xprog, cure);
+                       evalEdge(state, prog, xprog, cure);
                } else {
-                   evalEdge(state, xprog, cure);
+                   evalEdge(state, prog, xprog, cure);
                    push(stk, entry);
                    entry = cure;
                    curn = cure->node;
                    cure = 0;
                    if (fns->visit & PRE_VISIT)
-                       evalNode(state, xprog, curn);
+                       evalNode(state, prog, xprog, curn);
                    MARK(nd);
                    PUSH(nd);
                }
            } else {
                if (fns->visit & POST_VISIT)
-                   evalNode(state, xprog, curn);
+                   evalNode(state, prog, xprog, curn);
                nd = nData(curn);
                POP(nd);
                cure = entry;
@@ -620,37 +620,37 @@ static void travDFS(Gpr_t * state, comp_prog * xprog, trav_fns * fns)
     freeQ(stk);
 }
 
-static void travNodes(Gpr_t * state, comp_prog * xprog)
+static void travNodes(Gpr_t * state, Expr_t* prog, comp_block * xprog)
 {
     Agnode_t *n;
     Agraph_t *g = state->curgraph;
     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
-       evalNode(state, xprog, n);
+       evalNode(state, prog, xprog, n);
     }
 }
 
-static void travEdges(Gpr_t * state, comp_prog * xprog)
+static void travEdges(Gpr_t * state, Expr_t* prog, comp_block * xprog)
 {
     Agnode_t *n;
     Agedge_t *e;
     Agraph_t *g = state->curgraph;
     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
        for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
-           evalEdge(state, xprog, e);
+           evalEdge(state, prog, xprog, e);
        }
     }
 }
 
-static void travFlat(Gpr_t * state, comp_prog * xprog)
+static void travFlat(Gpr_t * state, Expr_t* prog, comp_block * xprog)
 {
     Agnode_t *n;
     Agedge_t *e;
     Agraph_t *g = state->curgraph;
     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
-       evalNode(state, xprog, n);
+       evalNode(state, prog, xprog, n);
        if (xprog->n_estmts > 0) {
            for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
-               evalEdge(state, xprog, e);
+               evalEdge(state, prog, xprog, e);
            }
        }
     }
@@ -658,70 +658,72 @@ static void travFlat(Gpr_t * state, comp_prog * xprog)
 
 /* traverse:
  */
-static void traverse(Gpr_t * state, comp_prog * xprog)
+static void traverse(Gpr_t * state, Expr_t* prog, comp_block * bp)
 {
     char *target;
 
-    if (state->name_used) {
-       sfprintf(state->tmp, "%s%d", state->tgtname, state->name_used);
-       target = sfstruse(state->tmp);
-    } else
-       target = state->tgtname;
-    state->name_used++;
-    state->target = openSubg(state->curgraph, target);
+    if (!state->target) {
+       if (state->name_used) {
+           sfprintf(state->tmp, "%s%d", state->tgtname, state->name_used);
+           target = sfstruse(state->tmp);
+       } else
+           target = state->tgtname;
+       state->name_used++;
+       state->target = openSubg(state->curgraph, target);
+    }
     if (!state->outgraph)
        state->outgraph = state->target;
 
     switch (state->tvt) {
     case TV_flat:
-       travFlat(state, xprog);
+       travFlat(state, prog, bp);
        break;
     case TV_bfs:
-       travBFS(state, xprog);
+       travBFS(state, prog, bp);
        break;
     case TV_dfs:
        DFSfns.visit = PRE_VISIT;
-       travDFS(state, xprog, &DFSfns);
+       travDFS(state, prog, bp, &DFSfns);
        break;
     case TV_fwd:
        FWDfns.visit = PRE_VISIT;
-       travDFS(state, xprog, &FWDfns);
+       travDFS(state, prog, bp, &FWDfns);
        break;
     case TV_rev:
        REVfns.visit = PRE_VISIT;
-       travDFS(state, xprog, &REVfns);
+       travDFS(state, prog, bp, &REVfns);
        break;
     case TV_postdfs:
        DFSfns.visit = POST_VISIT;
-       travDFS(state, xprog, &DFSfns);
+       travDFS(state, prog, bp, &DFSfns);
        break;
     case TV_postfwd:
        FWDfns.visit = POST_VISIT;
-       travDFS(state, xprog, &FWDfns);
+       travDFS(state, prog, bp, &FWDfns);
        break;
     case TV_postrev:
        REVfns.visit = POST_VISIT | PRE_VISIT;
-       travDFS(state, xprog, &REVfns);
+       travDFS(state, prog, bp, &REVfns);
        break;
     case TV_prepostdfs:
        DFSfns.visit = POST_VISIT | PRE_VISIT;
-       travDFS(state, xprog, &DFSfns);
+       travDFS(state, prog, bp, &DFSfns);
        break;
     case TV_prepostfwd:
        FWDfns.visit = POST_VISIT | PRE_VISIT;
-       travDFS(state, xprog, &FWDfns);
+       travDFS(state, prog, bp, &FWDfns);
        break;
     case TV_prepostrev:
        REVfns.visit = POST_VISIT;
-       travDFS(state, xprog, &REVfns);
+       travDFS(state, prog, bp, &REVfns);
        break;
     case TV_ne:
-       travNodes(state, xprog);
-       travEdges(state, xprog);
+       travNodes(state, prog, bp);
+       travEdges(state, prog, bp);
        break;
     case TV_en:
-       travEdges(state, xprog);
-       travNodes(state, xprog);
+       travEdges(state, prog, bp);
+       travNodes(state, prog, bp);
        break;
     }
 }
@@ -833,7 +835,7 @@ int gvpr (int argc, char *argv[], gvpropts * uopts)
     gpr_info info;
     int rv = 0;
     options* opts = 0;
-    int incoreGraphs;
+    int i, incoreGraphs;
 
     setErrorErrors (0);
     ingDisc.dflt = sfstdin;
@@ -909,17 +911,21 @@ int gvpr (int argc, char *argv[], gvpropts * uopts)
        while ((state->curgraph = nextGraph(ing))) {
            state->infname = fileName(ing);
 
-           /* begin graph */
-           if (incoreGraphs && (opts->compflags & CLONE))
-               state->curgraph = clone (0, (Agobj_t*)(state->curgraph));
-           state->curobj = (Agobj_t *) state->curgraph;
-           state->tvroot = 0;
-           if (xprog->begg_stmt)
-               exeval(xprog->prog, xprog->begg_stmt, state);
+           for (i = 0; i < xprog->n_blocks; i++) {
+               comp_block* bp = xprog->blocks + i;
 
-           /* walk graph */
-           if (walksGraph(xprog))
-               traverse(state, xprog);
+               /* begin graph */
+               if (incoreGraphs && (opts->compflags & CLONE))
+                   state->curgraph = (Agraph_t*)clone (0, (Agobj_t*)(state->curgraph));
+               state->curobj = (Agobj_t *) state->curgraph;
+               state->tvroot = 0;
+               if (bp->begg_stmt)
+                   exeval(xprog->prog, bp->begg_stmt, state);
+
+               /* walk graph */
+               if (walksGraph(bp))
+                   traverse(state, xprog->prog, bp);
+           }
 
            /* end graph */
            state->curobj = (Agobj_t *) state->curgraph;
index 5628a0176b3235c3454f1a580daed0d2a559f408..98a2a010deec1c7bc7bc4c5df85f4c139941e590 100644 (file)
@@ -395,6 +395,27 @@ parseCase(Sfio_t * str, char **guard, int *gline, char **action,
     return kind;
 }
 
+/* addBlock:
+ * create new block and append to list;
+ * return new item as tail
+ */
+static parse_block *addBlock (parse_block * last, char *stmt, int line,
+       int n_nstmts, case_info *nodelist, int n_estmts, case_info *edgelist)
+{
+    parse_block* item = newof(0, parse_block, 1, 0);
+
+    item->l_beging = line;
+    item->begg_stmt = stmt;
+    item->n_nstmts = n_nstmts;
+    item->n_estmts = n_estmts;
+    item->node_stmts = nodelist;
+    item->edge_stmts = edgelist;
+    if (last)
+       last->next = item;
+
+    return item;
+}
+
 /* addCase:
  * create new case_info and append to list;
  * return new item as tail
@@ -456,13 +477,18 @@ parse_prog *parseProg(char *input, int isFile)
     char *guard = NULL;
     char *action = NULL;
     int more;
+    parse_block *blocklist = 0;
     case_info *edgelist = 0;
     case_info *nodelist = 0;
+    parse_block *blockl = 0;
     case_info *edgel = 0;
     case_info *nodel = 0;
+    int n_blocks = 0;
     int n_nstmts = 0;
     int n_estmts = 0;
     int line = 0, gline = 0;
+    int l_beging;
+    char *begg_stmt;
 
     prog = newof(0, parse_prog, 1, 0);
     if (!prog) {
@@ -487,7 +513,8 @@ parse_prog *parseProg(char *input, int isFile)
        free (prog);
        return 0;
     }
-
+    
+    begg_stmt = 0;
     more = 1;
     while (more) {
        switch (parseCase(str, &guard, &gline, &action, &line)) {
@@ -496,8 +523,19 @@ parse_prog *parseProg(char *input, int isFile)
                       &(prog->l_begin));
            break;
        case BeginG:
-           bindAction(BeginG, action, line, &(prog->begg_stmt),
-                      &(prog->l_beging));
+           if (action && (begg_stmt || nodelist || edgelist)) { /* non-empty block */
+               blockl = addBlock(blockl, begg_stmt, l_beging, 
+                   n_nstmts, nodelist, n_estmts, edgelist);
+               if (!blocklist)
+                   blocklist = blockl;
+               n_blocks++;
+
+               /* reset values */
+               n_nstmts = n_estmts = 0;
+               edgel = nodel = edgelist = nodelist = 0;
+               begg_stmt = 0;
+           }
+           bindAction(BeginG, action, line, &begg_stmt, &l_beging);
            break;
        case End:
            bindAction(End, action, line, &(prog->end_stmt),
@@ -526,10 +564,16 @@ parse_prog *parseProg(char *input, int isFile)
        }
     }
 
-    prog->node_stmts = nodelist;
-    prog->edge_stmts = edgelist;
-    prog->n_nstmts = n_nstmts;
-    prog->n_estmts = n_estmts;
+    if (begg_stmt || nodelist || edgelist) { /* non-empty block */
+       blockl = addBlock(blockl, begg_stmt, l_beging, 
+           n_nstmts, nodelist, n_estmts, edgelist);
+       if (!blocklist)
+           blocklist = blockl;
+       n_blocks++;
+    }
+
+    prog->n_blocks = n_blocks;
+    prog->blocks = blocklist;
 
     sfclose(str);
 
@@ -554,14 +598,25 @@ freeCaseList (case_info* ip)
     }
 }
 
+static void
+freeBlocks (parse_block* ip)
+{
+    parse_block* nxt;
+    while (ip) {
+       nxt = ip->next;
+       free (ip->begg_stmt);
+       freeCaseList (ip->node_stmts);
+       freeCaseList (ip->edge_stmts);
+       ip = nxt;
+    }
+}
+
 void 
 freeParseProg (parse_prog * prog)
 {
     if (!prog) return;
     free (prog->begin_stmt);
-    free (prog->begg_stmt);
-    freeCaseList (prog->node_stmts);
-    freeCaseList (prog->edge_stmts);
+    freeBlocks (prog->blocks);
     free (prog->endg_stmt);
     free (prog->end_stmt);
     free (prog);
index da348726ddf76c76b9d8344111cd583330fd2d23..199b45d8a02830f6259cd96cbb79d78be9cb463b 100644 (file)
@@ -32,20 +32,26 @@ extern "C" {
        struct _case_info *next;
     } case_info;
 
-    typedef struct {
-       char *source;
-       int l_begin, l_beging, l_end, l_endg;
-       char *begin_stmt;
+    typedef struct _parse_block {
+       int l_beging;
        char *begg_stmt;
        int n_nstmts;
        int n_estmts;
        case_info *node_stmts;
        case_info *edge_stmts;
+       struct _parse_block *next;
+    } parse_block; 
+
+    typedef struct {
+       char *source;
+       int l_begin, l_end, l_endg;
+       char *begin_stmt;
+       int n_blocks;
+       parse_block *blocks;
        char *endg_stmt;
        char *end_stmt;
     } parse_prog;
 
-
     extern parse_prog *parseProg(char *, int);
     extern void freeParseProg (parse_prog *);