{- BNF Converter: C Main file Copyright (C) 2004 Author: Michael Pellauer This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -} module CTop (makeC) where import Utils import CF import CFtoCAbs import CFtoFlexC import CFtoBisonC import CFtoCSkel import CFtoCPrinter import CFtoLatex import Data.Char import System.Exit (exitFailure) makeC :: Bool -> String -> CF -> IO () makeC make name cf = do let (hfile, cfile) = cf2CAbs name cf writeFileRep "Absyn.h" hfile writeFileRep "Absyn.c" cfile let (flex, env) = cf2flex name cf writeFileRep (name ++ ".l") flex putStrLn " (Tested with flex 2.5.31)" let bison = cf2Bison name cf env writeFileRep (name ++ ".y") bison putStrLn " (Tested with bison 1.875a)" let header = mkHeaderFile cf (allCats cf) (allEntryPoints cf) env writeFileRep "Parser.h" header let (skelH, skelC) = cf2CSkel cf writeFileRep "Skeleton.h" skelH writeFileRep "Skeleton.c" skelC let (prinH, prinC) = cf2CPrinter cf writeFileRep "Printer.h" prinH writeFileRep "Printer.c" prinC writeFileRep "Test.c" (ctest cf) let latex = cfToLatex name cf writeFileRep (name ++ ".tex") latex if make then (writeFileRep "Makefile" $ makefile name) else return () makefile :: String -> String makefile name = unlines [ "CC = gcc", "CCFLAGS = -g -W -Wall", "", "FLEX = flex", "FLEX_OPTS = -P" ++ name, "", "BISON = bison", "BISON_OPTS = -t -p" ++ name, "", "LATEX = pdflatex", "", "all: Test" ++ name ++ " " ++ name ++ ".pdf", "", ".PHONY: clean distclean", "", "clean:", -- peteg: don't nuke what we generated - move that to the "vclean" target. "\trm -f *.o " ++ name ++ ".dvi " ++ name ++ ".aux " ++ name ++ ".log " ++ name ++ ".pdf Test" ++ name, "", "distclean: clean", -- FIXME "\trm -f *.o Absyn.c Absyn.h Test.c Parser.c Parser.h Lexer.c Skeleton.c Skeleton.h Printer.c Printer.h " ++ name ++ ".l " ++ name ++ ".y " ++ name ++ ".tex " ++ name ++ ".dvi " ++ name ++ ".aux " ++ name ++ ".log " ++ name ++ ".pdf Test" ++ name ++ " Makefile", "", "Test" ++ name ++ ": Absyn.o Lexer.o Parser.o Printer.o Test.o", "\t@echo \"Linking test" ++ name ++ "...\"", "\t${CC} ${CCFLAGS} *.o -o Test" ++ name ++ "", "", "Absyn.o: Absyn.c Absyn.h", "\t${CC} ${CCFLAGS} -c Absyn.c", "", "Lexer.c: " ++ name ++ ".l", "\t${FLEX} ${FLEX_OPTS} -oLexer.c " ++ name ++ ".l", "", "Parser.c: " ++ name ++ ".y", "\t${BISON} ${BISON_OPTS} " ++ name ++ ".y -o Parser.c", "", "Lexer.o: Lexer.c Parser.h", "\t${CC} ${CCFLAGS} -c Lexer.c ", "", "Parser.o: Parser.c Absyn.h", "\t${CC} ${CCFLAGS} -c Parser.c", "", "Printer.o: Printer.c Printer.h Absyn.h", "\t${CC} ${CCFLAGS} -c Printer.c", "", "Test.o: Test.c Parser.h Printer.h Absyn.h", "\t${CC} ${CCFLAGS} -c Test.c", "", "" ++ name ++ ".pdf: " ++ name ++ ".tex", "\t${LATEX} " ++ name ++ ".tex", "" ] ctest :: CF -> String ctest cf = unlines [ "/*** Compiler Front-End Test automatically generated by the BNF Converter ***/", "/* */", "/* This test will parse a file, print the abstract syntax tree, and then */", "/* pretty-print the result. */", "/* */", "/****************************************************************************/", "", "#include ", "#include ", "", "#include \"Parser.h\"", "#include \"Printer.h\"", "#include \"Absyn.h\"", "", "int main(int argc, char ** argv)", "{", " FILE *input;", " " ++ def ++ " parse_tree;", " if (argc > 1) ", " {", " input = fopen(argv[1], \"r\");", " if (!input)", " {", " fprintf(stderr, \"Error opening input file.\\n\");", " exit(1);", " }", " }", " else input = stdin;", " /* The default entry point is used. For other options see Parser.h */", " parse_tree = p" ++ def ++ "(input);", " if (parse_tree)", " {", " printf(\"\\nParse Succesful!\\n\");", " printf(\"\\n[Abstract Syntax]\\n\");", " printf(\"%s\\n\\n\", show" ++ def ++ "(parse_tree));", " printf(\"[Linearized Tree]\\n\");", " printf(\"%s\\n\\n\", print" ++ def ++ "(parse_tree));", " return 0;", " }", " return 1;", "}", "" ] where def = head (allEntryPoints cf) mkHeaderFile :: CF -> [Cat] -> [Cat] -> [(a, String)] -> String mkHeaderFile cf cats eps env = unlines [ "#ifndef PARSER_HEADER_FILE", "#define PARSER_HEADER_FILE", "", "#include \"Absyn.h\"", "", "typedef union", "{", " int int_;", " char char_;", " double double_;", " char* string_;", (concatMap mkVar cats) ++ "} YYSTYPE;", "", "#define _ERROR_ 258", mkDefines (259::Int) env, "extern YYSTYPE yylval;", concatMap mkFunc eps, "", "#endif" ] where mkVar s | (normCat s == s) = " " ++ (identCat s) +++ (map toLower (identCat s)) ++ "_;\n" mkVar _ = "" mkDefines n [] = mkString n mkDefines n ((_,s):ss) = ("#define " ++ s +++ (show n) ++ "\n") ++ (mkDefines (n+1) ss) mkString n = if isUsedCat cf "String" then ("#define _STRING_ " ++ show n ++ "\n") ++ mkChar (n+1) else mkChar n mkChar n = if isUsedCat cf "Char" then ("#define _CHAR_ " ++ show n ++ "\n") ++ mkInteger (n+1) else mkInteger n mkInteger n = if isUsedCat cf "Integer" then ("#define _INTEGER_ " ++ show n ++ "\n") ++ mkDouble (n+1) else mkDouble n mkDouble n = if isUsedCat cf "Double" then ("#define _DOUBLE_ " ++ show n ++ "\n") ++ mkIdent(n+1) else mkIdent n mkIdent n = if isUsedCat cf "Ident" then ("#define _IDENT_ " ++ show n ++ "\n") else "" mkFunc s | (normCat s == s) = (identCat s) ++ " p" ++ (identCat s) ++ "(FILE *inp);\n" mkFunc _ = ""