{- 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.Char import Data.Foldable (toList) import qualified Data.List as List import qualified Data.Map as Map import BNFC.Utils import BNFC.CF import BNFC.Options import BNFC.Backend.Base import BNFC.Backend.C (bufferH, bufferC) import BNFC.Backend.C.CFtoBisonC (cf2Bison) import BNFC.Backend.C.CFtoFlexC (cf2flex, ParserMode(..)) 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 mkfile "Absyn.H" hfile mkfile "Absyn.C" cfile mkfile "Buffer.H" bufferH mkfile "Buffer.C" $ bufferC "Buffer.H" let (flex, env) = cf2flex parserMode cf mkfile (name ++ ".l") flex let bison = cf2Bison (linenumbers opts) parserMode cf env mkfile (name ++ ".y") bison let header = mkHeaderFile (inPackage opts) cf (allParserCats cf) (toList $ allEntryPoints cf) (Map.elems env) mkfile "Parser.H" header mkfile "ParserError.H" $ printParseErrHeader (inPackage opts) let (skelH, skelC) = cf2CVisitSkel True (inPackage opts) cf mkfile "Skeleton.H" skelH mkfile "Skeleton.C" skelC let (prinH, prinC) = cf2CPPPrinter True (inPackage opts) cf mkfile "Printer.H" prinH mkfile "Printer.C" prinC mkfile "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 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 [ "/*** 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 ", "#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 inPackage cf cats eps env = unlines $ concat [ [ "#ifndef " ++ hdef , "#define " ++ hdef , "" , "#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);" ]