proplogPP

proplogPP is an example of a pretty printer for propositional logic using Rexastor. You can download all the sources in a package proplogPP.tar.gz.

The example contains the following files:

  • pl.rx a description of the Abstract Syntax Trees as given to the code-generator
  • subtypes.dot the subtyping relation on generated classes
  • PP.java source-code of the pretty printer
  • MinVisitor.java source-code of a minimal visitor stub with memoization, partially generated by the tool
  • TestPP.java a runnable testing example

pl.rx

package pl; 
builtin String; // no code is generated for builtin types
labels var, or, and, not, xor, imp;
alias Var -> var[String]; // Var is an alias for var[String], the corresponding Java type will be called Var

/////////// General Prop Log ////////////////

alias Pl.Or -> or[Pl.F, Pl.F]; // "Propositional logic Or" will be an inner class of Pl
alias Pl.And -> and[Pl.F,Pl.F]; 
alias Pl.Not -> not[Pl.F];
alias Pl.Xor -> xor[Pl.F,Pl.F];
alias Pl.Imp -> imp[Pl.F,Pl.F]; 

type Pl.F=Pl.Or | Pl.And | Pl.Not | Pl.Xor | Pl.Imp | Var ;

/////////// CNF ////////////////

alias CNF.And -> and[CNF.F,CNF.F];  // "CNF And" will be an inner class of CNF
alias CNF.Or ->  or[CNF.Clause, CNF.Clause];
alias CNF.Not -> not[Var];

type CNF.F=CNF.Clause | CNF.And ;
type CNF.Clause = CNF.Lit | CNF.Or ;
type CNF.Lit = Var | CNF.Not ;

The subtyping relation on generated classes

The subtyping relation on generated classes

Test example

TestPP.java contains a small testing class which demonstrates the pretty printer as well as the subtyping of the generated code.

import pl.Pl; // import Propositional logic
import pl.CNF; // import CNF logic

// statically import all constructs common to both logics
import static pl.Common.*; 

/**
 * A tiny testing class for {@code PP} and subtyping on formulas.
 * @author Mikolas Janota
 */
public class TestPP {
    public static void main(String[] args) {
        // Construction is done through static functions 
        // for conciseness reasons.

        // prepare a couple of variables
        Var a=Var("a");
        Var b=Var("b");
        Var c=Var("c");

        // construct two Propositional Logic formulas
        Pl.F f = Pl.Not(Pl.And(a, b));
        Pl.F f1 = Pl.Xor(a, c);

        // and one CNF formula
        CNF.F cnf = CNF.And(a, CNF.Not(b));

        // print via PP
        PP pp=new PP();
        System.out.println(pp.print(f));
        System.out.println(pp.print(f1));
        System.out.println(pp.print(cnf));

        // the following just shows that subtyping works as expected 
        Pl.F fFoo=cnf; // OK
        Pl.And fAnd=CNF.And(a, c); // OK
        CNF.F And1=CNF.And(a, c); // OK

        // uncommenting causes compilation error
        //        And1=fAnd;
        //        fAnd=And1;
        //        CNF.F cnfFoo=f1; // not OK
        //        CNF.F cnfBar=CNF.Or(CNF.And(a, b), c);
    }
}

Pretty printer

Source of the pretty printer is contained in PP.java:

import static pl.Pl.*; // import all constructs for Propositional Logic
import static pl.Common.*; // import all constructs common for all Logics

/**
 * A simple purely functional infix printer for Propositional Logic.
 * @author Mikolas Janota
 */
public class PP extends MinVisitor<String> {
    private static String p(String s) { return "(" + s + ")"; }

    /** Converts a given formula to  a String representation. */
    public String print(F f) { return eval(f); }

    @Override public String visit(Var v, String s)  { return s; }

    @Override public String visit(Xor n, String first, String second) 
        {return p(first) + " XOR " + p(second);}
  
    @Override public String visit(Imp n, String first, String second) 
        {return p(first) + " => " + p(second);}
  
    @Override public String visit(Or n, String first, String second) 
        {return p(first) + " OR " + p(second);}
  
    @Override public String visit(Not n, String first) 
        {return "NOT" + p(first);}
  
    @Override public String visit(And n, String first, String second) 
        {return p(first) + " AND " + p(second);}

}

Visitor

Minimal visitor with memoization, partially generated by the tool is in the file MinVisitor.java:

import static pl.Common.*;
import pl.Pl;
import pl.CNF;

import java.util.HashMap;

/** 
 * A visitor stub for depth-first search traversal. 
 */
public abstract class MinVisitor<R> implements Pl.FVisitor<R> {
    private final HashMap<Pl.F, R> m=new HashMap<Pl.F, R>();

    R eval(Pl.F n) { 
        // memoize
        R retv=m.get(n);
        if (retv!=null) return retv;
        retv=n.accept(this); 
        m.put(n, retv);
        return retv;
    }

  public final R visit(Var node) { return visit(node, node.getFirst()); }

  public final R visit(Pl.Xor node) {
    return visit(node, eval(node.getFirst()), eval(node.getSecond()));
  }

  public final R visit(CNF.Not node) {
    return visit(node, eval(node.getFirst()));
  }

  public final R visit(Pl.Imp node) {
    return visit(node, eval(node.getFirst()), eval(node.getSecond()));
  }

  public final R visit(CNF.Or node) {
    return visit(node, eval(node.getFirst()), eval(node.getSecond()));
  }

  public final R visit(Pl.Or node) {
    return visit(node, eval(node.getFirst()), eval(node.getSecond()));
  }

  public final R visit(Pl.Not node) {
    return visit(node, eval(node.getFirst()));
  }

  public final R visit(CNF.And node) {
    return visit(node, eval(node.getFirst()), eval(node.getSecond()));
  }

  public final R visit(Pl.And node) {
    return visit(node, eval(node.getFirst()), eval(node.getSecond()));
  }
 
  public abstract R visit(Var n, String first);
  public abstract R visit(Pl.Xor n, R first, R second);
  public abstract R visit(Pl.Imp n, R first, R second);
  public abstract R visit(Pl.Or n, R first, R second);
  public abstract R visit(Pl.And n, R first, R second);
  public abstract R visit(Pl.Not n, R first);

  // run parent visit methods   
  public R visit(CNF.Not n, R first) {return visit((Pl.Not)n);}
  public R visit(CNF.Or n, R first, R second) {return visit((Pl.Or)n);}
  public R visit(CNF.And n, R first, R second) {return visit((Pl.And)n);}
}