use strict; use Data::Dumper; use Parse::RecDescent; # $::RD_ERRORS=1; # $::RD_WARN=1; # $::RD_HINT=1; # $::RD_TRACE=1; # $::debugging = 1; our %parse_vars; my %data_vars; my $grammar = q { code: line(s) eofile {$item[1]} | {print STDERR "\n ERROR! (Line $thisparser->{errors}->[0]->[1]): $thisparser->{errors}->[0]->[0]\n"; $thisparser->{errors} = undef} line: description_statement(s) description_statement: assignment_statement | conditional_description_statement conditional_description_statement: if_description_statement elsif_description_statement(s?) else_description_statement(?) if_description_statement: 'if' '(' expression ')' '{' description_statement(s) '}' {print STDERR "if branch on line $thisline\n"; $return = $item[7]; 1; } elsif_description_statement: 'elsif' '(' expression ')' '{' description_statement(s) '}' {print STDERR "elsif branch on line $thisline\n"; $return = $item[7]; 1; } else_description_statement: 'else' '{' description_statement(s) '}' {print STDERR "else branch on line $thisline\n"; $return = $item[3]; 1; } assignment_statement: variable '=' expression ';' {$main::parse_vars{$item[1]} = $item[-2]} | expression: unary_expression bin_num_op expression {my $res = eval "@item[1..$#item]"; print "exec: $item[2] operation, result = $res\n" if ($::debugging); $res } | unary_expression bin_str_op expression {my $res = '"'.eval("@item[1..$#item]").'"'; print "exec: $item[2] operation, result = $res\n" if ($::debugging); $res } | unary_expression unary_expression: primary | variable {$main::parse_vars{$item[1]} ||= 0} | '+' expression {$item[2]} | '-' expression {$item[2] * -1} | '~' expression {~$item[2]} | '!' expression {!$item[2]} | paren_expression {$item[1]} paren_expression : '(' expression ')' {$item[2]} | primary: number {$item[1]} | string_literal {$item[1]} number: binary_number {$item[1]} | hex_number {$item[1]} | decimal_number {$item[1]} decimal_number: /\d+/ {eval $item[1]} binary_number : /0b[01_]+/i {eval lc($item[1])} hex_number : /0x[a-f0-9_]+/i {eval lc($item[1])} string_literal: { extract_delimited($text,'"') } { my $str_lit = $item[1]; # variable interpolation $str_lit =~ s/([^\\\])(\$)\{?(\w+)\}?/$1$main::parse_vars{"$2$3"}/g; '"'.eval($str_lit).'"'; } simple_identifier: m{[a-zA-Z_]\w*} {$item[1]} variable: '$' '{' simple_identifier '}' {"$item[1]$item[4]"} | '$' simple_identifier {"$item[1]$item[3]"} | bin_num_op: '||' | '&&' | '|' | '^' | '&' | '==' | '!=' | '<=>' | 'eq' | 'ne' | 'cmp' | '<<' | '>>' | '<=' | '>=' | '<' | '>' | 'lt' | 'le' | 'gt' | 'ge' | '+' | '-' | '*' | '/' | '%' | '**' bin_str_op: '.' | 'x' eofile: /^\Z/ }; my $parser=Parse::RecDescent->new($grammar); my $document = q( $_errvar2 = 9; $_errvar3 = $_errvar2; if (1) { $if_var01 = 1; } if (1) { $if_var02 = 1; } else { $if_var02 = 2; } if (0) { $if_var11 = 1; } if (0) { $if_var12 = 1; } else { $if_var12 = 2; } if (1) { $if_var3 = 1; } elsif (2) { $if_var3 = 2; } else { $if_var3 = 3; } if (1) { $if_var4 = 1; } elsif (2) { $if_var4 = 2; } elsif (3) { $if_var4 = 3; } elsif (4) { $if_var4 = 4; } else { $if_var4 = 5; } if (1) { if ($_errvar2 == 13) { $if_var6 = 1; } else { $if_var6 = 2; } } else { $if_var6 = 3; } ); my $parse_res = $parser->code($document); defined($parse_res) || die "\n ERROR! Syntax errors in document\n\n"; %data_vars = %parse_vars; undef(%parse_vars); print Data::Dumper->Dump([\%data_vars]);