{- BNF Converter: C++ Main file Copyright (C) 2004 Author: Markus Forsberg, Michael Pellauer Copyright (C) 2020 Andreas Abel Modified from CPPTop to BNFC.Backend.CPP.STL 2006 by Aarne Ranta. -} module BNFC.Backend.CPP.STL (makeCppStl,) where import Data.Foldable (toList) import BNFC.Utils import BNFC.CF import BNFC.Options import BNFC.Backend.Base import BNFC.Backend.C ( bufferH, bufferC, comment, testfileHeader ) import BNFC.Backend.C.CFtoBisonC ( cf2Bison ) import BNFC.Backend.C.CFtoFlexC ( cf2flex, ParserMode(..) ) import BNFC.Backend.CPP.Common ( commentWithEmacsModeHint ) import BNFC.Backend.CPP.Makefile import BNFC.Backend.CPP.STL.CFtoSTLAbs import BNFC.Backend.CPP.STL.CFtoCVisitSkelSTL import BNFC.Backend.CPP.PrettyPrinter import BNFC.Backend.CPP.STL.STLUtils import qualified BNFC.Backend.Common.Makefile as Makefile makeCppStl :: SharedOptions -> CF -> MkFiles () makeCppStl opts cf = do let (hfile, cfile) = cf2CPPAbs (linenumbers opts) (inPackage opts) name cf mkCppFile "Absyn.H" hfile mkCppFile "Absyn.C" cfile mkCppFile "Buffer.H" bufferH mkCppFile "Buffer.C" $ bufferC "Buffer.H" let (flex, env) = cf2flex parserMode cf mkCppFileWithHint (name ++ ".l") flex mkCppFileWithHint (name ++ ".y") $ cf2Bison (linenumbers opts) parserMode cf env mkCppFile "Parser.H" $ mkHeaderFile (inPackage opts) (toList $ allEntryPoints cf) mkCppFile "ParserError.H" $ printParseErrHeader (inPackage opts) let (skelH, skelC) = cf2CVisitSkel True (inPackage opts) cf mkCppFile "Skeleton.H" skelH mkCppFile "Skeleton.C" skelC let (prinH, prinC) = cf2CPPPrinter True (inPackage opts) cf mkCppFile "Printer.H" prinH mkCppFile "Printer.C" prinC mkCppFile "Test.C" (cpptest (inPackage opts) cf) Makefile.mkMakefile opts $ makefile prefix name where name :: String name = lang opts -- The prefix is a string used by flex and bison -- that is prepended to generated function names. -- It should be a valid C identifier. prefix :: String prefix = snakeCase_ name ++ "_" parserMode :: ParserMode parserMode = CppParser (inPackage opts) prefix mkCppFile x = mkfile x comment mkCppFileWithHint x = mkfile x commentWithEmacsModeHint printParseErrHeader :: Maybe String -> String printParseErrHeader inPackage = unlines [ " #pragma once " , " #include " , " #include " , "" , nsStart inPackage , " class parse_error : public std::runtime_error" , " {" , " public:" , " parse_error(int line, std::string str)" , " : std::runtime_error(str)" , " , m_line(line) {}" , " int getLine() {" , " return m_line;" , " } " , " private:" , " int m_line;" , " }; " , nsEnd inPackage ] cpptest :: Maybe String -> CF -> String cpptest inPackage cf = unlines $ concat [ testfileHeader , [ "", "#include ", "#include ", "#include ", "#include \"Parser.H\"", "#include \"Printer.H\"", "#include \"Absyn.H\"", "#include \"ParserError.H\"", "", "void usage() {", " printf(\"usage: Call with one of the following argument " ++ "combinations:\\n\");", " printf(\"\\t--help\\t\\tDisplay this help message.\\n\");", " printf(\"\\t(no arguments)\\tParse stdin verbosely.\\n\");", " printf(\"\\t(files)\\t\\tParse content of files verbosely.\\n\");", " printf(\"\\t-s (files)\\tSilent mode. Parse content of files " ++ "silently.\\n\");", "}", "", "int main(int argc, char ** argv)", "{", " FILE *input;", " int quiet = 0;", " char *filename = NULL;", "", " if (argc > 1) {", " if (strcmp(argv[1], \"-s\") == 0) {", " quiet = 1;", " if (argc > 2) {", " filename = argv[2];", " } else {", " input = stdin;", " }", " } else {", " filename = argv[1];", " }", " }", "", " if (filename) {", " input = fopen(filename, \"r\");", " if (!input) {", " usage();", " exit(1);", " }", " } else input = stdin;", " /* The default entry point is used. For other options see Parser.H */", " " ++ scope ++ dat ++ " *parse_tree = NULL;", " try { ", " parse_tree = " ++ scope ++ "p" ++ def ++ "(input);", " } catch( " ++ scope ++ "parse_error &e) {", " std::cerr << \"Parse error on line \" << e.getLine() << \"\\n\"; ", " }", " if (parse_tree)", " {", " printf(\"\\nParse Successful!\\n\");", " if (!quiet) {", " printf(\"\\n[Abstract Syntax]\\n\");", " " ++ scope ++ "ShowAbsyn *s = new " ++ scope ++ "ShowAbsyn();", " printf(\"%s\\n\\n\", s->show(parse_tree));", " printf(\"[Linearized Tree]\\n\");", " " ++ scope ++ "PrintAbsyn *p = new " ++ scope ++ "PrintAbsyn();", " printf(\"%s\\n\\n\", p->print(parse_tree));", " }", " delete(parse_tree);", " return 0;", " }", " return 1;", "}", "" ] ] where cat = firstEntry cf dat = identCat $ normCat cat def = identCat cat scope = nsScope inPackage mkHeaderFile :: Maybe String -> [Cat] -> String mkHeaderFile inPackage eps = unlines $ concat [ [ "#ifndef " ++ hdef , "#define " ++ hdef , "" , "#include" , "#include" , "#include" , "#include \"Absyn.H\"" , "" , nsStart inPackage ] , concatMap mkFuncs eps , [ nsEnd inPackage , "" , "#endif" ] ] where hdef = nsDefine inPackage "PARSER_HEADER_FILE" mkFuncs s = [ identCat (normCat s) ++ "*" +++ "p" ++ identCat s ++ "(FILE *inp);" , identCat (normCat s) ++ "*" +++ "p" ++ identCat s ++ "(const char *str);" ]