package Ast; #----------------------------------------------------------------------------- # This package is used to create a simple Abstract Syntax tree. Each node # in the AST is an associative array and supports two kinds of properties - # scalars and lists of scalars. #----------------------------------------------------------------------------- use strict; my $curr_level = 0; my $indent = " "; # Constructor # e.g AST->new ("personnel") # Stores the argument in a property called astNodeName whose sole purpose # is to support print() sub new { my ($pkg, $name) = @_; bless {'ast_node_name' => $name}, $pkg; } # Add a property to this object # $ast_node->add_prop("className", "Employee"); sub add_prop { $_[0]->{$_[1]} = $_[2]; } # Equivalent to add_prop, except the property name is associated # with a list of values # $class_ast_node->add_prop_list("attr_list", $attr_ast_node); sub add_prop_list { my ($this, $prop_name, $node_ref) = @_; if (! exists $this->{$prop_name}) { $this->{$prop_name} = []; } push (@{$this->{$prop_name}}, $node_ref); } # Returns a list of all the property names of this object sub get_props { my ($this) = $_[0]; return keys %{$this}; } sub get_prop_value { my ($this, $prop_name) = $_[0]; return $this->{$prop_name}; } my @saved_values_stack; sub visit { no strict 'refs'; my $this = shift; package main; my ($var, $val, $old_val, %saved_values); while (($var,$val) = each %{$this}) { if (defined ($old_val = $$var)) { $saved_values{$var} = $old_val; } $$var = $val; } push (@saved_values_stack, \%saved_values); } sub bye { my $rh_saved_values = pop(@saved_values_stack); no strict 'refs'; package main; my ($var,$val); while (($var,$val) = each %$rh_saved_values) { $$var = $val; } } # Recursively prints the entire AST tree. sub print { my $this = shift; my($curr_indent); my($i,$o,$prop); $curr_indent = $indent x $curr_level; print "${curr_indent}name :", $this->{"ast_node_name"}, "\n"; $curr_indent .= $indent ; ++$curr_level; foreach $prop (keys %$this) { next if ($prop eq "ast_node_name"); $o = $this->{"$prop"}; if (ref($o) eq "Ast") { $o->print(); } elsif (ref($o) eq "ARRAY") { foreach $i (@{$o}) { $i->print() if (ref($i) eq "Ast"); } } else { print "${curr_indent}$prop: $o \n"; } } --$curr_level; } 1;