Parse Prolog-like terms in Perl

11 May 2010

You want to parse strings of things that look like Prolog terms using Perl.

Use Parse::RecDescent, this example parser below will read a term and return a lisp-like array reference of the form: [$fun, @arg]; where $fun—a string scalar—is the functor of the term, and each argument in @arg—if any—is a lisp-like array reference itself.

A reverse function, term_str, is also provided as an example on how to recursively process such term structures.

use Parse::RecDescent;

my $parser = Parse::RecDescent->new(q(
  terms  : <leftop: term ',' term>
  term   : atom '(' terms ')' <commit>
           { $return = $item{terms}; unshift @$return, $item{atom}; }
         | atomic
           { $return = [$item{atomic}] }
  atomic : atom | num
  atom   : /[a-zA-Z_]+/
  num    : /\d+/
));

sub term_str {
  my @arg = @{ shift @_ };
  my $fun = shift @arg;
  # here $fun and @arg hold their expected values 
  return $fun unless @arg; # nulary term
  for my $a (@arg) { $a = term_str($a) } # process arguments recursively
  return $fun . "[" . join (",", @arg) . "]";
}

print term_str($parser->term('ls(s(p),q,d(x,p))'));
# outputs: ls[s[p],q,d[x,p]]