Description: a test case ensuring bit-by-bit reproducibility of
 Parse::Yapp-generated parser.
Bug: https://rt.cpan.org/Public/Bug/Display.html?id=122977
Bug-Debian: https://bugs.debian.org/903979
Forwarded: https://rt.cpan.org/Ticket/Display.html?id=122977#txn-1796659
Author: Andrius Merkys <andrius.merkys@gmail.com>
Last-Update: 2018-07-19

--- /dev/null
+++ b/t/reproducibility.t
@@ -0,0 +1,412 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use Parse::Yapp;
+use Text::Diff;
+
+BEGIN { $| = 1; print "1..1\n"; }
+
+open( my $inp, 'Calc.yp' );
+my $grammar = join '', <$inp>;
+close $inp;
+
+my $parser = new Parse::Yapp( input => $grammar );
+
+my $output_new = $parser->Output( classname => 'Calc' );
+$output_new =~ s/(Parse::Yapp version )\d+\.\d+/$1<version>/;
+$output_new =~ s/(yyversion => ')[^']+'/$1<version>'/;
+
+my $output_old = join '', <DATA>;
+close DATA;
+
+my $diff = diff \$output_old, \$output_new;
+if( $diff ) {
+    print "not ok 1\n";
+    print "Non-zero diff:\n" . $diff;
+    exit(1);
+} else {
+    print "ok 1\n";
+}
+
+__DATA__
+####################################################################
+#
+#    This file was generated using Parse::Yapp version <version>.
+#
+#        Don't edit this file, use source file instead.
+#
+#             ANY CHANGE MADE HERE WILL BE LOST !
+#
+####################################################################
+package Calc;
+use vars qw ( @ISA );
+use strict;
+
+@ISA= qw ( Parse::Yapp::Driver );
+use Parse::Yapp::Driver;
+
+
+
+sub new {
+        my($class)=shift;
+        ref($class)
+    and $class=ref($class);
+
+    my($self)=$class->SUPER::new( yyversion => '<version>',
+                                  yystates =>
+[
+	{#State 0
+		DEFAULT => -1,
+		GOTOS => {
+			'input' => 1
+		}
+	},
+	{#State 1
+		ACTIONS => {
+			'' => 2,
+			"(" => 3,
+			"-" => 4,
+			"\n" => 5,
+			'NUM' => 6,
+			'VAR' => 7,
+			'error' => 8
+		},
+		GOTOS => {
+			'exp' => 9,
+			'line' => 10
+		}
+	},
+	{#State 2
+		DEFAULT => 0
+	},
+	{#State 3
+		ACTIONS => {
+			"(" => 3,
+			"-" => 4,
+			'NUM' => 6,
+			'VAR' => 7
+		},
+		GOTOS => {
+			'exp' => 11
+		}
+	},
+	{#State 4
+		ACTIONS => {
+			"(" => 3,
+			"-" => 4,
+			'NUM' => 6,
+			'VAR' => 7
+		},
+		GOTOS => {
+			'exp' => 12
+		}
+	},
+	{#State 5
+		DEFAULT => -3
+	},
+	{#State 6
+		DEFAULT => -6
+	},
+	{#State 7
+		ACTIONS => {
+			"=" => 13
+		},
+		DEFAULT => -7
+	},
+	{#State 8
+		ACTIONS => {
+			"\n" => 14
+		}
+	},
+	{#State 9
+		ACTIONS => {
+			"*" => 15,
+			"+" => 16,
+			"-" => 17,
+			"/" => 18,
+			"\n" => 19,
+			"^" => 20
+		}
+	},
+	{#State 10
+		DEFAULT => -2
+	},
+	{#State 11
+		ACTIONS => {
+			")" => 21,
+			"*" => 15,
+			"+" => 16,
+			"-" => 17,
+			"/" => 18,
+			"^" => 20
+		}
+	},
+	{#State 12
+		ACTIONS => {
+			"^" => 20
+		},
+		DEFAULT => -13
+	},
+	{#State 13
+		ACTIONS => {
+			"(" => 3,
+			"-" => 4,
+			'NUM' => 6,
+			'VAR' => 7
+		},
+		GOTOS => {
+			'exp' => 22
+		}
+	},
+	{#State 14
+		DEFAULT => -5
+	},
+	{#State 15
+		ACTIONS => {
+			"(" => 3,
+			"-" => 4,
+			'NUM' => 6,
+			'VAR' => 7
+		},
+		GOTOS => {
+			'exp' => 23
+		}
+	},
+	{#State 16
+		ACTIONS => {
+			"(" => 3,
+			"-" => 4,
+			'NUM' => 6,
+			'VAR' => 7
+		},
+		GOTOS => {
+			'exp' => 24
+		}
+	},
+	{#State 17
+		ACTIONS => {
+			"(" => 3,
+			"-" => 4,
+			'NUM' => 6,
+			'VAR' => 7
+		},
+		GOTOS => {
+			'exp' => 25
+		}
+	},
+	{#State 18
+		ACTIONS => {
+			"(" => 3,
+			"-" => 4,
+			'NUM' => 6,
+			'VAR' => 7
+		},
+		GOTOS => {
+			'exp' => 26
+		}
+	},
+	{#State 19
+		DEFAULT => -4
+	},
+	{#State 20
+		ACTIONS => {
+			"(" => 3,
+			"-" => 4,
+			'NUM' => 6,
+			'VAR' => 7
+		},
+		GOTOS => {
+			'exp' => 27
+		}
+	},
+	{#State 21
+		DEFAULT => -15
+	},
+	{#State 22
+		ACTIONS => {
+			"*" => 15,
+			"+" => 16,
+			"-" => 17,
+			"/" => 18,
+			"^" => 20
+		},
+		DEFAULT => -8
+	},
+	{#State 23
+		ACTIONS => {
+			"^" => 20
+		},
+		DEFAULT => -11
+	},
+	{#State 24
+		ACTIONS => {
+			"*" => 15,
+			"/" => 18,
+			"^" => 20
+		},
+		DEFAULT => -9
+	},
+	{#State 25
+		ACTIONS => {
+			"*" => 15,
+			"/" => 18,
+			"^" => 20
+		},
+		DEFAULT => -10
+	},
+	{#State 26
+		ACTIONS => {
+			"^" => 20
+		},
+		DEFAULT => -12
+	},
+	{#State 27
+		ACTIONS => {
+			"^" => 20
+		},
+		DEFAULT => -14
+	}
+],
+                                  yyrules  =>
+[
+	[#Rule 0
+		 '$start', 2, undef
+	],
+	[#Rule 1
+		 'input', 0, undef
+	],
+	[#Rule 2
+		 'input', 2,
+sub
+#line 17 "unkown"
+{ push(@{$_[1]},$_[2]); $_[1] }
+	],
+	[#Rule 3
+		 'line', 1,
+sub
+#line 20 "unkown"
+{ $_[1] }
+	],
+	[#Rule 4
+		 'line', 2,
+sub
+#line 21 "unkown"
+{ print "$_[1]\n" }
+	],
+	[#Rule 5
+		 'line', 2,
+sub
+#line 22 "unkown"
+{ $_[0]->YYErrok }
+	],
+	[#Rule 6
+		 'exp', 1, undef
+	],
+	[#Rule 7
+		 'exp', 1,
+sub
+#line 26 "unkown"
+{ $_[0]->YYData->{VARS}{$_[1]} }
+	],
+	[#Rule 8
+		 'exp', 3,
+sub
+#line 27 "unkown"
+{ $_[0]->YYData->{VARS}{$_[1]}=$_[3] }
+	],
+	[#Rule 9
+		 'exp', 3,
+sub
+#line 28 "unkown"
+{ $_[1] + $_[3] }
+	],
+	[#Rule 10
+		 'exp', 3,
+sub
+#line 29 "unkown"
+{ $_[1] - $_[3] }
+	],
+	[#Rule 11
+		 'exp', 3,
+sub
+#line 30 "unkown"
+{ $_[1] * $_[3] }
+	],
+	[#Rule 12
+		 'exp', 3,
+sub
+#line 31 "unkown"
+{
+                                      $_[3]
+                                  and return($_[1] / $_[3]);
+                                  $_[0]->YYData->{ERRMSG}
+                                    =   "Illegal division by zero.\n";
+                                  $_[0]->YYError;
+                                  undef
+                                }
+	],
+	[#Rule 13
+		 'exp', 2,
+sub
+#line 39 "unkown"
+{ -$_[2] }
+	],
+	[#Rule 14
+		 'exp', 3,
+sub
+#line 40 "unkown"
+{ $_[1] ** $_[3] }
+	],
+	[#Rule 15
+		 'exp', 3,
+sub
+#line 41 "unkown"
+{ $_[2] }
+	]
+],
+                                  @_);
+    bless($self,$class);
+}
+
+#line 44 "unkown"
+
+
+sub _Error {
+        exists $_[0]->YYData->{ERRMSG}
+    and do {
+        print $_[0]->YYData->{ERRMSG};
+        delete $_[0]->YYData->{ERRMSG};
+        return;
+    };
+    print "Syntax error.\n";
+}
+
+sub _Lexer {
+    my($parser)=shift;
+
+        $parser->YYData->{INPUT}
+    or  $parser->YYData->{INPUT} = <STDIN>
+    or  return('',undef);
+
+    $parser->YYData->{INPUT}=~s/^[ \t]//;
+
+    for ($parser->YYData->{INPUT}) {
+        s/^([0-9]+(?:\.[0-9]+)?)//
+                and return('NUM',$1);
+        s/^([A-Za-z][A-Za-z0-9_]*)//
+                and return('VAR',$1);
+        s/^(.)//s
+                and return($1,$1);
+    }
+}
+
+sub Run {
+    my($self)=shift;
+    $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error );
+}
+
+my($calc)=new Calc;
+$calc->Run;
+
+1;
