#!/usr/bin/perl
# Compiler of The Graphomaton to Pascal
# (c) 2006 Martin Mares <mj@ucw.cz>

use strict;
use warnings;

my $var_decl = 0;
my %vars = ( "vv" => undef, "s" => undef, "p" => undef );

my $h = <>;
my ($deg) = $h =~ /^#deg\s+(\d+)\s*$/ or die "Missing #deg";

print "program graphomaton;\n";
while (<>) {
	s/{[^{}]*}//g;
	/[{}]/ && die "Multi-line comments not supported";
	/^\s*$/ && next;
	if (/^var\s+/) {
		print "const\tdeg = $deg;\n";
		print "type\tpvertex = ^vertex;\n";
		print "\tvertex = record\n";
		print "\t\ts: array [1..deg] of pvertex;\n";
		print "\t\tp: array [1..deg] of 1..deg;\n";
		print "\t\tstop: boolean;\n";
		s/^var//;
		$var_decl = 1;
	}
	if (/^begin/) {
		$var_decl || die "No variables declared";
		$var_decl = 0;
		print "\tend;\n\n";
		print "procedure init(vv: pvertex);\nbegin\n";
		print "\twith vv^ do begin\n";
		foreach my $v (sort keys %vars) {
			print "\t\t$v := $vars{$v};\n" if defined $vars{$v};
		}
		print "\tend;\n";
		print "end;\n\n";
		print "procedure dump(vv: pvertex);\nbegin\n";
		print "\twith vv^ do begin\n";
		foreach my $v (sort keys %vars) {
			if (defined $vars{$v}) {
				print "\t\twrite(' $v=', $v);\n";
			}
		}
		print "\tend;\n";
		print "end;\n\n";
		print "procedure run(vv: pvertex);\nbegin\nwith vv^ do begin\n";
		print "\tstop := false;\n";
		next;
	} elsif (/^end\./) {
		print "end;\nend;\n";
		next;
	} elsif (/^\w/) {
		die "Unknown top-level construct";
	}
	if ($var_decl) {
		my ($vars, $type, $init) = /^\s+(.*):([^=]+)(=.*)?;\s*$/ or die "Incomprehensible declaration: $_";
		if (defined $init) {
			$init =~ /^=\s*(\d+)\s*$/ or die "Nasty initializer: $init";
			$init = $1;
		}
		$type =~ s/^\s+//; $type =~ s/\s+$//;
		$type =~ /^\d+\.\.\d+$/ or die "Barbaric type: $type";
		foreach my $v (split(/,/, $vars)) {
			$v =~ s/^\s+//; $v =~ s/\s+$//;
			$v =~ tr/A-Z/a-z/;
			!exists $vars{$v} or die "Duplicate variable: $v";
			$vars{$v} = $init;
			if ($v eq "x") { defined($init) && die "Input must not have an explicit initializer"; }
			elsif (!defined $init) { $init = 0; }	# Defaulting initializer to 0
			print "\t\t$v: $type;";
			print " { = $init }" if defined $init;
			print "\n";
		}
	} else {
		sub maybevar($) {
			my $v = shift @_;
			$v =~ tr/A-Z/a-z/;
			return $v;
		}
		s/(\w+)/maybevar($1)/ge;
		s/]\./]^./g;
		s/\bstop\b/stop := true/g;
		print;
	}
}

print "\n";
open RT, "runtime" or die "Cannot open runtime";
while (<RT>) {
	print;
}
close RT;
