#!/usr/bin/env python3

import sys as _sys
import re as _re
import json as _json


def coin(template, arguments):
	result = template
	for (key, value, ) in arguments.items():
		result = result.replace("{{%s}}" % key, value)
	return result
	

def convert_symbol(symbol):
	if (symbol.startswith("<")):
		return {"type": "variable", "parameters": {"id": symbol[1:-1]}}
	elif (symbol.startswith("[")):
		return {"type": "terminal", "parameters": {"id": symbol[1:-1]}}
	elif (symbol.startswith("{")):
		return {"type": "label", "parameters": {"id": symbol[1:-1]}}
	else:
		raise ValueError("unknown symbol: %s" % symbol)
	

def extract_name(symbol, type_):
	conversion = convert_symbol(symbol)
	if (not (conversion["type"] == type_)):
		raise ValueError("type mismatch")
	else:
		name = conversion["parameters"]["id"]
		return (None if (name == "") else name)
	


def main():
	pattern_name = "[0-9a-zA-Z_-]*"
	pattern_terminal = coin("\\[{{pattern_name}}\\]", {"pattern_name": pattern_name})
	pattern_variable = coin("<{{pattern_name}}>", {"pattern_name": pattern_name})
	pattern_label = coin("\\{{{pattern_name}}\\}", {"pattern_name": pattern_name})
	
	rules = [
		# version
		{
			"pattern": coin(
				"@{{space}}(.+)",
				{
					"space": "\\s*",
				}
			),
			"action": lambda state, matching: {
				"version": matching.group(1),
				"specification": state["specification"],
			},
		},
		# lexer_rule
		{
			"pattern": coin(
				"{{space}}({{pattern_terminal}}){{space}}:{{space}}\"(.*)\"(?:{{space}}:{{space}}(\\S+){{space}})?",
				{
					"space": "\\s*",
					"pattern_terminal": pattern_terminal,
				}
			),
			"action": lambda state, matching: {
				"version": state["version"],
				"specification": {
					"version": state["specification"]["version"],
					"lexer_rules": (
						state["specification"]["lexer_rules"]
						+
						[{
							"pattern": matching.group(2),
							"name": extract_name(matching.group(1), "terminal"),
							"pass": (len(matching.groups()) >= 3),
						}]
					),
					"parser_rules": state["specification"]["parser_rules"],
					"parser_start": state["specification"]["parser_start"],
				}
			}
		},
		# parser_rule
		{
			"pattern": coin(
				"({{pattern_label}}){{space}}:{{space}}({{pattern_variable}}){{space}}:(.*)",
				{
					"space": "\\s*",
					"pattern_variable": pattern_variable,
					"pattern_label": pattern_label,
				}
			),
			"action": lambda state, matching: {
				"version": state["version"],
				"specification": {
					"version": state["specification"]["version"],
					"lexer_rules": state["specification"]["lexer_rules"],
					"parser_rules": (
						state["specification"]["parser_rules"]
						+
						[{
							"label": extract_name(matching.group(1), "label"),
							"premise": extract_name(matching.group(2), "variable"),
							"conclusion": list(map(
								convert_symbol,
								_re.findall(
									coin(
										"{{pattern_terminal}}|{{pattern_variable}}",
										{
											"pattern_terminal": pattern_terminal,
											"pattern_variable": pattern_variable,
										}
									),
									matching.group(3)
								)
							)),
						}]
					),
					"parser_start": state["specification"]["parser_start"],
				}
			}
		},
		# parser_start
		{
			"pattern": coin(
				"({{pattern_variable}})",
				{
					"space": "\\s*",
					"pattern_variable": pattern_variable,
				}
			),
			"action": lambda state, matching: {
				"version": state["version"],
				"specification": {
					"version": state["specification"]["version"],
					"lexer_rules": state["specification"]["lexer_rules"],
					"parser_rules": state["specification"]["parser_rules"],
					"parser_start": extract_name(matching.group(1), "variable"),
				}
			}
		},
		# empty
		{
			"pattern": ".*",
			"action": lambda state, matching: state,
		},
	]
	
	state = {
		"version": "1",
		"specification": {
			"version": "2",
			"lexer_rules": [],
			"parser_rules": [],
			"parser_start": None,
		},
	}
	content = _sys.stdin.read()
	for line in content.split("\n"):
		for rule in rules:
			matching = _re.match("^%s$" % rule["pattern"], line)
			if (not (matching is None)):
				state = rule["action"](state, matching)
				break
	_sys.stdout.write(_json.dumps(state["specification"], indent = "\t"))

main()
