packages feed

BNFC-2.6.0.0: src/formats/c/CTop.hs

{-
    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 <stdio.h>",
    "#include <stdlib.h>",
    "",
    "#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 _ = ""