# -*- Mode: Python; tab-width: 4 -*-

import kjParseBuild
import string

grammar = """
	form ::
	@R r_form_1			:: form >> definition
	@R r_form_2			:: form >> exp
	@R r_exp_1			:: exp >> int
	@R r_exp_string		:: exp >> string
	@R r_exp_2			:: exp >> varref
	@R r_exp_3			:: exp >> operator operands
	@R r_exp_4			:: exp >> if exp then exp else exp
	@R r_exp_5			:: exp >> let decl_list in exp
	@R r_exp_6			:: exp >> proc vars exp
	@R r_exp_7			:: exp >> var := exp
	@R r_exp_8			:: exp >> begin compound end
	@R r_exp_9			:: exp >> letrecproc procdecls in exp
	@R r_exp_10			:: exp >> while exp do exp
	@R r_exp_11			:: exp >> list
	@R r_exp_12			:: exp >> exp [ exp ]
	@R r_exp_13			:: exp >> letcont var in exp
	@R r_operator_1		:: operator >> varref
	@R r_operator_2		:: operator >> ( exp )
	@R r_operands_1		:: operands >> ( )
	@R r_operands_2		:: operands >> ( operand_list )
	@R r_operand_list_1	:: operand_list >> operand
	@R r_operand_list_2	:: operand_list >> operand_list , operand
	@R r_operand		:: operand >> exp
	@R r_varref			:: varref >> var
	@R r_decl_list_1	:: decl_list >> decl
	@R r_decl_list_2	:: decl_list >> decl_list ; decl
	@R r_decl			:: decl >> var = exp
	@R r_vars_1			:: vars >> ( )
	@R r_vars_2			:: vars >> ( varlist )
	@R r_varlist_1		:: varlist >> var
	@R r_varlist_2		:: varlist >> varlist , var
	@R r_compound_1		:: compound >> exp
	@R r_compound_2		:: compound >> compound ; exp
	@R r_procdecls_1	:: procdecls >> procdecl
	@R r_procdecls_2	:: procdecls >> procdecls ; procdecl
	@R r_procdecl		:: procdecl >> var ( varlist ) = exp
	@R r_definition		:: definition >> define var = exp
	@R r_list_1			:: list >> [ ]
	@R r_list_2			:: list >> [ operand_list ]
"""

non_terminals = """
	form definition exp
	operator operands operand_list operand
	varref decl_list decl
	vars varlist
	compound
	procdecls procdecl
	list
"""

int_regex = "\(-\)?[0-9]+"
var_regex = "[A-Za-z_+*-][A-Za-z0-9+*-]*"
string_regex = '"[^"]+"'

def int_interp (str):
	return string.atoi (str)

def string_interp (str):
	return str[1:-1]

def identity (str):
	return str

def build_grammar():
	g = kjParseBuild.NullCGrammar()
	g.Addterm ("int", int_regex, int_interp)
	g.Addterm ("var", var_regex, identity)
	g.Addterm ("string", string_regex, string_interp)
	g.Keywords ("if then else let in proc := begin end letrecproc define while do letcont")
	g.punct ('(),;=[]"')
	g.Nonterms (non_terminals)
	g.Declarerules (grammar)
	g.Compile()
	g.MarshalDump (open ('grammar.bin','wb'))
	return g

def bind_rules (g):

	def r_form_1 (list, context):
		return list[0]
	
	def r_form_2 (list, context):
		return list[0]

	def r_exp_1 (list, context):
		return ['lit', list[0]]

	def r_exp_string (list, context):
		return ['lit', list[0]]

	def r_exp_2 (list, context):
		return list[0]

	def r_exp_3 (list, context):
		return ['app', list[0], list[1]]

	def r_exp_4 (list, context):
		return ['conditional', list[1], list[3], list[5]]

	def r_exp_5 (list, context):
		return ['let', list[1], list[3]]

	def r_exp_7 (list, context):
		return ['varassign', list[0], list[2]]

	def r_exp_8 (list, context):
		return ['compound', list[1]]

	def r_exp_9 (list, context):
		return ['letrecproc', list[1], list[3]]

	def r_exp_11 (list, context):
		return list[0]

	def r_exp_12 (list, context):
		return ['array_ref', list[0], list[2]]

	def r_operator_1 (list, context):
		return list[0]

	def r_operator_2 (list, context):
		return list[1]

	def r_operands_1 (list, context):
		return []
	
	def r_operands_2 (list, context):
		return list[1]

	def r_operand_list_1 (list, context):
		return [list[0]]

	def r_operand_list_2 (list, context):
		return list[0] + [list[2]]
						  
	def r_operand (list, context):
		return list[0]

	def r_varref (list, context):
		return ['varref', list[0]]

	def r_decl_list_1 (list, context):
		return [list[0]]

	def r_decl_list_2 (list, context):
		return list[0] + [list[2]]

	def r_decl (list, context):
		return ['decl', list[0], list[2]]

	def r_vars_1 (list, context):
		return []

	def r_vars_2 (list, context):
		return list[1]

	def r_varlist_1 (list, context):
		return [list[0]]

	def r_varlist_2 (list, context):
		return list[0] + [list[2]]

	def r_compound_1 (list, context):
		return [list[0]]

	def r_compound_2 (list, context):
		return list[0] + [list[2]]

	def r_procdecls_1 (list, context):
		return [list[0]]

	def r_procdecls_2 (list, context):
		return list[0] + [list[2]]

	def r_procdecl (list, context):
		return ['procdecl', list[0], list[2], list[5]]

	def r_definition (list, context):
		return ['definition', list[1], list[3]]

	def r_list_1 (list, context):
		return ['list', []]
		
	def r_list_2 (list, context):
		return ['list', list[1]]

	for n,f in (
		("r_form_1",			r_form_1),
		("r_form_2",			r_form_2),
		("r_exp_1",				r_exp_1),
		("r_exp_2",				r_exp_2),
		("r_exp_3",				r_exp_3),
		("r_exp_4",				r_exp_4),
		("r_exp_5",				r_exp_5),
		("r_exp_7",				r_exp_7),
		("r_exp_8",				r_exp_8),
		("r_exp_9",				r_exp_9),
		("r_exp_11",			r_exp_11),
		("r_exp_12",			r_exp_12),
		("r_operator_1",		r_operator_1),
		("r_operator_2",		r_operator_2),
		("r_operands_1",		r_operands_1),
		("r_operands_2",		r_operands_2),
		("r_operand_list_1",	r_operand_list_1),
		("r_operand_list_2",	r_operand_list_2),
		("r_operand",			r_operand),
		("r_varref",			r_varref),
		("r_decl_list_1",		r_decl_list_1),
		("r_decl_list_2",		r_decl_list_2),
		("r_decl",				r_decl),
		("r_vars_1",			r_vars_1),
		("r_vars_2",			r_vars_2),
		("r_varlist_1",			r_varlist_1),
		("r_varlist_2",			r_varlist_2),
		("r_compound_1",		r_compound_1),
		("r_compound_2",		r_compound_2),
		("r_procdecls_1",		r_procdecls_1),
		("r_procdecls_2",		r_procdecls_2),
		("r_procdecl",			r_procdecl),
		("r_definition",		r_definition),
		("r_list_1",			r_list_1),
		("r_list_2",			r_list_2),
		("r_exp_string",		r_exp_string),
		):
		g.Bind (n,f)

def make_grammar():
	import kjParser
	try:
		g = kjParser.UnMarshalGram (
			open ('grammar.bin','rb')
			)
		g.Addterm ("int", int_regex, int_interp)
		g.Addterm ("var", var_regex, identity)
		g.Addterm ("string", string_regex, string_interp)
	except:	
		print 'building parser...'
		g = build_grammar()
		print '...done'
	bind_rules (g)
	return g
