git @ Cat's Eye Technologies Kangaroo-Iceberg / master src / parse.c
master

Tree @master (Download .tar.gz)

parse.c @masterraw · history · blame

/*
 * Copyright (c)2004 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 kiceberg.
 * $Id$
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "scan.h"
#include "parse.h"
#include "symbol.h"

#include "graph.h"
#include "rule.h"

extern struct symbol_table	*gstab;
extern struct legislature	*glaw;

/*** GRAPH ***/

void
kangaroo_iceberg(struct scan_st *sc, struct node *global)
{
	struct symbol *name;

	while (tokis(sc, TOKEN_IDENTIFIER)) {
		name = top_level_node(sc);
		node_arc_add(global, name, 0);
	}
}

struct symbol *
top_level_node(struct scan_st *sc)
{
	struct symbol *sym = NULL;
	struct node *n;

	sym = node_name(sc, gstab, SYM_LOOKUP_DEFINE);
	n = node_lit(sc, sym);
        n = n;

	return(sym);
}

struct symbol *
node_name(struct scan_st *sc, struct symbol_table *stab, int lookup)
{
	struct symbol *sym;
	int type = SYM_TYPE_NODE;

	sym = symbol_lookup(stab, sc->token);

	if (lookup == SYM_LOOKUP_UNIQUE) {
		if (sym != NULL) {
			scan_error(sc, "Symbol '%s' already defined", sc->token);
			scan(sc);
			return(NULL);
		} else {
			sym = symbol_define(stab, sc->token, type);
			scan(sc);
			return(sym);
		}
	} else if (lookup == SYM_LOOKUP_DEFINE) {
		if (sym != NULL) {
			scan(sc);
			return(sym);
		} else {
			sym = symbol_define(stab, sc->token, type);
			scan(sc);
			return(sym);
		}
	} else if (lookup == SYM_LOOKUP_EXTANT) {
		if (sym == NULL) {
			scan_error(sc, "Symbol '%s' not defined", sc->token);
			scan(sc);
			return(NULL);
		} else {
			scan(sc);
			return(sym);
		}
	}

	return(NULL);
}

struct node *
node_lit(struct scan_st *sc, struct symbol *sym)
{
	struct node *n = NULL;
	struct ruleset *rs = NULL;

	scan_expect(sc, "{");
	n = node_new(sym);
	while (tokne(sc, "/") && tokne(sc, "}") && !tokis(sc, TOKEN_EOF)) {
		arc_defn(sc, n);
	}
	if (tokeq(sc, "/")) {
		scan(sc);
		rs = ruleset(sc, sym);
		while(tokeq(sc, ";")) {
			scan(sc);
			rs = ruleset(sc, sym);
		}
	}
	scan_expect(sc, "}");
	rs = rs;
        
	return(n);
}	

void
arc_defn(struct scan_st *sc, struct node *n)
{
	struct symbol *name;
	int weight;

	name = node_ref(sc);
	scan_expect(sc, ":");
	weight = weight_defn(sc);
	node_arc_add(n, name, weight);
}

struct symbol *
node_ref(struct scan_st *sc)
{
	struct symbol *sym = NULL;
	struct node *dest = NULL;

	if (tokeq(sc, "{")) {
		sym = symbol_new_anon(gstab, SYM_TYPE_NODE);
		dest = node_lit(sc, sym);
	} else if (tokeq(sc, "^")) {
		scan(sc);
		sym = node_name(sc, gstab, SYM_LOOKUP_DEFINE);
	} else if (tokis(sc, TOKEN_IDENTIFIER)) {
		sym = node_name(sc, gstab, SYM_LOOKUP_UNIQUE);
		dest = node_lit(sc, sym);
	} else {
		scan_error(sc, "Expected identifier, `^', or `{'");
	}
        dest = dest;
	return(sym);
}

int
weight_defn(struct scan_st *sc)
{
	int weight;

	weight = atoi(sc->token);
	scan(sc);

	return(weight);
}

/*** RULES ***/

struct ruleset *
ruleset(struct scan_st *sc, struct symbol *sym)
{
	struct ruleset *rs;

	rs = ruleset_new(glaw, sym);
	rule(sc, rs);
	while(tokeq(sc, ",")) {
		scan(sc);
		rule(sc, rs);
	}

	ruleset_dump(rs);

	return(rs);
}

void
rule(struct scan_st *sc, struct ruleset *rs)
{
	struct rule *r;

	r = rule_new(rs);
	while(tokne(sc, "->") && !tokis(sc, TOKEN_EOF)) {
		arc_app(sc, r, PATTERN_ADD_MATCH);
	}
	scan_expect(sc, "->");
	while(tokne(sc, ",") && tokne(sc, ";") && tokne(sc, "}") &&
	      !tokis(sc, TOKEN_EOF)) {
		arc_app(sc, r, PATTERN_ADD_REWRITE);
	}
}

void
arc_app(struct scan_st *sc, struct rule *r, int which_side)
{
	struct symbol *name;
	int weight;

	name = node_app(sc);
	scan_expect(sc, ":");
	weight = weight_app(sc);
	rule_pattern_add(which_side, r, name, weight);
}

struct symbol *
node_app(struct scan_st *sc)
{
	struct symbol *name = NULL;

	if (tokeq(sc, "$")) {
		var_name(sc);
	} else {
		name = node_ref(sc);
	}
	
	return(name);
}

int
weight_app(struct scan_st *sc)
{
	int weight = 0;

	if (tokeq(sc, "$")) {
		var_name(sc);
	} else {
		weight = weight_defn(sc);
	}
	
	return(weight);
}

void
var_name(struct scan_st *sc)
{
	scan_expect(sc, "$");
	scan(sc);
}