From f0ed4df2b0e11ab66966a8395cd7d6d29c7a8efc Mon Sep 17 00:00:00 2001 From: Camil Staps Date: Fri, 3 Jul 2015 23:39:40 +0200 Subject: Latex & Html output options --- Logic.dcl | 23 +++++++--- Logic.icl | 134 ++++++++++++++++++++++++++++++++++++++------------------ LogicParser.icl | 16 ++++--- README.md | 3 ++ StringUtils.dcl | 4 +- StringUtils.icl | 10 +++-- index.html | 4 +- request.php | 2 +- 8 files changed, 134 insertions(+), 62 deletions(-) diff --git a/Logic.dcl b/Logic.dcl index 1a0821b..23ae191 100644 --- a/Logic.dcl +++ b/Logic.dcl @@ -23,7 +23,7 @@ */ definition module Logic -import StdEnv +import StdEnv, StdMaybe // Expressions :: Expr = B Bool // A constant @@ -47,6 +47,19 @@ import StdEnv :: AtomOption :== (AtomName,Bool) :: TruthTable = {exprs :: [Expr], options :: [[AtomOption]]} +:: FilledTruthTable = {table :: TruthTable, values :: [[Maybe Bool]]} + +:: OutputOption = Plain | Html | LaTeX +DefaultOutputOption :== Plain +instance == OutputOption + +class show a :: OutputOption a -> String +instance show Bool +instance show Char +instance show Op1 +instance show Op2 +instance show Expr +instance show FilledTruthTable isBool :: Expr -> Bool isAtom :: Expr -> Bool @@ -60,11 +73,6 @@ isOr :: Expr -> Bool isImpl :: Expr -> Bool isEquiv :: Expr -> Bool -instance toString Op1 -instance toString Op2 -instance toString Expr -instance toString TruthTable - instance == Op1 instance < Op1 // Maybe useful later if more unary operators are added instance == Op2 @@ -87,6 +95,9 @@ sorted_subexprs :: (Expr -> [Expr]) // Similar, but roughly sorted by co simple_truthtable :: Expr -> TruthTable // Simple truthtable: only the atomic expression and the expression itself simple_truthtable_n :: [Expr] -> TruthTable // Simple truthtable with multiple expressions truthtable :: Expr -> TruthTable // Truthtable from an expression +truthtable_n :: [Expr] -> TruthTable // Truthtable with multiple expressions + +compute :: TruthTable -> FilledTruthTable // Fill in a truthtable parse :: String -> Expr // Parse a string into an expression diff --git a/Logic.icl b/Logic.icl index dabc71d..97d8df5 100644 --- a/Logic.icl +++ b/Logic.icl @@ -23,7 +23,7 @@ */ implementation module Logic -import StdEnv, StringUtils +import StdEnv, StdMaybe, StringUtils isBool :: Expr -> Bool isBool (B _) = True @@ -73,50 +73,51 @@ apply2 x Or y = x || y apply2 x Impl y = y || not x apply2 x Equiv y = x == y -instance toString Op1 +instance == OutputOption where - toString Not = "~" + (==) Plain Plain = True + (==) Html Html = True + (==) LaTeX LaTeX = True + (==) _ _ = False -instance toString Op2 +instance show Bool where - toString And = "&" - toString Or = "|" - toString Impl = "->" - toString Equiv = "<->" + show LaTeX True = "\\top" + show LaTeX False = "\\bot" + show _ b = toString b -instance toString Expr +instance show Char where - toString (B b) = toString b - toString (Atom a) = toString a - toString (App1 op e) - | needs_parentheses (App1 op e) = toString op +++ "(" +++ toString e +++ ")" - | otherwise = toString op +++ toString e - toString (App2 e1 op e2) = e1` +++ " " +++ toString op +++ " " +++ e2` - where - e1` - | needs_parentheses_left (App2 e1 op e2) = "(" +++ toString e1 +++ ")" - | otherwise = toString e1 - e2` - | needs_parentheses_right (App2 e1 op e2) = "(" +++ toString e2 +++ ")" - | otherwise = toString e2 - -instance toString TruthTable + show LaTeX c = " " +++ toString c + show _ c = toString c + +instance show Op1 where - toString t=:{exprs,options} - = row_b +++ join row_s [pad_right ' ' head len \\ head <- map toString exprs & len <- padlens] +++ row_e +++ - line_b +++ join line_s [toString (repeatn len '-') \\ len <- padlens] +++ line_e +++ - foldr (+++) "" [row_b +++ join row_s [pad_right ' ' (toStringOrEmpty val) len \\ val <- map (eval o substitute_all options`) exprs & len <- padlens] +++ row_e \\ options` <- options] - where - row_b = " " // Row / Line begin, end, separator - row_e = " \n" - row_s = " | " - line_b = "-" - line_e = "-\n" - line_s = "-+-" - padlens = map ((max 5) o strlen o toString) exprs // 5 is the length of False - toStringOrEmpty :: [Bool] -> String - toStringOrEmpty [] = "" - toStringOrEmpty [b:bs] = toString b + show Plain Not = "~" + show Html Not = "¬" + show LaTeX Not = "\\neg" + +instance show Op2 +where + show Plain And = "&" + show Plain Or = "|" + show Plain Impl = "->" + show Plain Equiv = "<->" + show Html And = "∧" + show Html Or = "∨" + show Html Impl = "→" + show Html Equiv = "↔" + show LaTeX And = "\\land" + show LaTeX Or = "\\lor" + show LaTeX Impl = "\\rightarrow" + show LaTeX Equiv = "\\leftrightarrow" + +instance show Expr +where + show opt (B b) = show opt b + show opt (Atom a) = show opt a + show opt (App1 op e) = show opt op +++ show opt e + show opt (App2 e1 op e2) = show opt e1 +++ " " +++ show opt op +++ " " +++ show opt e2 instance == Op1 where @@ -175,7 +176,7 @@ where comp e1 e2 | isMember e1 (subexprs e2) = True | isMember e2 (subexprs e1) = False - | otherwise = strlen (toString e1) < strlen (toString e2) + | otherwise = strlen (show Plain e1) < strlen (show Plain e2) // Does a the argument of a unary operator need parentheses? needs_parentheses :: Expr -> Bool @@ -256,6 +257,55 @@ simple_truthtable_n es = {exprs = removeDup ([Atom a \\ a <- flatten (map all_at truthtable :: Expr -> TruthTable truthtable e = {exprs = sorted_subexprs e ++ [e], options = all_atom_options e} +truthtable_n :: [Expr] -> TruthTable +truthtable_n es = {exprs = sort (removeDup (flatten ([[e:subexprs e] \\ e <- es]))), options = removeDup (flatten (map all_atom_options es))} + +compute :: TruthTable -> FilledTruthTable // Fill in a truthtable +compute table=:{exprs,options} = {table=table, values=values} +where + values = [[toMaybeBool val \\ val <- map (eval o substitute_all options`) exprs] \\ options` <- options] + toMaybeBool [] = Nothing + toMaybeBool [b:bs] = Just b + +instance show FilledTruthTable +where + show :: OutputOption FilledTruthTable -> String + show opt t=:{table=table=:{exprs,options},values} + = begin +++ + head_b +++ + join head_s [pad_right (showOrNot head_i) header len \\ header <- map (show opt) exprs & len <- padlens] +++ + head_e +++ + line_b +++ + join line_s [foldr (+++) "" (repeatn len (showOrNot line_i)) \\ len <- padlens] +++ + line_e +++ + foldr (+++) "" [row_b +++ join row_s [pad_right (showOrNot row_i) (showOrNot v) len \\ v <- r & len <- padlens] +++ row_e \\ r <- values] +++ + end + where + padlens = map ((\l . maxList (map strlen [l,show opt True,show opt False])) o (show opt)) exprs + // Ideally, we would some kind of DOM writer for Html, but for this project this is sufficient (although not very readable) + (begin,end) = gen + gen + | opt == Plain = ("","") + | opt == Html = ("", "
") + | opt == LaTeX = ("\\begin{tabular}{" +++ join "|" (repeatn (length exprs) "c") +++ "}", "\\end{tabular}") + (head_b,head_e,head_s,head_i) = head + head + | opt == Html = ("", "", "", Nothing) + | otherwise = row + (row_b,row_e,row_s,row_i) = row + row + | opt == Plain = (" ", " \n", " | ", Just ' ') + | opt == Html = ("", "", "", Nothing) + | opt == LaTeX = ("$", "$\\\\", "$&$", Nothing) + (line_b,line_e,line_s,line_i) = line + line + | opt == Plain = ("-", "-\n", "-+-", Just '-') + | opt == Html = ("", "", "", Nothing) + | opt == LaTeX = ("\\hline", "", "", Nothing) + showOrNot :: (Maybe a) -> String | show a + showOrNot Nothing = "" + showOrNot (Just a) = show opt a + NOT :== '~' AND :== '&' OR :== '|' @@ -313,7 +363,7 @@ where parse_stack` :: [Char] [Expr] -> Expr parse_stack` [] [e] = e parse_stack` [] [] = abort "Cannot parse: not enough expressoins on the stack" - parse_stack` [] es = abort ("Cannot parse: too many expressions on the stack:\n" +++ join "\n" (map toString es) +++ "\n") + parse_stack` [] es = abort ("Cannot parse: too many expressions on the stack:\n" +++ join "\n" (map (show Plain) es) +++ "\n") parse_stack` [AND:st] [e1:[e2:es]] = parse_stack` st [App2 e2 And e1:es] parse_stack` [OR:st] [e1:[e2:es]] = parse_stack` st [App2 e2 Or e1:es] parse_stack` [IMPL:st] [e1:[e2:es]] = parse_stack` st [App2 e2 Impl e1:es] @@ -322,7 +372,7 @@ where parse_stack` [c:st] es | cIsAtom [c] = parse_stack` st [Atom (cToAtom [c]) : es] | cIsBool [c] = parse_stack` st [B (cToBool [c]) : es] - parse_stack` [c:st] es = abort ("Cannot parse: tried to perform an operation (" +++ toString c +++ ") with too few expressions on the stack:\n" +++ join "," (map toString es) +++ "\n") + parse_stack` [c:st] es = abort ("Cannot parse: tried to perform an operation (" +++ show Plain c +++ ") with too few expressions on the stack:\n" +++ join "," (map (show Plain) es) +++ "\n") cIsOp :: [Char] -> Bool cIsOp ['~'] = True diff --git a/LogicParser.icl b/LogicParser.icl index 320e2cc..fbf19ef 100644 --- a/LogicParser.icl +++ b/LogicParser.icl @@ -26,12 +26,18 @@ module LogicParser import StdEnv, StdMaybe, ArgEnv, Logic Start -| argc < 1 = abort ("Usage: " +++ argv.[0] +++ " -b -nt \n") -| extended = toString (truthtable (parse argv.[2])) -| otherwise = toString (simple_truthtable_n [parse argv.[n] \\ n <- [1..argc]]) -//| otherwise = toString ((if extended truthtable simple_truthtable) (parse argv.[1])) +| isEmpty exprs = abort ("Usage: " +++ argv.[0] +++ " -b -nt [-e] [-html|-latex] \n") +| otherwise = show outputoption (compute (if extended truthtable_n simple_truthtable_n (map parse exprs))) where argc = size argv - 1 argv = getCommandLine - extended = argv.[1] == "-e" + + exprs = filter (\s . s.[0] <> '-') [argv.[n] \\ n <- [1..argc]] + + extended = hasArg "-e" + outputoption + | hasArg "-html" = Html + | hasArg "-latex" = LaTeX + | otherwise = Plain + hasArg arg = or [arg == argv.[n] \\ n <- [0..argc]] diff --git a/README.md b/README.md index d52cb15..185406c 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ Logic toolbox in [Clean](http://wiki.clean.cs.ru.nl/Clean). Features include: * Displaying truth tables * Parsing strings to expressions * A web frontend to access the Clean program through, so only server-side installation is necessary + * Different output options (Plain / ASCII art, HTML, LaTeX) Read further for examples. @@ -148,6 +149,8 @@ The option `-e` tells the parser to show the extended truth table. With this opt True | False | True | False True | True | True | True +The parsers also recognises `-html` and `-latex` and will output an HTML or LaTeX table if these arguments are present. + ## Web frontend There is a simple web frontend in PHP and a basic HTML template which allows one to connect to the Clean application through his browser. The files for this are `index.html` and `request.php`, and a demo may be found on https://demo.camilstaps.nl/CleanLogic. For this to work, the `exec()` function should be enabled in your PHP configuration. diff --git a/StringUtils.dcl b/StringUtils.dcl index 5593c4c..22e80ad 100644 --- a/StringUtils.dcl +++ b/StringUtils.dcl @@ -27,8 +27,8 @@ import StdEnv strlen :: String -> Int // Length of a String -pad_right :: Char String Int -> String // Pad a String with Chars up to a length -pad_left :: Char String Int -> String // Similar, but pad on the left +pad_right :: String String Int -> String // Pad a String (@2) with another String (@1) up to a length +pad_left :: String String Int -> String // Similar, but pad on the left join :: String [String] -> String // Join a [String] with a String glue diff --git a/StringUtils.icl b/StringUtils.icl index 811b3d2..91e3d4f 100644 --- a/StringUtils.icl +++ b/StringUtils.icl @@ -31,15 +31,17 @@ where s` :: [Char] s` = fromString s -pad_right :: Char String Int -> String +pad_right :: String String Int -> String pad_right c s l | strlen s >= l = s -| otherwise = s +++ toString (repeatn (l - strlen s) c) +| strlen c == 0 = s +| otherwise = foldl (+++) s (repeatn ((l - strlen s) / strlen c) c) -pad_left :: Char String Int -> String +pad_left :: String String Int -> String pad_left c s l | strlen s >= l = s -| otherwise = toString (repeatn (l - strlen s) c) +++ s +| strlen c == 0 = s +| otherwise = foldr (+++) s (repeatn ((l - strlen s) / strlen c) c) join :: String [String] -> String join glue [] = "" diff --git a/index.html b/index.html index 48ad677..9a9c301 100644 --- a/index.html +++ b/index.html @@ -77,7 +77,7 @@

Truth table

Truth tables are generated with a server-side Clean program.

- +
@@ -94,7 +94,7 @@ expressions: $('#expressions').val().split("\n") }, success: function (data) { - $('#truthtable').val(data); + $('#truthtable').html(data).find('table').addClass('table table-striped table-condensed table-bordered table-hover'); } }); }).trigger('click'); diff --git a/request.php b/request.php index 594ae4f..2866ada 100644 --- a/request.php +++ b/request.php @@ -43,7 +43,7 @@ $expressions = array_map('escapeshellarg', $expressions); $expressions = implode(' ', $expressions); $extended = $extended ? '-e' : ''; -$call = './LogicParser -b -nt ' . $extended . ' ' . $expressions; +$call = './LogicParser -b -nt -html ' . $extended . ' ' . $expressions; $out = []; exec($call, $out); -- cgit v1.2.3