sub check_cmd
{
	@_[0] =~ /^\s*(\w+?)\s+(.*)$/i;	# oddelenie prikazu od parametrov
	$command=lc $1;	# prikaz sa prevedie na male znaky
	$param=$2;
	if (not exists $commands{$command}) { print LOGFILE "*** unknown command [$1] on line <$.>\n"; $was_err++; return; }
	if ($commands{$command} == 1)
	{
		if ($param !~ /\W+/)
		{
			if (not exists $time_codes{$param})
			{
				$was_err++;
				print LOGFILE "*** no declaration for the time variable [$param] referenced on line <$.>\n";
			}				
			return;
		}
		if ($param =~ /^(\w+)\.(\w+)$/)
		{
			if (not exists $objects{$1})
			{
				$was_err++;
				print LOGFILE "*** there was no declaration for the object [$1] referenced on line <$.>\n";
			}
			else
			{
				if (not exists $prototypes{$objects{$1}}{$2})
				{
					$was_err++;
					print LOGFILE "*** objects of class [$objects{$1}] doesn't have variable [$2] referenced on line <$.>\n";
					return;
				}
				else
				{
					if ($prototypes{$objects{$1}}{$2} !~ /in/i)
					{
						$was_err++;
						print LOGFILE "*** variable [$2] is not an input; on line <$.>\n";
						return;
					}
				}
			}

			print OUTFILE "> $cmd_codes{$command} $obj_codes{$1}.$prototypes_codes{$objects{$1}}{$2}\n";
			return;
		}
		$was_err++;
		print LOGFILE "*** incorrect parameters [$param] to [$command] on line <$.>\n";
		return;
	}
	if ($commands{$command} == 2)
	{
		if ($param !~ /^(.+?)\s*,\s*(.+?)$/)
		{
			$was_err++;
			print LOGFILE "*** incorrect parameters [$param] to [$command] on line <$.>\n";
			return;
		}
		if ($1 =~ /(\W+)/)
		{
			$was_err++;
			print LOGFILE "*** incorrect character [$1] in variable name on line <$.>\n";
			return;
		}
		if (not exists $time_codes{$1})
		{
			print LOGFILE "*** no declaration for the time variable [$1] referenced on line <$.>\n";
			$was_err++;
			return;
		}
		if ($2 =~ /\D+/)
		{
			$was_err++;
			print LOGFILE "*** number was expected as the second parameter to [$command] on line <$.>\n";
			return;
		}
		if ($2 < 100000)		# max. casova konstanta
		{
			print OUTFILE "> $cmd_codes{$command} $time_codes{$1}.$2\n";
			return;
		}
		$was_err++;
		print LOGFILE "*** too big time constant [$2] in the [$command] command on line <$.>\n";
		return;
	}
	if ($commands{$command} == 3)
	{
		if ($param =~ /(\W+)/)
		{
			$was_err++;
			print LOGFILE "*** incorrect character [$1] in variable name on line <$.>\n";
			return;
		}
		if (not exists $time_codes{$param})
		{
			print LOGFILE "*** no declaration for the time variable [$param] referenced on line <$.>\n";
			$was_err++;
			return;
		}
		print OUTFILE "> $cmd_codes{$command} $time_codes{$param}\n";
		return;
	}
	if ($commands{$command} == 4)
	{
		if ($param !~ /(\W+)/)
		{
			$used_labels{$param}=$.;

			if (not exists $def_labels{$param})
			{
				$was_err++;
				print LOGFILE "*** label [$param] was not defined but referenced on line <$.>\n";
				return;
			}
			$next_state=$def_labels{$param};
			return;
		}
		$was_err++;
		print LOGFILE "*** wrong character [$1] in the label [$param] on line <$.>\n";
		return;
	}
	if ($commands{$command} == 5)
	{
		if ($param =~ /^"(.*)"$/)
		{
			print OUTFILE "> $cmd_codes{$command} $1\n";
			return;
		}
		$was_err++;
		print LOGFILE "*** string expected as a parameter to [$command] on line <$.>\n";
		return;
	}
}


# hlavny program
if ($#ARGV != 0) { die "*** incorrect number of parameters - input file missing!\n\n" }
if ($ARGV[0] !~ /(.+)\.prg/i) { die "*** incorrect filename [$ARGV[0]]!\n\n" }
open(LOGFILE,">".$1.".out") or die "*** can't redirect STDOUT!\n\n";
if (not open(INFILE,$ARGV[0])) {print LOGFILE "*** error opening input file [$ARGV[0]]\n\n"; die; }
if (not open(OUTFILE,">".$1.".bin")) {print LOGFILE "*** can't open output file [$1.bin]!\n\n"; die; }
binmode OUTFILE;
$was_err=0;
%prototypes=();		# 1. kluc = meno objektu, 2. kluc = meno premennej, hodnota = in|out
%used_labels=();	# mnozina klucov obsahuje mena pouzitych (referenced) navesti; hodnota je cislo riadku
%protypes_codes=();	# 1. kluc = meno objektu, 2. kluc = meno premennej, hodnota = jedinecne cislo
%class_codes=();
while($line=<INFILE>) { if ($line =~ /^\s*prototypes\s*$/i) {goto cont11} }
close INFILE;
close OUTFILE;
print LOGFILE "*** bad or missing [PROTOTYPES] statement!\n\n";
die;
cont11:
while($line=<INFILE>)
{
	if ($line =~ /^\s*[#;].*$|^$/) {next}
	if ($line =~ /^\s*end\s*$/i) {goto cont12}
	if ($line =~ /^\s*class\s+(\w+):\s*(.*)?/i)
	{
		if (not $2 eq "") { print LOGFILE "*** extra characters [$2] after object name [$1] on line <$.>\n"; $was_err++; next; }
		if ($1 =~ /time/i) { print LOGFILE "*** TIME is a predefined class - use different name; on line <$.>\n"; $was_err++; next; }
		if (defined @prototypes{$1}) { print LOGFILE "*** duplicate declaration for object class [$1] on line <$.>\n"; $was_err++; }
		@prototypes{$1}="";
		$obj=$1;
		$var_num=0;
		$class_codes{$1}=$obj_num++;
		next;
	}
	if (not defined $obj) { print LOGFILE "*** object name specification expected on line <$.>\n"; $was_err++; next; }
	if ($line !~ /^\s*(out|in)\s+(\w+)\s*$/i) { print LOGFILE "*** syntax error in prototype declaration [$obj] on line <$.>\n"; $was_err++; next; }
	if (defined $prototypes{$obj}{$2}) { print LOGFILE "*** duplicate declaration for variable [$2] of the object [$obj] on line <$.>\n"; $was_err++; next; }
	$prototypes{$obj}{$2}=$1;
	$prototypes_codes{$obj}{$2}=($var_num)++;
}
cont12:

while($line=<INFILE>) { if ($line =~ /^\s*declarations\s*$/i) {goto cont10} }
close INFILE;
close OUTFILE;
print LOGFILE "*** bad or missing [DECLARATIONS] statement!\n\n";
die;
cont10:
%objects=();	# kluce su mena deklarovanych objektov, hodnota je meno triedy
%obj_codes=();	# kluce su mena deklarovanych objektov, hodnota je jedinecne cislo
%time_codes=();	# kluce su mena deklarovanych casovych premennych, hodnota je jedinecne cislo
$obj_num=1;
$time_num=0;
#if (not open(TMPFILE,">pok.txt")) {print LOGFILE "*** Can't open output file!\n"; die; }
while($line=<INFILE>)
{
	if ($line =~ /^\s*[#;].*$|^$/) {next}
	if ($line =~ /^\s*end\s*$/i) {goto cont00}
	if ($line =~ /^\s*time\s+(.*?)\s*$/i)
	{
		@vars=split(/\s*,\s*/,$1,-1);
		foreach $var (@vars)
		{
			if (($var !~ /\w+/) or (not $var !~ /\W+/)) { print LOGFILE "*** invalid characters in TIME variable [$var] on line <$.>\n"; $was_err++; next; }
			if (exists $time_codes{$var}) { print LOGFILE "*** duplicate declaration for time variable [$var] on line <$.>\n"; $was_err++; next; }
			$time_codes{$var}=($time_num)++;
		}
		next;
	}

	if ($line !~ /^(\w+?)\s+(\w+?)\s+>\s*(\d{1,5})\s+(\d{1,5})\s+(0|1)\s+(\d{1,5})\s+(\d{1,5})\s+(\d{1,5})\s+(\d{1,5})\s+(\d{1,5})\s+(\d{1,5})\s+(\d{1,5})\s*$/) { print LOGFILE "$line*** incorrect object declaration on line <$.>\n"; $was_err++; next; }
	if (not exists $prototypes{$1}) { print LOGFILE "*** object class [$1] is not in the list of prototypes; on line <$.>\n"; $was_err++; next; }
	if (exists $objects{$2}) { print LOGFILE "*** duplicate declaration for object [$2] on line <$.>\n"; $was_err++; next; }
	$objects{$2}=$1;
	$obj_codes{$2}=$obj_num++;
	print OUTFILE "~ $2 $class_codes{$1} $3 $4 $5 $6 $7 $8 $9 $10 $11 $12\n";
}
cont00:
close TMPFILE;
if ($was_err) { close INFILE; print LOGFILE "*** there were $was_err errors in the object declaration part!\n"; die;}

while($line=<INFILE>)
{
	if ($line =~ /^\s*errdef\s*$/i) {goto cont20}
	if ($line =~ /^\s*program\s+(.+)$/i) {goto cont01}
}
goto cont30;
cont20:
while($line=<INFILE>)
{
	if ($line =~ /^\s*[#;].*$|^$/) {next}
	if ($line =~ /^\s*end\s*$/i) {goto cont30}
	if ($line =~ /^\s*([ST])\s+(\w+)\.(\w+)\s*(.*?)\s*$/)
	{
		if (not exists $objects{$2})
		{
			$was_err++;
			print LOGFILE "*** there was no declaration for the object [$2] referenced on line <$.>\n";
		}
		else
		{
			if (not exists $prototypes{$objects{$2}}{$3})
			{
				$was_err++;
				print LOGFILE "*** objects of class [$objects{$2}] doesn't have variable [$3] referenced on line <$.>\n";
				next;
			}
		}
		$var=$4;
		if ($4 eq "")
		{
			$was_err++;
			print LOGFILE "*** syntax error (too few parameters) on line <$.>\n";
			next;
		}
		print OUTFILE "\" $obj_codes{$2} $prototypes_codes{$objects{$2}}{$3} $1";
		if ($1 eq "S")
		{
			if ($4 !~ /^\s*(\d+)\s*\,\s*(\d+)\s*\,\s*(\d+)\s*$/)
			{
				$was_err++;
				print LOGFILE "*** syntax error in statistics parameters on line <$.>\n";
				next;
			}
			print OUTFILE " $1 $2 $3\n";
		}
		if ($1 eq "T")
		{
			if ($4 !~ /^\s*\(\s*$/)
			{
				$was_err++;
				print LOGFILE "*** syntax error (bracket missing) on line <$.>\n";
				next;
			}
			print OUTFILE "\n";
			while($line=<INFILE>)
			{
				if ($line =~ /^\s*[#;].*$|^$/) {next}
				if ($line =~ /^\s*\)\s*$/i) {goto cont31}
				if ($line !~ /^\s*(\d+)\s*\:\s*(\d+)\s*$/)
				{
					$was_err++;
					print LOGFILE "*** syntax error in error definition on line <$.>\n";
					next;
				}
				if ($2 > 2)
				{
					$was_err++;
					print LOGFILE "*** incorrect error type used on line <$.>\n";
					next;
				}
				print OUTFILE "\' $1 $2\n"
			}
cont31:
		}
	}
	else
	{
		$was_err++;
		print LOGFILE "*** syntax error in error definition on line <$.>\n";
		next;
	}		
}
cont30:
if ($was_err) { close INFILE; print LOGFILE "*** there were $was_err errors in the error declaration part!\n"; die;}

while($line=<INFILE>) { if ($line =~ /^\s*program\s+(.+)$/i) {goto cont01} }
close INFILE;
close OUTFILE;
print LOGFILE "*** bad or missing [PROGRAM] statement!\n\n";
die;
cont01:
print LOGFILE "\nProgram name: $1\n";

%commands=(
	set => 1,
	rst => 1,
	start => 2,
	stop => 3,
	next => 4,
	say => 5,
	halt => 5,
	error => 1
	);

%cmd_codes=(
	set => 1,
	rst => 2,
	start => 3,
	stop => 4,
	next => 5,
	say => 6,
	halt => 7,
	error => 8
	);

%sign_val=('+'=>1,'-'=>0);

while($line=<INFILE>)
{
	if ($line =~ /^\s*[#;].*$|^$/) {next}
	if ($line =~ /^\s*begin\s*$/i) {goto cont02}
	else { print LOGFILE "*** bad or missing [BEGIN] statement!\n\n"; die; }
}
cont02:
@vars=();
$lbl_num=0;
%num=();
%def_labels=();
%val=();
$back=tell;
$back_ln=$.;

while($line=<INFILE>)
{
	if ($line =~ /^\s*[#;].*$|^$/) {next}
	if ($line !~ /^\s*state\s+(.*?)\s+waits\s*\{\s*(.+?)\s*\}\s*$/i) {next}
	$label=$1;
	if ($label =~ /.*?(\W+).*?/) { print LOGFILE "*** wrong character [$1] in the label [$label] on line <$.>\n"; $was_err++; }
	if (exists $def_labels{$label}) { print LOGFILE "*** duplicate label [$label] on line <$.>\n"; $was_err++; }
	$def_labels{$label}=++$lbl_num;
}

seek (INFILE,$back,0);
$.=$back_ln;
while($line=<INFILE>)
{
	if ($line =~ /^\s*[#;].*$|^$/) {next}
cont04:
	if ($line !~ /^\s*state\s+(.*?)\s+waits\s*\{\s*(.+?)\s*\}\s*$/i) { print LOGFILE "*** syntax error in [STATE/WAITS] clause on line <$.>\n$line\n\n"; die; }
	$label=$1;
	$variables=$2;

	print OUTFILE "# $def_labels{$label}";

	@vars=split(/\s*,\s*/,$variables,-1);
	foreach $var (@vars)
	{
		if ($var !~ /\w+/) { $was_err++; print LOGFILE "*** invalid characters in WAITS list on line <$.>\n"; next; }
		if ($var !~ /\W+/)
		{
			if (not exists $time_codes{$var}) { print LOGFILE "*** no declaration for the time variable [$var] referenced on line <$.>\n"; $was_err++; next; }
			goto lbl01;
		}
		if ($var =~ /([+-])(\w+)\.(\w+)/)
		{
			if (not $` eq "")
			{
				$was_err++;
				print LOGFILE "*** extra characters [$`] before variable [$2.$3] on line <$.>\n";
			}
			if (not $' eq "")
			{
				$was_err++;
				print LOGFILE "*** extra characters [$'] after variable [$2.$3] on line <$.>\n";
			}
			if (not exists $objects{$2})
			{
				$was_err++;
				print LOGFILE "*** there was no declaration for the object [$2] referenced on line <$.>\n";
			}
			else
			{
				if (not exists $prototypes{$objects{$2}}{$3})
				{
					$was_err++;
					print LOGFILE "*** objects of class [$objects{$2}] doesn't have variable [$3] referenced on line <$.>\n";
				}
				else
				{
					if ($prototypes{$objects{$2}}{$3} !~ /out/i)
					{
						$was_err++;
						print LOGFILE "*** variable [$3] is not an output; on line <$.>\n";
					}
				}
			}
			$var=$2.".".$3;
#			@val{$var}=($1,$2,$3);
			$val{$var}[0]=$1;
			$val{$var}[1]=$2;
			$val{$var}[2]=$3;

			goto lbl01;
		}
		if ($var !~ /[+-].*/) { print LOGFILE "*** variable name [$var] doesn't have value sign <+/->; on line <$.>\n" }
		else { print LOGFILE "*** incorrect variable name [$var] on line <$.>\n" };
		$was_err++;
		next;
lbl01:
		if (++$num{$var} > 1) { print LOGFILE "*** duplicate variable name [$var] on line <$.>\n"; $was_err++; }

	}
	%num=();
	$lbl=-1;
	while($line=<INFILE>)
	{
		if ($line =~ /^\s*[#;].*$|^$/) {next}
		if ($line =~ /^\s*state/i)
		{
			if ($lbl == -1 && $#vars == 0)
			{
				if (not $val{$vars[0]}[2] eq "")
				{
					print OUTFILE "\n: $obj_codes{$val{$vars[0]}[1]}.$prototypes_codes{$objects{$val{$vars[0]}[1]}}{$val{$vars[0]}[2]}.$sign_val{$val{$vars[0]}[0]}";
				}
				else
				{
					print OUTFILE "\n: 0.$time_codes{$vars[0]}.1";
				}
				print OUTFILE "\n> 5 ".($def_labels{$label}+1);
			}
			else
			{
				if ($lbl < $#vars)
				{
					$was_err++;
					print LOGFILE "*** variable description expected before line <$.> for:\n";
					foreach $var (@vars) { if ($num{$var} == 0) { print LOGFILE "->  [$var]\n" } }
				}
			}
			print OUTFILE "\n";
			%num=();
			goto cont04;
		}
		if ($line =~ /^\s*end\s*$/i)
		{
			if ($lbl == -1 && $#vars == 0)
			{
				if (not $val{$vars[0]}[2] eq "")
				{
					print OUTFILE "\n: $obj_codes{$val{$vars[0]}[1]}.$prototypes_codes{$objects{$val{$vars[0]}[1]}}{$val{$vars[0]}[2]}.$sign_val{$val{$vars[0]}[0]}";
				}
				else
				{
					print OUTFILE "\n: 0.$time_codes{$vars[0]}.1";
				}
				print OUTFILE "\n> 5 1";
			}
			goto cont05;
		}
		if ($line !~ /^\s*[+-]?(\w+(\.\w+)?)\:\s*(.+?)\s*$/) { print LOGFILE "*** Syntax error on line <$.>\n$line\n"; die; }
		$param=$3;
		foreach $var (@vars)
		{
			if ($var eq $1)
			{
				if (++$num{$var} > 1) { print LOGFILE "*** Duplicate variable name [$var] on line <$.>\n"; $was_err++; }
				goto lbl02;
			}
		}
		print LOGFILE "*** incorrect (not defined) variable [$1] on line <$.>\n";
		$was_err++;
lbl02:
		if (not $val{$1}[2] eq "")
		{
			print OUTFILE "\n: $obj_codes{$val{$1}[1]}.$prototypes_codes{$objects{$val{$1}[1]}}{$val{$1}[2]}.$sign_val{$val{$1}[0]}\n";
		}
		else
		{
			print OUTFILE "\n: 0.$time_codes{$1}.1\n";
		}

		$next_state=0;
		$lbl++;
		if ($param eq '(')
		{
			$cmd=0;
			while($line=<INFILE>)
			{
				if ($line =~ /^\s*[#;].*$|^$/) {next}
				if ($line =~ /\s*\)\s*/)
				{
					if (not $next_state) { print OUTFILE "> 5 ".($def_labels{$label}+1) }
					else { print OUTFILE "> 5 ".$next_state }
					if ($cmd == 0) { print LOGFILE "*** command expected before ')' on line <$.>\n"; $was_err++; }
					goto cont03;
				}
				$cmd++;
				check_cmd($line);

			}
		}
		else
		{
			$cmd=$param;
			check_cmd($param);

			if (not $next_state) { print OUTFILE "> 5 ".($def_labels{$label}+1) }
			else { print OUTFILE "> 5 ".$next_state }
		}
cont03:
	}
}
print LOGFILE "*** missing the [END] of program at the end of file, line <$.>\n";
die;
cont05:
foreach $var (keys %used_labels)
{
	foreach $label (keys %def_labels)
	{
		if ($label eq $var)
		{
			next cont05;
		}
	}
	print LOGFILE "*** label [$var] was not defined but referenced on line <$used_labels{$var}>\n";
	$was_err++;
}

print OUTFILE "\n";
while (($a,$b)=each %def_labels)
{
	print OUTFILE "= $b.$a\n";
}
while (($a,$b)=each %obj_codes)
{
	print OUTFILE "- $b.$a\n";
}
print OUTFILE "!\n";





print LOGFILE "Number of states: ".keys(%def_labels)."\n";
print LOGFILE "Analyze completed with $was_err errors\n\n";
close INFILE;
close OUTFILE;
close LOGFILE;
