$yysccsid = "@(#)yaccpar 1.8 (Berkeley) 01/20/91 (Perl 2.0 12/31/92)"; #define YYBYACC 1 #line 49 "bc.y" ;# I don't use BigFloat any more because they lack operators such as **, ;# and they're very, very slow ;## BigFloat calls a function it does not define ;#sub Math::BigFloat::panic { die $_[0]; } ;#use Math::BigFloat; ;# The symbol table : the keys are the identifiers, the value is in the ;# "var" field if it is a variable, in the "func" field if it is a ;# function. my %sym_table; my @stmt_list = (); my @ope_stack; my @backup_sym_table; my $input; my $cur_file = '-'; $debug = 0; sub debug(&) { my $fn = shift; print STDERR "\t".&$fn() if $debug; } ;#$yydebug=1; #line 32 "y.tab.pl" $INT=257; $FLOAT=258; $STRING=259; $IDENT=260; $C_COMMENT=261; $BREAK=262; $DEFINE=263; $AUTO=264; $RETURN=265; $PRINT=266; $AUTO_LIST=267; $IF=268; $ELSE=269; $QUIT=270; $WHILE=271; $FOR=272; $EQ=273; $NE=274; $GT=275; $GE=276; $LT=277; $LE=278; $PP=279; $MM=280; $P_EQ=281; $M_EQ=282; $F_EQ=283; $D_EQ=284; $EXP_EQ=285; $MOD_EQ=286; $L_SHIFT=287; $R_SHIFT=288; $E_E=289; $O_O=290; $EXP=291; $UNARY=292; $PPP=293; $MMM=294; $YYERRCODE=256; @yylhs = ( -1, 0, 0, 1, 1, 1, 3, 4, 9, 3, 3, 3, 12, 3, 13, 3, 14, 3, 15, 17, 3, 18, 19, 20, 3, 3, 10, 10, 16, 16, 8, 8, 6, 6, 2, 2, 5, 5, 22, 22, 23, 23, 24, 24, 7, 7, 25, 25, 11, 11, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 26, 26, ); @yylen = ( 2, 0, 2, 1, 2, 2, 1, 0, 0, 13, 1, 1, 0, 3, 0, 4, 0, 7, 0, 0, 8, 0, 0, 0, 13, 1, 1, 4, 0, 1, 1, 3, 0, 1, 1, 1, 0, 1, 1, 3, 0, 1, 1, 3, 0, 3, 1, 3, 1, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 6, 1, 1, 1, 1, 1, 4, ); @yydefred = ( 1, 0, 0, 85, 86, 87, 0, 0, 11, 7, 0, 12, 0, 6, 18, 0, 0, 0, 0, 0, 0, 14, 0, 34, 35, 2, 3, 0, 10, 0, 0, 5, 0, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 76, 77, 80, 74, 0, 0, 75, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 78, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 51, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 0, 0, 0, 27, 0, 16, 0, 21, 0, 15, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 89, 31, 0, 0, 0, 33, 0, 19, 0, 0, 39, 17, 0, 22, 0, 20, 0, 0, 0, 0, 8, 23, 46, 0, 0, 0, 0, 45, 0, 0, 47, 9, 24, ); @yydgoto = ( 1, 25, 140, 86, 36, 129, 141, 155, 90, 159, 28, 82, 38, 48, 132, 40, 91, 147, 134, 151, 160, 29, 130, 77, 78, 158, 30, ); @yysindex = ( 0, 475, -8, 0, 0, 0, 84, -239, 0, 0, -11, 0, 3, 0, 0, 19, -218, -218, 899, 899, 899, 0, 899, 0, 0, 0, 0, -8, 0, 893, -54, 0, 899, 899, 899, 0, -199, 899, 899, 958, 24, 958, -26, 0, 0, 0, 0, -32, 958, 0, 0, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 899, 0, 0, 893, 893, 25, 48, 830, 65, 852, 64, 893, 27, 958, 0, 53, 899, 0, 26, 0, 923, 923, 142, 142, 142, 142, 416, 416, -21, -21, -30, -30, -29, -29, -180, -180, 142, 142, 142, 142, 142, 142, 0, 899, 67, -146, 0, 899, 0, 85, 0, 874, 0, 958, 893, 899, 0, 86, 87, 893, -8, -8, 958, 0, 0, 893, -8, -127, 0, 958, 0, 88, 41, 0, 0, 958, 0, -8, 0, 958, -116, 108, -103, 0, 0, 0, 18, 958, -8, -100, 0, 31, 958, 0, 0, 0, ); @yyrindex = ( 0, 0, 0, 0, 0, 0, -10, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 37, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 119, 57, 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, -40, 0, 139, 0, 0, 0, 34, 66, 0, 145, 0, 0, 0, 0, 0, 0, 820, 822, 507, 518, 537, 551, 405, 442, 298, 380, 122, 192, 129, 167, 76, 99, 572, 579, 680, 758, 777, 799, 0, 0, 13, 149, 0, 0, 0, 0, 0, 0, 0, 36, -38, 0, 0, 0, 153, 93, 1023, 1023, 119, 0, 0, 29, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, 499, 0, 0, 0, 0, 0, 0, 36, 1023, 0, 0, 0, 0, 0, 0, 0, ); @yygindex = ( 0, 0, 358, 52, 0, 0, -108, 0, 38, 0, 0, 0, 0, 0, 0, 0, 337, 0, 0, 0, 0, 1278, 0, 0, 0, 0, 2, ); $YYTABLESIZE=1405; @yytable = ( 88, 42, 24, 43, 42, 65, 43, 65, 65, 89, 63, 61, 63, 62, 82, 64, 65, 64, 43, 44, 35, 63, 61, 89, 62, 142, 64, 88, 24, 37, 144, 88, 88, 88, 88, 88, 24, 88, 26, 83, 25, 24, 42, 39, 13, 82, 28, 84, 82, 88, 89, 23, 164, 27, 89, 89, 89, 89, 89, 41, 89, 80, 161, 82, 85, 88, 114, 88, 120, 26, 83, 25, 89, 83, 84, 13, 48, 23, 84, 84, 84, 84, 84, 88, 84, 23, 67, 26, 83, 25, 23, 84, 115, 13, 88, 28, 84, 82, 88, 88, 88, 88, 88, 49, 88, 117, 89, 48, 119, 66, 48, 66, 122, 67, 128, 88, 88, 67, 67, 67, 67, 67, 83, 67, 33, 48, 133, 138, 127, 82, 84, 139, 62, 145, 49, 67, 66, 49, 89, 64, 66, 66, 66, 66, 66, 32, 66, 148, 154, 156, 88, 124, 49, 26, 83, 25, 166, 157, 66, 13, 165, 28, 84, 62, 149, 62, 62, 62, 40, 67, 64, 64, 64, 64, 64, 34, 64, 65, 28, 65, 41, 62, 88, 32, 63, 61, 28, 62, 64, 64, 36, 48, 66, 146, 37, 0, 0, 163, 0, 150, 0, 67, 63, 0, 0, 0, 0, 0, 65, 65, 65, 65, 65, 0, 65, 62, 167, 0, 49, 0, 0, 0, 64, 0, 66, 0, 65, 67, 68, 69, 70, 71, 72, 63, 0, 63, 63, 63, 0, 73, 74, 51, 52, 53, 54, 55, 56, 62, 0, 0, 0, 63, 0, 0, 64, 57, 58, 59, 60, 66, 65, 66, 66, 88, 88, 88, 88, 88, 88, 0, 66, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 0, 88, 88, 63, 89, 89, 89, 89, 89, 89, 65, 0, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 0, 89, 89, 53, 0, 84, 84, 84, 84, 84, 84, 0, 63, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, 0, 88, 88, 88, 88, 88, 88, 0, 0, 0, 53, 0, 0, 53, 0, 88, 88, 88, 88, 88, 67, 67, 67, 67, 67, 67, 0, 0, 53, 0, 26, 31, 0, 0, 67, 67, 67, 67, 0, 0, 0, 0, 0, 66, 66, 66, 66, 66, 66, 87, 0, 0, 0, 0, 0, 0, 50, 66, 66, 66, 66, 52, 53, 0, 0, 0, 62, 62, 62, 62, 62, 62, 0, 64, 64, 64, 64, 64, 64, 0, 62, 62, 62, 62, 0, 0, 60, 64, 64, 64, 64, 0, 52, 121, 53, 52, 0, 0, 0, 0, 57, 58, 59, 60, 66, 0, 0, 0, 0, 0, 52, 65, 65, 65, 65, 65, 65, 60, 0, 125, 60, 0, 0, 61, 65, 65, 65, 65, 65, 63, 61, 0, 62, 136, 64, 60, 63, 63, 63, 63, 63, 63, 143, 0, 52, 0, 0, 0, 0, 0, 63, 63, 63, 63, 61, 0, 24, 61, 0, 153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 61, 0, 0, 0, 52, 0, 152, 22, 44, 0, 0, 0, 7, 0, 20, 162, 56, 18, 0, 19, 125, 0, 0, 0, 0, 0, 0, 57, 0, 60, 0, 44, 0, 23, 61, 0, 44, 0, 44, 0, 0, 44, 0, 44, 0, 0, 58, 56, 0, 0, 56, 0, 0, 0, 0, 0, 0, 44, 57, 0, 59, 57, 0, 0, 0, 56, 61, 0, 0, 0, 53, 53, 53, 53, 53, 53, 57, 58, 0, 0, 58, 68, 0, 0, 53, 53, 53, 53, 69, 0, 0, 59, 0, 0, 59, 58, 0, 21, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 57, 0, 68, 0, 0, 68, 0, 0, 0, 69, 0, 44, 69, 44, 0, 0, 0, 0, 0, 58, 68, 56, 0, 0, 0, 0, 0, 69, 0, 0, 0, 0, 57, 59, 0, 0, 0, 0, 0, 0, 0, 0, 52, 52, 52, 52, 52, 52, 0, 0, 0, 58, 0, 0, 68, 0, 52, 52, 52, 52, 0, 69, 0, 0, 0, 59, 0, 60, 60, 60, 60, 60, 60, 0, 0, 0, 0, 0, 0, 70, 0, 60, 60, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 69, 59, 60, 66, 0, 0, 0, 0, 0, 0, 0, 61, 61, 61, 61, 61, 61, 70, 0, 0, 70, 0, 0, 0, 0, 61, 61, 2, 3, 4, 5, 6, 0, 8, 9, 70, 10, 11, 0, 12, 0, 13, 14, 15, 0, 0, 0, 0, 0, 0, 16, 17, 44, 44, 44, 44, 0, 44, 44, 0, 44, 44, 0, 44, 71, 44, 44, 44, 0, 70, 0, 0, 0, 0, 44, 44, 56, 56, 56, 56, 56, 56, 0, 72, 0, 0, 0, 57, 57, 57, 57, 57, 57, 0, 0, 71, 0, 0, 71, 0, 0, 70, 0, 0, 0, 73, 58, 58, 58, 58, 58, 58, 0, 71, 72, 0, 0, 72, 0, 0, 59, 59, 59, 59, 59, 59, 54, 0, 55, 0, 0, 0, 72, 0, 0, 0, 73, 0, 0, 73, 0, 68, 68, 68, 68, 68, 68, 71, 69, 69, 69, 69, 69, 69, 73, 0, 0, 54, 0, 55, 54, 0, 55, 65, 0, 0, 72, 0, 63, 61, 0, 62, 0, 64, 0, 54, 0, 55, 0, 71, 0, 0, 0, 0, 0, 65, 0, 0, 73, 118, 63, 61, 0, 62, 0, 64, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 54, 0, 55, 63, 61, 0, 62, 0, 64, 0, 116, 73, 0, 0, 0, 0, 0, 65, 0, 22, 0, 0, 63, 61, 7, 62, 20, 64, 0, 18, 0, 19, 54, 0, 55, 0, 0, 0, 0, 0, 70, 70, 70, 70, 70, 70, 0, 65, 0, 0, 0, 0, 63, 61, 135, 62, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 7, 0, 20, 0, 0, 18, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 71, 71, 71, 71, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 72, 72, 72, 72, 72, 32, 0, 0, 0, 0, 32, 0, 32, 0, 0, 32, 0, 32, 0, 0, 0, 73, 73, 73, 73, 73, 73, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, 54, 55, 55, 0, 0, 0, 0, 0, 0, 51, 52, 53, 54, 55, 56, 0, 0, 0, 0, 0, 0, 0, 0, 57, 58, 59, 60, 66, 0, 0, 0, 51, 52, 53, 54, 55, 56, 0, 0, 0, 0, 0, 0, 0, 0, 57, 58, 59, 60, 66, 0, 0, 32, 51, 52, 53, 54, 55, 56, 0, 0, 0, 3, 4, 5, 6, 0, 57, 58, 59, 60, 66, 51, 52, 53, 54, 55, 56, 0, 0, 0, 0, 0, 0, 16, 17, 57, 58, 59, 60, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, 55, 56, 0, 0, 0, 0, 0, 0, 0, 0, 57, 58, 59, 60, 66, 3, 4, 5, 6, 0, 8, 9, 0, 10, 11, 0, 12, 0, 13, 14, 15, 0, 0, 0, 0, 0, 0, 16, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 32, 32, 32, 0, 32, 32, 0, 32, 32, 0, 32, 0, 32, 32, 32, 45, 46, 47, 0, 49, 0, 32, 32, 0, 0, 0, 0, 0, 0, 75, 76, 79, 0, 0, 81, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 126, 0, 0, 0, 131, 0, 0, 0, 0, 0, 0, 0, 137, ); @yycheck = ( 10, 41, 10, 41, 44, 37, 44, 37, 37, 41, 42, 43, 42, 45, 10, 47, 37, 47, 16, 17, 259, 42, 43, 10, 45, 133, 47, 37, 10, 40, 138, 41, 42, 43, 44, 45, 10, 47, 10, 10, 10, 10, 260, 40, 10, 41, 10, 10, 44, 59, 37, 59, 160, 1, 41, 42, 43, 44, 45, 40, 47, 260, 44, 59, 40, 91, 41, 10, 41, 41, 41, 41, 59, 44, 37, 41, 10, 59, 41, 42, 43, 44, 45, 93, 47, 59, 10, 59, 59, 59, 59, 39, 44, 59, 37, 59, 59, 93, 41, 42, 43, 44, 45, 10, 47, 40, 93, 41, 44, 10, 44, 291, 59, 37, 260, 125, 59, 41, 42, 43, 44, 45, 93, 47, 40, 59, 41, 41, 61, 125, 93, 44, 10, 260, 41, 59, 37, 44, 125, 10, 41, 42, 43, 44, 45, 61, 47, 59, 264, 41, 93, 125, 59, 125, 125, 125, 125, 260, 59, 125, 260, 125, 125, 41, 123, 43, 44, 45, 41, 93, 41, 42, 43, 44, 45, 91, 47, 10, 59, 37, 41, 59, 125, 123, 42, 43, 41, 45, 59, 47, 41, 125, 93, 141, 41, -1, -1, 159, -1, 147, -1, 125, 10, -1, -1, -1, -1, -1, 41, 42, 43, 44, 45, -1, 47, 93, 164, -1, 125, -1, -1, -1, 93, -1, 125, -1, 59, 281, 282, 283, 284, 285, 286, 41, -1, 43, 44, 45, -1, 293, 294, 273, 274, 275, 276, 277, 278, 125, -1, -1, -1, 59, -1, -1, 125, 287, 288, 289, 290, 291, 93, 291, 291, 273, 274, 275, 276, 277, 278, -1, 291, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, -1, 293, 294, 93, 273, 274, 275, 276, 277, 278, 125, -1, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, -1, 293, 294, 10, -1, 273, 274, 275, 276, 277, 278, -1, 125, -1, -1, -1, -1, -1, -1, 287, 288, 289, 290, 291, -1, 273, 274, 275, 276, 277, 278, -1, -1, -1, 41, -1, -1, 44, -1, 287, 288, 289, 290, 291, 273, 274, 275, 276, 277, 278, -1, -1, 59, -1, 1, 2, -1, -1, 287, 288, 289, 290, -1, -1, -1, -1, -1, 273, 274, 275, 276, 277, 278, 41, -1, -1, -1, -1, -1, -1, 27, 287, 288, 289, 290, 10, 93, -1, -1, -1, 273, 274, 275, 276, 277, 278, -1, 273, 274, 275, 276, 277, 278, -1, 287, 288, 289, 290, -1, -1, 10, 287, 288, 289, 290, -1, 41, 85, 125, 44, -1, -1, -1, -1, 287, 288, 289, 290, 291, -1, -1, -1, -1, -1, 59, 273, 274, 275, 276, 277, 278, 41, -1, 90, 44, -1, -1, 10, 37, 287, 288, 289, 290, 42, 43, -1, 45, 125, 47, 59, 273, 274, 275, 276, 277, 278, 134, -1, 93, -1, -1, -1, -1, -1, 287, 288, 289, 290, 41, -1, 10, 44, -1, 151, -1, -1, -1, -1, -1, -1, -1, -1, -1, 93, -1, -1, 59, -1, -1, -1, 125, -1, 149, 33, 10, -1, -1, -1, 38, -1, 40, 158, 10, 43, -1, 45, 163, -1, -1, -1, -1, -1, -1, 10, -1, 125, -1, 33, -1, 59, 93, -1, 38, -1, 40, -1, -1, 43, -1, 45, -1, -1, 10, 41, -1, -1, 44, -1, -1, -1, -1, -1, -1, 59, 41, -1, 10, 44, -1, -1, -1, 59, 125, -1, -1, -1, 273, 274, 275, 276, 277, 278, 59, 41, -1, -1, 44, 10, -1, -1, 287, 288, 289, 290, 10, -1, -1, 41, -1, -1, 44, 59, -1, 123, -1, 93, -1, -1, -1, -1, -1, -1, -1, -1, -1, 59, 93, -1, 41, -1, -1, 44, -1, -1, -1, 41, -1, 123, 44, 125, -1, -1, -1, -1, -1, 93, 59, 125, -1, -1, -1, -1, -1, 59, -1, -1, -1, -1, 125, 93, -1, -1, -1, -1, -1, -1, -1, -1, 273, 274, 275, 276, 277, 278, -1, -1, -1, 125, -1, -1, 93, -1, 287, 288, 289, 290, -1, 93, -1, -1, -1, 125, -1, 273, 274, 275, 276, 277, 278, -1, -1, -1, -1, -1, -1, 10, -1, 287, 288, -1, -1, -1, 125, -1, -1, -1, -1, -1, -1, 125, 289, 290, 291, -1, -1, -1, -1, -1, -1, -1, 273, 274, 275, 276, 277, 278, 41, -1, -1, 44, -1, -1, -1, -1, 287, 288, 256, 257, 258, 259, 260, -1, 262, 263, 59, 265, 266, -1, 268, -1, 270, 271, 272, -1, -1, -1, -1, -1, -1, 279, 280, 257, 258, 259, 260, -1, 262, 263, -1, 265, 266, -1, 268, 10, 270, 271, 272, -1, 93, -1, -1, -1, -1, 279, 280, 273, 274, 275, 276, 277, 278, -1, 10, -1, -1, -1, 273, 274, 275, 276, 277, 278, -1, -1, 41, -1, -1, 44, -1, -1, 125, -1, -1, -1, 10, 273, 274, 275, 276, 277, 278, -1, 59, 41, -1, -1, 44, -1, -1, 273, 274, 275, 276, 277, 278, 10, -1, 10, -1, -1, -1, 59, -1, -1, -1, 41, -1, -1, 44, -1, 273, 274, 275, 276, 277, 278, 93, 273, 274, 275, 276, 277, 278, 59, -1, -1, 41, -1, 41, 44, -1, 44, 37, -1, -1, 93, -1, 42, 43, -1, 45, -1, 47, -1, 59, -1, 59, -1, 125, -1, -1, -1, -1, -1, 37, -1, -1, 93, 41, 42, 43, -1, 45, -1, 47, -1, -1, 125, -1, -1, -1, -1, -1, -1, -1, -1, 37, -1, 93, -1, 93, 42, 43, -1, 45, -1, 47, -1, 93, 125, -1, -1, -1, -1, -1, 37, -1, 33, -1, -1, 42, 43, 38, 45, 40, 47, -1, 43, -1, 45, 125, -1, 125, -1, -1, -1, -1, -1, 273, 274, 275, 276, 277, 278, -1, 37, -1, -1, -1, -1, 42, 43, 93, 45, -1, 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, -1, -1, -1, -1, 38, -1, 40, -1, -1, 43, -1, 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 273, 274, 275, 276, 277, 278, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 273, 274, 275, 276, 277, 278, 33, -1, -1, -1, -1, 38, -1, 40, -1, -1, 43, -1, 45, -1, -1, -1, 273, 274, 275, 276, 277, 278, -1, -1, -1, 123, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 273, 274, 273, 274, -1, -1, -1, -1, -1, -1, 273, 274, 275, 276, 277, 278, -1, -1, -1, -1, -1, -1, -1, -1, 287, 288, 289, 290, 291, -1, -1, -1, 273, 274, 275, 276, 277, 278, -1, -1, -1, -1, -1, -1, -1, -1, 287, 288, 289, 290, 291, -1, -1, 123, 273, 274, 275, 276, 277, 278, -1, -1, -1, 257, 258, 259, 260, -1, 287, 288, 289, 290, 291, 273, 274, 275, 276, 277, 278, -1, -1, -1, -1, -1, -1, 279, 280, 287, 288, 289, 290, 291, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 275, 276, 277, 278, -1, -1, -1, -1, -1, -1, -1, -1, 287, 288, 289, 290, 291, 257, 258, 259, 260, -1, 262, 263, -1, 265, 266, -1, 268, -1, 270, 271, 272, -1, -1, -1, -1, -1, -1, 279, 280, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 257, 258, 259, 260, -1, 262, 263, -1, 265, 266, -1, 268, -1, 270, 271, 272, 18, 19, 20, -1, 22, -1, 279, 280, -1, -1, -1, -1, -1, -1, 32, 33, 34, -1, -1, 37, 38, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 88, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 115, -1, -1, -1, 119, -1, -1, -1, -1, -1, -1, -1, 127, ); $YYFINAL=1; #ifndef YYDEBUG #define YYDEBUG 0 #endif $YYMAXTOKEN=294; #if YYDEBUG @yyname = ( "end-of-file",'','','','','','','','','',"'\\n'",'','','','','','','','','','','','','','','','','','','','', '','',"'!'",'','','',"'%'","'&'",'',"'('","')'","'*'","'+'","','","'-'","'.'","'/'",'', '','','','','','','','','','',"';'",'',"'='",'','','','','','','','','','','','','','','','','','','','','','','', '','','','','','',"'['",'',"']'",'','','','','','','','','','','','','','','','','','','','','','','','','','','', '','',"'{'","'|'","'}'",'','','','','','','','','','','','','','','','','','','','','','','','','','','','','', '','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','', '','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','','', '','','','','','','','','','','','','','','','','','','','','','',"INT","FLOAT","STRING","IDENT", "C_COMMENT","BREAK","DEFINE","AUTO","RETURN","PRINT","AUTO_LIST","IF","ELSE", "QUIT","WHILE","FOR","EQ","NE","GT","GE","LT","LE","PP","MM","P_EQ","M_EQ", "F_EQ","D_EQ","EXP_EQ","MOD_EQ","L_SHIFT","R_SHIFT","E_E","O_O","EXP","UNARY", "PPP","MMM", ); @yyrule = ( "\$accept : stmt_list_exec", "stmt_list_exec :", "stmt_list_exec : stmt_list_exec stmt_exec", "stmt_exec : terminator", "stmt_exec : stmt_compile terminator", "stmt_exec : error terminator", "stmt_compile : QUIT", "\$$1 :", "\$$2 :", "stmt_compile : DEFINE $$1 IDENT '(' arg_list ')' terminator_or_void '{' terminator auto_list $$2 stmt_list_block '}'", "stmt_compile : return", "stmt_compile : BREAK", "\$$3 :", "stmt_compile : PRINT $$3 expr_list_commas", "\$$4 :", "stmt_compile : '{' $$4 stmt_list_block '}'", "\$$5 :", "stmt_compile : IF '(' stmt_compile ')' $$5 terminator_or_void stmt_compile", "\$$6 :", "\$$7 :", "stmt_compile : WHILE $$6 '(' stmt_compile_or_void ')' terminator_or_void $$7 stmt_compile", "\$$8 :", "\$$9 :", "\$$10 :", "stmt_compile : FOR '(' stmt_compile_or_void ';' $$8 stmt_compile_or_void ';' $$9 stmt_compile_or_void ')' $$10 terminator_or_void stmt_compile", "stmt_compile : expr", "return : RETURN", "return : RETURN '(' expr ')'", "stmt_compile_or_void :", "stmt_compile_or_void : stmt_compile", "stmt_list_block : stmt_compile_or_void", "stmt_list_block : stmt_list_block terminator stmt_compile_or_void", "terminator_or_void :", "terminator_or_void : terminator", "terminator : ';'", "terminator : '\\n'", "arg_list :", "arg_list : arg_list_nonempty", "arg_list_nonempty : IDENT", "arg_list_nonempty : arg_list_nonempty ',' IDENT", "param_list :", "param_list : param_list_nonempty", "param_list_nonempty : expr", "param_list_nonempty : param_list_nonempty ',' expr", "auto_list :", "auto_list : AUTO auto_list_nonempty terminator", "auto_list_nonempty : IDENT", "auto_list_nonempty : auto_list_nonempty ',' IDENT", "expr_list_commas : expr", "expr_list_commas : expr_list_commas ',' expr", "expr : IDENT '(' param_list ')'", "expr : '(' expr ')'", "expr : expr O_O expr", "expr : expr E_E expr", "expr : expr EQ expr", "expr : expr NE expr", "expr : expr GT expr", "expr : expr GE expr", "expr : expr LT expr", "expr : expr LE expr", "expr : expr L_SHIFT expr", "expr : expr R_SHIFT expr", "expr : expr '+' expr", "expr : expr '-' expr", "expr : expr '*' expr", "expr : expr '/' expr", "expr : expr EXP expr", "expr : expr '%' expr", "expr : ident P_EQ expr", "expr : ident M_EQ expr", "expr : ident F_EQ expr", "expr : ident D_EQ expr", "expr : ident EXP_EQ expr", "expr : ident MOD_EQ expr", "expr : '-' expr", "expr : '!' expr", "expr : PP ident", "expr : MM ident", "expr : ident PPP", "expr : ident MMM", "expr : '+' expr", "expr : '&' STRING", "expr : IDENT '=' expr", "expr : IDENT '[' expr ']' '=' expr", "expr : ident", "expr : INT", "expr : FLOAT", "expr : STRING", "ident : IDENT", "ident : IDENT '[' expr ']'", ); #endif sub yyclearin { $yychar = -1; } sub yyerrok { $yyerrflag = 0; } $YYSTACKSIZE = $YYSTACKSIZE || $YYMAXDEPTH || 500; $YYMAXDEPTH = $YYMAXDEPTH || $YYSTACKSIZE || 500; $yyss[$YYSTACKSIZE] = 0; $yyvs[$YYSTACKSIZE] = 0; sub YYERROR { ++$yynerrs; &yy_err_recover; } sub yy_err_recover { if ($yyerrflag < 3) { $yyerrflag = 3; while (1) { if (($yyn = $yysindex[$yyss[$yyssp]]) && ($yyn += $YYERRCODE) >= 0 && $yycheck[$yyn] == $YYERRCODE) { #if YYDEBUG print "yydebug: state $yyss[$yyssp], error recovery shifting", " to state $yytable[$yyn]\n" if $yydebug; #endif $yyss[++$yyssp] = $yystate = $yytable[$yyn]; $yyvs[++$yyvsp] = $yylval; next yyloop; } else { #if YYDEBUG print "yydebug: error recovery discarding state ", $yyss[$yyssp], "\n" if $yydebug; #endif return(1) if $yyssp <= 0; --$yyssp; --$yyvsp; } } } else { return (1) if $yychar == 0; #if YYDEBUG if ($yydebug) { $yys = ''; if ($yychar <= $YYMAXTOKEN) { $yys = $yyname[$yychar]; } if (!$yys) { $yys = 'illegal-symbol'; } print "yydebug: state $yystate, error recovery discards ", "token $yychar ($yys)\n"; } #endif $yychar = -1; next yyloop; } 0; } # yy_err_recover sub yyparse { #ifdef YYDEBUG if ($yys = $ENV{'YYDEBUG'}) { $yydebug = int($1) if $yys =~ /^(\d)/; } #endif $yynerrs = 0; $yyerrflag = 0; $yychar = (-1); $yyssp = 0; $yyvsp = 0; $yyss[$yyssp] = $yystate = 0; yyloop: while(1) { yyreduce: { last yyreduce if ($yyn = $yydefred[$yystate]); if ($yychar < 0) { if (($yychar = &yylex) < 0) { $yychar = 0; } #if YYDEBUG if ($yydebug) { $yys = ''; if ($yychar <= $#yyname) { $yys = $yyname[$yychar]; } if (!$yys) { $yys = 'illegal-symbol'; }; print "yydebug: state $yystate, reading $yychar ($yys)\n"; } #endif } if (($yyn = $yysindex[$yystate]) && ($yyn += $yychar) >= 0 && $yycheck[$yyn] == $yychar) { #if YYDEBUG print "yydebug: state $yystate, shifting to state ", $yytable[$yyn], "\n" if $yydebug; #endif $yyss[++$yyssp] = $yystate = $yytable[$yyn]; $yyvs[++$yyvsp] = $yylval; $yychar = (-1); --$yyerrflag if $yyerrflag > 0; next yyloop; } if (($yyn = $yyrindex[$yystate]) && ($yyn += $yychar) >= 0 && $yycheck[$yyn] == $yychar) { $yyn = $yytable[$yyn]; last yyreduce; } if (! $yyerrflag) { &yyerror('syntax error'); ++$yynerrs; } return(1) if &yy_err_recover; } # yyreduce #if YYDEBUG print "yydebug: state $yystate, reducing by rule ", "$yyn ($yyrule[$yyn])\n" if $yydebug; #endif $yym = $yylen[$yyn]; $yyval = $yyvs[$yyvsp+1-$yym]; switch: { if ($yyn == 4) { #line 126 "bc.y" { my ($res, $val) = exec_stmt(shift @stmt_list); if($res == 0 and defined($val) and $cur_file ne 'main::DATA') { print "$val\n"; } start_stmt(); last switch; } } if ($yyn == 5) { #line 136 "bc.y" { @ope_stack = (); @stmt_list = (); start_stmt(); &yyerrok; last switch; } } if ($yyn == 6) { #line 144 "bc.y" { exit(0); last switch; } } if ($yyn == 7) { #line 147 "bc.y" { start_stmt(); last switch; } } if ($yyn == 8) { #line 153 "bc.y" { start_stmt(); start_stmt(); last switch; } } if ($yyn == 9) { #line 159 "bc.y" { finish_stmt(); # The last one is empty push_instr('RETURN', 0); my $body = finish_stmt(); push_instr('{}', $body); my $code = finish_stmt(); push_instr('FUNCTION-DEF', $yyvs[$yyvsp-10], $code); last switch; } } if ($yyn == 11) { #line 170 "bc.y" { push_instr('BREAK'); last switch; } } if ($yyn == 12) { #line 173 "bc.y" { push_instr(','); start_stmt(); start_stmt(); last switch; } } if ($yyn == 13) { #line 179 "bc.y" { finish_stmt(); # The last one is empty my $stmt = finish_stmt(); push_instr('PRINT', $stmt); last switch; } } if ($yyn == 14) { #line 186 "bc.y" { start_stmt(); start_stmt(); last switch; } } if ($yyn == 15) { #line 191 "bc.y" { finish_stmt(); # The last one is empty my $stmt = finish_stmt(); push_instr('{}', $stmt); last switch; } } if ($yyn == 16) { #line 197 "bc.y" { start_stmt(); last switch; } } if ($yyn == 17) { #line 200 "bc.y" { my $stmt = finish_stmt(); push_instr('IF', $stmt); last switch; } } if ($yyn == 18) { #line 205 "bc.y" { start_stmt(); last switch; } } if ($yyn == 19) { #line 207 "bc.y" { my $stmt = finish_stmt(); push_instr('FOR-COND', $stmt); start_stmt(); last switch; } } if ($yyn == 20) { #line 213 "bc.y" { my $stmt = finish_stmt(); push_instr('FOR-INCR', []); push_instr('FOR-BODY', $stmt); last switch; } } if ($yyn == 21) { #line 219 "bc.y" { start_stmt(); last switch; } } if ($yyn == 22) { #line 221 "bc.y" { my $stmt = finish_stmt(); push_instr('FOR-COND', $stmt); start_stmt(); last switch; } } if ($yyn == 23) { #line 227 "bc.y" { my $stmt = finish_stmt(); push_instr('FOR-INCR', $stmt); start_stmt(); last switch; } } if ($yyn == 24) { #line 232 "bc.y" { my $stmt = finish_stmt(); push_instr('FOR-BODY', $stmt); last switch; } } if ($yyn == 26) { #line 241 "bc.y" { push_instr('RETURN', 0); last switch; } } if ($yyn == 27) { #line 242 "bc.y" { push_instr('RETURN', 1); last switch; } } if ($yyn == 30) { #line 250 "bc.y" { my $stmt = finish_stmt(); if(scalar(@$stmt) > 0) { push_instr('STMT', $stmt); } start_stmt(); last switch; } } if ($yyn == 31) { #line 258 "bc.y" { my $stmt = finish_stmt(); if(scalar(@$stmt) > 0) { push_instr('STMT', $stmt); } start_stmt(); last switch; } } if ($yyn == 38) { #line 281 "bc.y" { push_instr('a', $yyvs[$yyvsp-0]); last switch; } } if ($yyn == 39) { #line 282 "bc.y" { push_instr('a', $yyvs[$yyvsp-0]); last switch; } } if ($yyn == 46) { #line 299 "bc.y" { push_instr('A', $yyvs[$yyvsp-0]); last switch; } } if ($yyn == 47) { #line 300 "bc.y" { push_instr('A', $yyvs[$yyvsp-0]); last switch; } } if ($yyn == 48) { #line 305 "bc.y" { my $stmt = finish_stmt(); push_instr('PRINT-STMT', $stmt); start_stmt(); last switch; } } if ($yyn == 49) { #line 311 "bc.y" { my $stmt = finish_stmt(); push_instr('PRINT-STMT', $stmt); start_stmt(); last switch; } } if ($yyn == 50) { #line 320 "bc.y" { push_instr('FUNCTION-CALL', $yyvs[$yyvsp-3]); last switch; } } if ($yyn == 51) { #line 324 "bc.y" { last switch; } } if ($yyn == 52) { #line 326 "bc.y" { push_instr('||_'); last switch; } } if ($yyn == 53) { #line 327 "bc.y" { push_instr('&&_'); last switch; } } if ($yyn == 54) { #line 329 "bc.y" { push_instr('==_'); last switch; } } if ($yyn == 55) { #line 330 "bc.y" { push_instr('!=_'); last switch; } } if ($yyn == 56) { #line 331 "bc.y" { push_instr('>_'); last switch; } } if ($yyn == 57) { #line 332 "bc.y" { push_instr('>=_'); last switch; } } if ($yyn == 58) { #line 333 "bc.y" { push_instr('<_'); last switch; } } if ($yyn == 59) { #line 334 "bc.y" { push_instr('<=_'); last switch; } } if ($yyn == 60) { #line 335 "bc.y" { push_instr('<<_'); last switch; } } if ($yyn == 61) { #line 336 "bc.y" { push_instr('>>_'); last switch; } } if ($yyn == 62) { #line 338 "bc.y" { push_instr('+_'); last switch; } } if ($yyn == 63) { #line 339 "bc.y" { push_instr('-_'); last switch; } } if ($yyn == 64) { #line 340 "bc.y" { push_instr('*_'); last switch; } } if ($yyn == 65) { #line 341 "bc.y" { push_instr('/_'); last switch; } } if ($yyn == 66) { #line 342 "bc.y" { push_instr('^_'); last switch; } } if ($yyn == 67) { #line 343 "bc.y" { push_instr('%_'); last switch; } } if ($yyn == 68) { #line 347 "bc.y" { push_instr('+_'); push_instr('V', $yyvs[$yyvsp-2]); push_instr('=V'); last switch; } } if ($yyn == 69) { #line 353 "bc.y" { push_instr('-_'); push_instr('V', $yyvs[$yyvsp-2]); push_instr('=V'); last switch; } } if ($yyn == 70) { #line 359 "bc.y" { push_instr('*_'); push_instr('V', $yyvs[$yyvsp-2]); push_instr('=V'); last switch; } } if ($yyn == 71) { #line 365 "bc.y" { push_instr('/_'); push_instr('V', $yyvs[$yyvsp-2]); push_instr('=V'); last switch; } } if ($yyn == 72) { #line 371 "bc.y" { push_instr('^_'); push_instr('V', $yyvs[$yyvsp-2]); push_instr('=V'); last switch; } } if ($yyn == 73) { #line 377 "bc.y" { push_instr('%_'); push_instr('V', $yyvs[$yyvsp-2]); push_instr('=V'); last switch; } } if ($yyn == 74) { #line 386 "bc.y" { push_instr('m_'); last switch; } } if ($yyn == 75) { #line 390 "bc.y" { push_instr('!_'); last switch; } } if ($yyn == 76) { #line 394 "bc.y" { # 'v'.$2 has already been pushed in the 'ident' rule push_instr('N', 1); push_instr('+_'); push_instr('V', $yyvs[$yyvsp-0]); push_instr('=V'); last switch; } } if ($yyn == 77) { #line 402 "bc.y" { push_instr('N', 1); push_instr('-_'); push_instr('V', $yyvs[$yyvsp-0]); push_instr('=V'); last switch; } } if ($yyn == 78) { #line 409 "bc.y" { # $1 is already on the stack (see the "ident:" rule) push_instr('v', $yyvs[$yyvsp-1]) ; push_instr('V', '*tmp') ; push_instr('=V') ; # *tmp = $1 push_instr(',') ; push_instr('N', 1) ; push_instr('+_') ; push_instr('V', $yyvs[$yyvsp-1]) ; push_instr('=V') ; # $1 = $1 + 1 push_instr(',') ; push_instr('v', '*tmp') ; # Return *tmp last switch; } } if ($yyn == 79) { #line 426 "bc.y" { # See PPP for comments push_instr('v', $yyvs[$yyvsp-1]); push_instr('V', '*tmp'); push_instr('=V'); push_instr(','); push_instr('N', 1); push_instr('-_'); push_instr('V', $yyvs[$yyvsp-1]); push_instr('=V'); push_instr(','); push_instr('v', '*tmp'); last switch; } } if ($yyn == 80) { #line 440 "bc.y" { $yyval = $yyvs[$yyvsp-0]; last switch; } } if ($yyn == 81) { #line 442 "bc.y" { push_instr('&', $yyvs[$yyvsp-0]); $yyval = 1; last switch; } } if ($yyn == 82) { #line 448 "bc.y" { push_instr('V', $yyvs[$yyvsp-2]); push_instr('=V'); $yyval = $yyvs[$yyvsp-0]; last switch; } } if ($yyn == 83) { #line 454 "bc.y" { # Add [] to the name in order to allow the same name # for an array and a scalar push_instr('P', $yyvs[$yyvsp-5]); push_instr('=P'); $yyval = $yyvs[$yyvsp-0]; last switch; } } if ($yyn == 84) { #line 462 "bc.y" { $yyval = $yyvs[$yyvsp-0]->{"value"}; last switch; } } if ($yyn == 85) { #line 464 "bc.y" { push_instr('N', $yyvs[$yyvsp-0]); last switch; } } if ($yyn == 86) { #line 465 "bc.y" { push_instr('N', $yyvs[$yyvsp-0]); last switch; } } if ($yyn == 87) { #line 466 "bc.y" { push_instr('S', $yyvs[$yyvsp-0]); last switch; } } if ($yyn == 88) { #line 470 "bc.y" { push_instr('v', $yyvs[$yyvsp-0]); last switch; } } if ($yyn == 89) { #line 473 "bc.y" { push_instr('p', $yyvs[$yyvsp-3]); $yyval = $yyvs[$yyvsp-3].'[]'.$yyvs[$yyvsp-1]; last switch; } } #line 1201 "y.tab.pl" } # switch $yyssp -= $yym; $yystate = $yyss[$yyssp]; $yyvsp -= $yym; $yym = $yylhs[$yyn]; if ($yystate == 0 && $yym == 0) { #if YYDEBUG print "yydebug: after reduction, shifting from state 0 ", "to state $YYFINAL\n" if $yydebug; #endif $yystate = $YYFINAL; $yyss[++$yyssp] = $YYFINAL; $yyvs[++$yyvsp] = $yyval; if ($yychar < 0) { if (($yychar = &yylex) < 0) { $yychar = 0; } #if YYDEBUG if ($yydebug) { $yys = ''; if ($yychar <= $#yyname) { $yys = $yyname[$yychar]; } if (!$yys) { $yys = 'illegal-symbol'; } print "yydebug: state $YYFINAL, reading $yychar ($yys)\n"; } #endif } return(0) if $yychar == 0; next yyloop; } if (($yyn = $yygindex[$yym]) && ($yyn += $yystate) >= 0 && $yyn <= $#yycheck && $yycheck[$yyn] == $yystate) { $yystate = $yytable[$yyn]; } else { $yystate = $yydgoto[$yym]; } #if YYDEBUG print "yydebug: after reduction, shifting from state ", "$yyss[$yyssp] to state $yystate\n" if $yydebug; #endif $yyss[++$yyssp] = $yystate; $yyvs[++$yyvsp] = $yyval; } # yyloop } # yyparse #line 479 "bc.y" # Prompt the user on STDERR, but only prompt if STDERR and the input # file are both terminals. @file_list=(); $mathlib=0; sub command_line() { while ($f = shift(@ARGV)) { if ($f eq '-d') { use Data::Dumper; $debug = 1; } elsif ($f eq '-y') { $yydebug = 1; } elsif ($f eq '-l') { $mathlib = 1; } else { push(@file_list, $f); } } # read from STDIN if no files are named on the command line @file_list = ('-') if $#file_list < 0; } # After finishing a file, open the next one. Return whether there # really is a next one that was opened. sub next_file { if($cur_file) { close $input; } if($mathlib) { debug { "reading the math library\n" }; $input = \*main::DATA; $mathlib=0; $cur_file="main::DATA"; return 1; } elsif($file = shift(@file_list)) { debug { "reading from $file\n" }; if (! open(IN, $file)) { die "$file: cannot open file: $!\n"; } $input = IN; $cur_file = $file; $prompt = ''; return 1; } debug { "no next file\n" }; return 0; } # print the prompt sub prompt { print STDERR $prompt if $prompt; } # print an error message sub yyerror { print STDERR "\"$cur_file\", " if $cur_file ne '-'; # debug { "yyerror-stmt_list : ".Dumper(\@stmt_list) }; print STDERR "line $.: ", @_, "\n"; @ope_stack = (); start_stmt(); } # Hand-coded lex sub yylex { lexloop: { # get a line of input, if we need it. if ($line eq '') { &prompt; while(! ($line = <$input>)) { &next_file || do { return(0); }; } } # Skip over white space, and grab the first character. # If there is no such character, then grab the next line. $line =~ s/^\s*(.|\n)// || next lexloop; local($char) = $1; if ($char eq '/' and $line =~ /^\*/) { # C-style comment while($line !~ m%\*/%) { $line = <$input>; } $line =~ s%.*?\*/% %; yylex(); } elsif ($char eq '#') { # comment, so discard the line $line = "\n"; &yylex; } elsif ($char eq '\\' and $line eq "\n") { # Discard the newline $line = ''; yylex(); } elsif ($char =~ /^(['"])/) { $yylval = ""; my $c = $1; while($line !~ /$c/) { $yylval .= $line; $line = <$input>; } $line =~ s%(.*?)$c% %; $yylval .= $1; $STRING; } elsif ($char =~ /^[\dA-F]/ or ($char eq '.' and $line =~ /\d/)) { # Bug: hexadecimal values are not supported, because they are # not supported in Math::BigFloat # I should support them myself if($char =~ /[A-F]/) { &yyerror('Sorry, hexadecimal values are not supported'); } $line = "0.$line" if($char eq '.'); # number, is it integer or float? if ($line =~ s/^(\d+)//) { # $yylval = Math::BigFloat->new($char . $1); $yylval = 0 + ($char.$1); } else { # $yylval = Math::BigFloat->new($char); $yylval = 0 + $char; } $type = $INT; if ($line =~ s/^(\.\d*)//) { $tmp = "0$1"; $yylval += $tmp; $type = $FLOAT; } if ($line =~ s/^[eE]([-+]*\d+)//) { $yylval *= 10 ** $1; $type = $FLOAT; } $type; } elsif ($char =~ /^[a-z]/) { # Uppercase is reserved for hexadecimal numbers $line =~ s/^([\w\d]*)//; $yylval = $char.$1; if($yylval eq 'auto') { $AUTO; } elsif($yylval eq 'break') { $BREAK; } elsif($yylval eq 'define') { $DEFINE; } elsif($yylval eq 'for') { $FOR; } elsif($yylval eq 'if') { $IF; } elsif($yylval eq 'else') { $ELSE; } elsif($yylval eq 'print') { $PRINT; } elsif($yylval eq 'quit') { $QUIT; } elsif($yylval eq 'return') { $RETURN; } elsif($yylval eq 'while') { $WHILE; } else { $IDENT; } } elsif (($char eq '*' && $line =~ s/^\*=//) or ($char eq '^' && $line =~ s/=//)) { $EXP_EQ; } elsif (($char eq '*' && $line =~ s/^\*//) or ($char eq '^')) { $EXP; } elsif ($char eq '|' && $line =~ s/^\|//) { $O_O; } elsif ($char eq '&' && $line =~ s/^&//) { $E_E; } elsif ($char eq '%' && $line =~ s/^=//) { $MOD_EQ; } elsif ($char eq '!' && $line =~ s/^=//) { $NE; } elsif ($char eq '=' && $line =~ s/^=//) { $EQ; } elsif ($char =~ /^[<>]/ && $line =~ s/^=//) { $char eq '<' ? $LE : $GE; } elsif ($char =~ /^[<>]/ && $line =~ s/^$char//) { $char eq '<' ? $L_SHIFT : $R_SHIFT; } elsif ($char =~ /^[<>]/) { $char eq '<' ? $LT : $GT; } elsif ($char eq '+' && $line =~ s/^\+(\s*\w)/$1/) { $PP; } elsif ($char eq '+' && $line =~ s/^=//) { $P_EQ; } elsif ($char eq '+' && $line =~ s/^\+//) { $PPP; } elsif ($char eq '-' && $line =~ s/^\-(\s*\w)/$1/) { $MM; } elsif ($char eq '-' && $line =~ s/^\-//) { $MMM; } elsif ($char eq '-' && $line =~ s/^=//) { $M_EQ; } elsif ($char eq '*' && $line =~ s/^=//) { $F_EQ; } elsif ($char eq '/' && $line =~ s/^=//) { $D_EQ; } else { $yylval = $char; ord($char); } } } # factorial sub fact { local($n) = @_; local($f) = 1; $f *= $n-- while ($n > 1) ; $f; } sub bi_length { my $stack = shift; $_ = pop @$stack; my ($a, $b); die "NaN" unless ($a, $b) = /[-+]?(\d*)\.?(\d+)?/; $a =~ s/^0+//; $b =~ s/0+$//; my $len = length($a) + length($b); return $len == 0 ? 1 : $len; } sub bi_scale { my $stack = shift; $_ = pop @$stack; my ($a, $b); die "NaN" unless ($a, $b) = /[-+]?(\d*)\.?(\d+)?/; return length($b); } sub bi_sqrt { my $stack = shift; $_ = pop @$stack; return sqrt($_); } # Initialize the symbol table sub init_table { $sym_table{'scale'} = { type => 'var', value => 0}; $sym_table{'ibase'} = { type => 'var', value => 0}; $sym_table{'obase'} = { type => 'var', value => 0}; $sym_table{'last'} = { type => 'var', value => 0}; $sym_table{'length()'} = { type => 'builtin', value => \&bi_length }; $sym_table{'scale()'} = { type => 'builtin', value => \&bi_scale }; $sym_table{'sqrt()'} = { type => 'builtin', value => \&bi_sqrt }; } # # Pseudo-code # # Compilation time: a stack of statements is maintained. Each statement # is itself a stack of instructions. # Each instruction is appended to the statement which is on the top. # When a sub-block (IF, DEFINE...) is encountered, a # new, empty statement is pushed onto the stack, and it receives the # instructions in the sub-block. my $cur_stmt; # Pushes one instruction onto the current statement # First element is the type, others are 0 or more arguments, depending on # the type. sub push_instr { die "Internal error: no cur stmt" unless($cur_stmt); my @args = @_; push(@$cur_stmt, [ @args ]); } # Pushes a new statement onto the stack of statements, and makes it the # current sub start_stmt { $cur_stmt = []; push(@stmt_list, $cur_stmt); } # Closes a statement, and returns a reference on it. sub finish_stmt { my $stmt = pop @stmt_list; $cur_stmt = $stmt_list[$#stmt_list]; return $stmt; } # # Execution time # my ($res, $val); my $res2; my $code; sub exec_print { my $res = exec_stmt(@_); print "$res\n" if(defined $res); } # # exec_stmt # Really executes a statement. Calls itself recursively when it # encounters sub-statements (in block, loops, functions...) # my $count = 0; sub exec_stmt { $count++; my $stmt = shift; my $return = 0; # 1 if a "return" statement is encountered my @stmt_s = @$stmt; # print STDERR "ko\n";"executing statement: ".Dumper(\@stmt_s); # Each instruction in the stack is an array which first element gives # the type. Others elements may contain references to sub-statements my $instr; INSTR: while (defined($instr = shift @stmt_s)) { $_ = $instr->[0]; print STDERR ("instruction: ".join(', ', @$instr)."\n" ) if $debug; # remove the stack top value, and forget about it if($_ eq ',') { $res = pop @ope_stack; next INSTR; } elsif($_ eq 'N') { # N for number push(@ope_stack, 0 + $instr->[1]); next INSTR; } elsif($_ eq '+_' or $_ eq '-_' or $_ eq '*_' or $_ eq '/_' or $_ eq '^_' or $_ eq '%_' or $_ eq '==_' or $_ eq '!=_' or $_ eq '>_' or $_ eq '>=_' or $_ eq '<_' or $_ eq '<=_' or $_ eq '<<_' or $_ eq '>>_' or $_ eq '||_' or $_ eq '&&_') { # Binary operators my $b = pop(@ope_stack); my $a = pop(@ope_stack); if ($_ eq '+_') { $res = $a + $b ; 1 } elsif($_ eq '-_') { $res = $a - $b ; 1 } elsif($_ eq '*_') { $res = $a * $b ; 1 } elsif($_ eq '/_') { $res = $a / $b ; 1 } elsif($_ eq '^_') { $res = $a ** $b ; 1 } elsif($_ eq '%_') { $res = $a % $b ; 1 } elsif($_ eq '==_') { $res = 0 + ($a == $b) ; 1 } elsif($_ eq '!=_') { $res = 0 + ($a != $b) ; 1 } elsif($_ eq '>_') { $res = 0 + ($a > $b) ; 1 } elsif($_ eq '>=_') { $res = 0 + ($a >= $b) ; 1 } elsif($_ eq '<_') { $res = 0 + ($a < $b) ; 1 } elsif($_ eq '<=_') { $res = 0 + ($a <= $b) ; 1 } elsif($_ eq '<<_') { $res = ($a << $b) ; 1 } elsif($_ eq '>>_') { $res = ($a >> $b) ; 1 } elsif($_ eq '||_') { $res = ($a || $b) ? 1 : 0 ; 1 } elsif($_ eq '&&_') { $res = ($a && $b) ? 1 : 0 ; 1 } ; push(@ope_stack, $res); next INSTR; # Unary operators } elsif($_ eq 'm_') { $res = pop(@ope_stack); push(@ope_stack, -$res); next INSTR; } elsif($_ eq '!_') { $res = pop(@ope_stack); push(@ope_stack, 0+!$res); next INSTR; } elsif($_ eq 'V') { # Variable or array identifier push(@ope_stack, $instr->[1]); next INSTR; } elsif($_ eq 'P') { push(@ope_stack, $instr->[1].'[]'.(pop(@ope_stack))); next INSTR; } elsif($_ eq 'v') { # Variable value # '*' is reserved for internal variables my $name = $instr->[1]; unless (defined($sym_table{$name}) and $sym_table{$name}{'type'} eq 'var') { print STDERR "$name: undefined variable\n"; $return = 3; @ope_stack = (); @stmt_list=(); YYERROR; } push(@ope_stack, $sym_table{$name}{'value'}); next INSTR; } elsif($_ eq 'p') { # Array value : initialized to 0 my ($name, $idx) = ($instr->[1], pop(@ope_stack)); if($idx !~ /^\d+$/) { print STDERR "Non-integer index $idx for array\n"; $return = 3; @ope_stack = (); @stmt_list=(); YYERROR; } # debug {"p: $name, $idx.\n"}; unless (defined($sym_table{$name.'[]'}) and $sym_table{$name.'[]'}{'type'} eq 'array') { $sym_table{$name.'[]'} = { type => 'array'}; } unless ($sym_table{$name.'[]'}{'value'}[$idx]) { $sym_table{$name.'[]'}{'value'}[$idx] = { type => 'var', value => 0 }; } push(@ope_stack, $sym_table{$name.'[]'}{'value'}[$idx]{'value'}); next INSTR; } elsif($_ eq '=V') { # Attribution of a value to a variable # ope_stack ends with a NUMBER and an IDENTIFIER my $varName = pop(@ope_stack); my $value = pop(@ope_stack); $sym_table{$varName} = { type => 'var', value => $value }; push(@ope_stack, $value); next INSTR; } elsif($_ eq '=P') { my $varName = pop(@ope_stack); my $value = pop(@ope_stack); my ($name, $idx) = ($varName =~ /([a-z]+)\[\](\d+)/); $name .= '[]'; unless (defined($sym_table{$name}) and $sym_table{$name}{'type'} eq 'array') { $sym_table{$name} = { type => 'array', value => [] }; } $sym_table{$name}{'value'}[$idx] = { type => 'var', value => $value }; push(@ope_stack, $value); next INSTR; } elsif($_ eq 'IF') { # IF statement my $cond = pop @ope_stack; my $res = $cond; $val = 0; if($cond) { ($return, $val) = exec_stmt($instr->[1]); push(@ope_stack, $val), last INSTR if $return; } # debug {"IF: $val.\n"}; push(@ope_stack, $val); # debug {"IF: ope_stack=".Dumper(\@ope_stack)}; next INSTR; } elsif($_ eq 'FOR-COND') { # WHILE and FOR statement # debug {"while-cond: stmt_s=".Dumper(\@stmt_s)}; my $i_cond = $instr; my $i_incr = shift @stmt_s; my $i_body = shift @stmt_s; my $r; my $val=1; # debug { "cond: ".Dumper($i_cond) }; LOOP: while(1) { @ope_stack=(); if($#{ $i_cond->[1] } >= 0) { ($return, $val) = exec_stmt($i_cond->[1]); # debug {"results of cond: $return, $val"}; push(@ope_stack, $val), last INSTR if($return == 1 or $return == 2); last LOOP if $val == 0; } # debug {"while: executing a body\n"}; if($#{ $i_body->[1] } >= 0) { ($return, $val) = exec_stmt($i_body->[1]); push(@ope_stack, $val); if($return == 1) { last INSTR; } elsif($return == 2) { $return = 0 ; last INSTR; } } if($#{ $i_incr->[1] } >= 0) { # debug {"for: executing the increment: ".Dumper($i_incr)}; @ope_stack = (); ($return, $val) = exec_stmt($i_incr->[1]); push(@ope_stack, $val); last INSTR if($return == 1 or $return == 2); } } $return = 3; push(@ope_stack, 1); # whatever next INSTR; } elsif($_ eq 'FUNCTION-CALL') { # Function call push @backup_sym_table, undef; # Hmmm... my $name = $instr->[1]; $name .= '()'; unless($sym_table{$name}) { print STDERR "No function $name has been defined\n"; @ope_stack = (0); $return = 3; YYERROR; } if($sym_table{$name}{type} eq 'builtin') { ($return, $val) = (1, &{ $sym_table{$name}{value} }(\@ope_stack)); } else { ($return, $val) = exec_stmt($sym_table{$name}{'value'}); # Restore the symbols temporarily pushed in 'a' and 'A' instructions debug {"restoring backup: ".Dumper(\@backup_sym_table)}; my $n; # pop @backup_sym_table; # The first is undef my $entry; while($var = pop @backup_sym_table) { debug {"restoring var: ".Dumper($var)}; if($var->{'type'} eq 'undef') { delete $sym_table{$var->{'name'}};; } else { $sym_table{$var->{'name'}} = $var->{'entry'}; } } # push @backup_sym_table, undef; } # debug {"result from function $name: $return, $val.\n"}; push(@ope_stack, $val); if($return == 1) { $return = 0; # so the result will be printed } elsif($return == 2) { print STDERR "No enclosing while or for"; YYERROR; } elsif($return == 3) { $return = 0; } next INSTR; } elsif($_ eq 'a' or $_ eq 'A') { # Function arguments and auto list declaration # The difference is that function arguments are initialized from the # operation stack, while auto variables are initialized to zero my ($where, $name) = ($_, $instr->[1]); if(defined $sym_table{$name}) { debug { "backup $name, $sym_table{$name}\n" }; push @backup_sym_table, { name => $name, entry => $sym_table{$name} }; } else { debug { "backup $name, undef \n" }; push @backup_sym_table, { name => $name, type => 'undef' }; } $sym_table{$name} = { type => 'var', value => ($where eq 'a' ? shift(@ope_stack) : 0) }; # debug { "new entry $name in sym table: $sym_table{$name}{'value'}" }; next INSTR; } elsif($_ eq '{}') { # Grouped statements if(scalar @{ $instr->[1] } > 0) { ($return, $val) = exec_stmt($instr->[1]); } else { ($return, $val) = (0, 0); } push(@ope_stack, $val), last INSTR if($return eq 1 or $return eq 2); $return = 3; push(@ope_stack, $val); next INSTR; } elsif($_ eq 'STMT') { @ope_stack=(); if(scalar $instr->[1] > 0) { ($return, $val) = exec_stmt($instr->[1]); } else { ($return, $val) = (3, undef); } @ope_stack = ($val), last INSTR if($return eq 1 or $return eq 2); $return = 3; @ope_stack = ($val); next INSTR; } elsif($_ eq 'RETURN') { # Return statement # debug {"returning $instr->[1].\n"}; my $value = ($instr->[1] == 0) ? 0 : pop(@ope_stack); $return = 1; @ope_stack = ($value); last INSTR; } elsif($_ eq 'BREAK') { # Break statement # debug {"breaking.\n"}; $return = 2; push(@ope_stack, 0); last INSTR; } elsif($_ eq 'PRINT') { # PRINT statement if(scalar @{ $instr->[1] } > 0) { ($return, $val) = exec_stmt($instr->[1]); } else { ($return, $val) = (0, 0); } push(@ope_stack, $val), last INSTR if($return eq 1 or $return eq 2); $return = 3; next INSTR; } elsif($_ eq 'PRINT-STMT') { @ope_stack=(); if(scalar $instr->[1] > 0) { ($return, $val) = exec_stmt($instr->[1]); } else { ($return, $val) = (3, undef); } last INSTR if($return eq 1 or $return eq 2); $return = 3; print $val; next INSTR; } elsif($_ eq 'FUNCTION-DEF') { # Function definition my ($name, $code) = ($instr->[1], $instr->[2]); push(@$code, ["RETURN", 0]); $sym_table{$name.'()'} = { type => 'func', value => $code }; $return = 3; push(@ope_stack, 1); # whatever next INSTR; } elsif($_ eq '&') { # Evaluating a Perl instruction $res = eval $instr->[1]; push(@ope_stack, "\nresult of eval: $res"); next INSTR; } elsif($_ eq 'S') { # S for string $_ = $instr->[1]; s/ \\a /\a/gx; s/ \\b /\b/gx; s/ \\f /\f/gx; s/ \\n /\n/gx; s/ \\r /\r/gx; s/ \\t /\t/gx; s/ \\q /"/gx; # " s/ \\\\ /\\/gx; push(@ope_stack, $_); next INSTR; } else { die "internal error: illegal statement $_"; } } my $val; if ($return == 3) { @ope_stack = (); } else { if(scalar @ope_stack != 1) { die("internal error: ope_stack = ".join(", ", @ope_stack).".\n"); } $val = pop(@ope_stack); # debug {"Returning ($return, $val)\n"}; # debug {"ope_stack at e-o-func: ".Dumper(\@ope_stack)}; } return ($return, $val); } # catch signals sub catch { local($signum) = @_; print STDERR "\n" if (-t STDERR && -t STDIN); &yyerror("Floating point exception") if $signum == 8; # next outer; main(); } # main program sub main { # outer: while(1) { $line = ''; eval '$status = &yyparse;'; # debug { "yyparse returned $status" } if !$@; exit $status if ! $@; &yyerror($@); } } init_table(); command_line(); $SIG{'INT'} = 'catch'; $SIG{'FPE'} = 'catch'; select(STDERR); $| = 1; select(STDOUT); &next_file; start_stmt(); main(); print "count=$count\n"; __END__ /* libmath.b for GNU bc. */ /* This file is part of GNU bc. Copyright (C) 1991, 1992, 1993, 1997 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License , or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. You may contact the author by: e-mail: phil@cs.wwu.edu us-mail: Philip A. Nelson Computer Science Department, 9062 Western Washington University Bellingham, WA 98226-9062 *************************************************************************/ scale = 20 /* Uses the fact that e^x = (e^(x/2))^2 When x is small enough, we use the series: e^x = 1 + x + x^2/2! + x^3/3! + ... */ define e(x) { auto a, d, e, f, i, m, n, v, z /* a - holds x^y of x^y/y! */ /* d - holds y! */ /* e - is the value x^y/y! */ /* v - is the sum of the e's */ /* f - number of times x was divided by 2. */ /* m - is 1 if x was minus. */ /* i - iteration count. */ /* n - the scale to compute the sum. */ /* z - orignal scale. */ /* Check the sign of x. */ if (x<0) { m = 1 x = -x } /* Precondition x. */ z = scale; n = 6 + z + .44*x; scale = scale(x)+1; while (x > 1) { f += 1; x /= 2; scale += 1; } /* Initialize the variables. */ scale = n; v = 1+x a = x d = 1 for (i=2; 1; i++) { e = (a *= x) / (d *= i) if (e == 0) { if (f>0) while (f--) v = v*v; scale = z if (m) return (1/v); return (v/1); } v += e } } /* Natural log. Uses the fact that ln(x^2) = 2*ln(x) The series used is: ln(x) = 2(a+a^3/3+a^5/5+...) where a=(x-1)/(x+1) */ define l(x) { auto e, f, i, m, n, v, z /* return something for the special case. */ if (x <= 0) return ((1 - 10^scale)/1) /* Precondition x to make .5 < x < 2.0. */ z = scale; scale = 6 + scale; f = 2; i=0 while (x >= 2) { /* for large numbers */ f *= 2; x = sqrt(x); } while (x <= .5) { /* for small numbers */ f *= 2; x = sqrt(x); } /* Set up the loop. */ v = n = (x-1)/(x+1) m = n*n /* Sum the series. */ for (i=3; 1; i+=2) { e = (n *= m) / i if (e == 0) { v = f*v scale = z return (v/1) } v += e } } /* Sin(x) uses the standard series: sin(x) = x - x^3/3! + x^5/5! - x^7/7! ... */ define s(x) { auto e, i, m, n, s, v, z /* precondition x. */ z = scale scale = 1.1*z + 2; v = a(1) if (x < 0) { m = 1; x = -x; } scale = 0 n = (x / v + 2 )/4 x = x - 4*n*v if (n%2) x = -x /* Do the loop. */ scale = z + 2; v = e = x s = -x*x for (i=3; 1; i+=2) { e *= s/(i*(i-1)) if (e == 0) { scale = z if (m) return (-v/1); return (v/1); } v += e } } /* Cosine : cos(x) = sin(x+pi/2) */ define c(x) { auto v; scale += 1; v = s(x+a(1)*2); scale -= 1; return (v/1); } /* Arctan: Using the formula: atan(x) = atan(c) + atan((x-c)/(1+xc)) for a small c (.2 here) For under .2, use the series: atan(x) = x - x^3/3 + x^5/5 - x^7/7 + ... */ define a(x) { auto a, e, f, i, m, n, s, v, z /* a is the value of a(.2) if it is needed. */ /* f is the value to multiply by a in the return. */ /* e is the value of the current term in the series. */ /* v is the accumulated value of the series. */ /* m is 1 or -1 depending on x (-x -> -1). results are divided by m. */ /* i is the denominator value for series element. */ /* n is the numerator value for the series element. */ /* s is -x*x. */ /* z is the saved user's scale. */ /* Negative x? */ m = 1; if (x<0) { m = -1; x = -x; } /* Special case and for fast answers */ if (x==1) { if (scale <= 25) return (.7853981633974483096156608/m) if (scale <= 40) return (.7853981633974483096156608458198757210492/m) if (scale <= 60) \ return (.785398163397448309615660845819875721049292349843776455243736/m) } if (x==.2) { if (scale <= 25) return (.1973955598498807583700497/m) if (scale <= 40) return (.1973955598498807583700497651947902934475/m) if (scale <= 60) \ return (.197395559849880758370049765194790293447585103787852101517688/m) } /* Save the scale. */ z = scale; /* Note: a and f are known to be zero due to being auto vars. */ /* Calculate atan of a known number. */ if (x > .2) { scale = z+5; a = a(.2); } /* Precondition x. */ scale = z+3; while (x > .2) { f += 1; x = (x-.2) / (1+x*.2); } /* Initialize the series. */ v = n = x; s = -x*x; /* Calculate the series. */ for (i=3; 1; i+=2) { e = (n *= s) / i; if (e == 0) { scale = z; return ((f*a+v)/m); } v += e } } /* Bessel function of integer order. Uses the following: j(-n,x) = (-1)^n*j(n,x) j(n,x) = x^n/(2^n*n!) * (1 - x^2/(2^2*1!*(n+1)) + x^4/(2^4*2!*(n+1)*(n+2)) - x^6/(2^6*3!*(n+1)*(n+2)*(n+3)) .... ) */ define j(n,x) { auto a, d, e, f, i, m, s, v, z /* Make n an integer and check for negative n. */ z = scale; scale = 0; n = n/1; if (n<0) { n = -n; if (n%2 == 1) m = 1; } /* Compute the factor of x^n/(2^n*n!) */ f = 1; for (i=2; i<=n; i++) f = f*i; scale = 1.5*z; f = x^n / 2^n / f; /* Initialize the loop .*/ v = e = 1; s = -x*x/4 scale = 1.5*z /* The Loop.... */ for (i=1; 1; i++) { e = e * s / i / (n+i); if (e == 0) { scale = z if (m) return (-f*v/1); return (f*v/1); } v += e; } } #line 2391 "y.tab.pl"