/*
CSC 124: The Truth Lab First Stage
Progress Grades will be Given Second Week of Class
In this multi-part assignment we will learn the basics of lexical
analysis and parsing, using the JFlex lexical analyzer but with
(eventually) your own parser generator.
PART I: Do textbook exercises 2.1a-c, 2.4, and 2.5a.
Ultimately, you need to write a program that takes as input a sentence of
propositional logic, and output a truth table for the sentence.
As examples: (transcripts of my working program:)
Enter proposition: (a|b)->(b&c&!a)
a b c | value
0 0 0 | 1
0 0 1 | 1
0 1 0 | 0
0 1 1 | 1
1 0 0 | 0
1 0 1 | 0
1 1 0 | 0
1 1 1 | 0
Enter proposition: ~(a ^ b) -> ~a v ~b
a b | value
0 0 | 1
0 1 | 1
1 0 | 1
1 1 | 1
The symbol | represents "or", & is "and", ! is "not" and -> is
"implies". It is also valid to use the symbol "^" for "and", "v" for
"or" and "~" for "not". Use 0 or F for the constant false and 1 or T
for true. The above proposition can also be written as
a v b -> b ^ c^~a
Propositional variables are NOT limited to single letters: a2 -> a2 is fine.
Of course, avb should not be confused with a v b: sometimes spaces are needed.
Syntactically, negation ! (~) binds tighter than all other
connectives (so you need to specify the precedence for it in the
correct way). & binds tighter than than |, which in turn binds
tighter than ->. & and | associates to the left but -> associates to
the right. For example, a->!b|c is the same as a->((!b)|c).
PART II: Use JFlex to write a lexical analyzer for this syntax. All the
lexical analyzer produces are tokens. It does not have to do anything else.
Issues such as precedence and associativity of the operators are left to the
parsing phase of the assignment. You can put print statements in the action
part of each state transition to tracet the recognition of each token.
Your JFlex lexer should output instances of the following class (put in
separate file)
public class Gsym
{
public final String sym;
public String javatype = null;
public boolean nonterminal = false;
public String assoc = null; // label of object associated with symbol.
public Object value = null;
// assoc and value never used together: assoc in rule, value on stack
public Gsym(String x) {sym=x;}
public Gsym(String x, Object v) {sym=x; value=v;}
public Gsym(String x, String y, boolean t)
{sym=x; javatype=y; nonterminal=t;}
public Gsym clone()
{ Gsym g = new Gsym(sym,javatype,nonterminal);
g.assoc = assoc; g.value = value;
return g;
}
}//Gsym
This is the generic "symbol" class used by MVOPG (my very own parser
generator). Unlike Java Cup (yacc), I simplified things so that the lexer
and the parser both use this "grammar symbol" class. Not everything in this
class pertains to this assignment. For example, when you see "->" you can
just return a new Gsym("->"); Consult my examples. Write a main to test that
your lexer is indeed reading all the symbols. The lexer class generated by
JFlex contains a public method yylex() to return symbols one at a time.
Part III: Abstract syntax.
Write an independent java program that represents abstract syntax trees for
propositional sentences. Look at my examples (calculator, jBasic interpreter)
for examples. Also read textbook section 1.3 and chapter 4 for ideas.
Note that at some point I will ask you to convert your tree classes to use
the Visitor design pattern, but that is not technically required for part III.
After you compile the abstract syntax classes, the lexer generated by JFlex
should also compile.
Here are some specific hints:
public interface Prop // interface for all propositions
{
Boolean eval(Hashtable env); // evaluate proposition
void vars(ArrayList vs); // collects vars in vs list (init empty)
}
class propvar implements Prop // propositional variables
{
String varname;
public propvar(String s) {varname=s;}
public Boolean eval(Hashtable env)
{ return env.get(varname); }
public void vars(ArrayList vs)
{ if (!vs.contains(varname)) vs.add(varname); }
}
Part IV: Generating a truth table.
Write a routine that generates a truth table with output as shown
above. Since you don't have a parser yet, you can hand-code a couple
of small examples to test it (include ~(a & b) -> ~a | ~b (De Morgan
law). Hint on generating the lines of the truth table: If there are n
distinct propositional variables in your proposition, then there
should be (int)Math.pow(2,n) lines in the truth table. Each line
corresponds to binar numer (000, 001, 010, etc.). I believe there's
even a built-in "toBinaryString" function in java (find it yourself).
Unlike the online calculator example, we can't just perform the
calculation as we parse, because we don't know what values the
variables will be bound to. We need to generate an abstract syntax
tree structure that represents the expression. Then, after the
parsing stage, we need to enumerate all possible assignments for the
variables - that is, all possible combinations of 0's and 1's for the
variables of the sentence. Then we can evaluate the abstract syntax
tree for each "truth assignment" and determine the results. Thus
the eval method in the hint code takes a "env", which is a Hashtable
representing a truth assignment.
The truth table for -> is:
a b | a->b
0 0 | 1
0 1 | 1
1 0 | 0
1 1 | 1
***In order to receive a passing 1st progress grade, you must have
completed (not just attempted) each of parts 1-4 described above.
More parts later ...