From 663c0a758ccae21f90e5f8c75db5e6d7a421feed Mon Sep 17 00:00:00 2001 From: "hiroyuki.nagata" Date: Sun, 29 Aug 2021 15:48:48 +0900 Subject: [PATCH 1/9] Update C++STL test code to use unique_ptr * Modify include file and Parser header file name as psXXX * Add compile option to `src/BNFC/Backend/CPP/Makefile.hs` --- source/src/BNFC/Backend/CPP/Makefile.hs | 7 +++---- source/src/BNFC/Backend/CPP/NoSTL.hs | 4 +++- source/src/BNFC/Backend/CPP/STL.hs | 11 +++++++---- source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs | 5 +++-- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/source/src/BNFC/Backend/CPP/Makefile.hs b/source/src/BNFC/Backend/CPP/Makefile.hs index 464c5d82..933a0b60 100644 --- a/source/src/BNFC/Backend/CPP/Makefile.hs +++ b/source/src/BNFC/Backend/CPP/Makefile.hs @@ -5,10 +5,10 @@ module BNFC.Backend.CPP.Makefile (makefile) where import BNFC.Backend.Common.Makefile import BNFC.PrettyPrint -makefile :: String -> String -> String -> Doc -makefile prefix name basename = vcat +makefile :: String -> String -> String -> String -> Doc +makefile prefix name compileOpt basename = vcat [ mkVar "CC" "g++ -g" - , mkVar "CCFLAGS" "--ansi -W -Wall -Wsign-conversion -Wno-unused-parameter -Wno-unused-function -Wno-unneeded-internal-declaration" + , mkVar "CCFLAGS" (compileOpt ++ " -W -Wall -Wno-unused-parameter -Wno-unused-function -Wno-unneeded-internal-declaration") , "" , mkVar "FLEX" "flex" , mkVar "FLEX_OPTS" ("-P" ++ prefix) @@ -51,7 +51,6 @@ makefile prefix name basename = vcat , mkRule "Parser.C Bison.H" [ name ++ ".y" ] [ "${BISON} ${BISON_OPTS} " ++ name ++ ".y -o Parser.C" ] , mkRule "Lexer.o" [ "CCFLAGS+=-Wno-sign-conversion" ] - [] , mkRule "Lexer.o" [ "Lexer.C", "Bison.H" ] [ "${CC} ${CCFLAGS} -c Lexer.C " ] , mkRule "Parser.o" [ "Parser.C", "Absyn.H", "Bison.H" ] diff --git a/source/src/BNFC/Backend/CPP/NoSTL.hs b/source/src/BNFC/Backend/CPP/NoSTL.hs index 2eda55e7..ba093acd 100644 --- a/source/src/BNFC/Backend/CPP/NoSTL.hs +++ b/source/src/BNFC/Backend/CPP/NoSTL.hs @@ -40,7 +40,7 @@ makeCppNoStl opts cf = do mkCppFile "Printer.H" prinH mkCppFile "Printer.C" prinC mkCppFile "Test.C" (cpptest cf) - Makefile.mkMakefile opts $ makefile prefix name + Makefile.mkMakefile opts $ makefile prefix name compileOpt where name :: String name = lang opts @@ -49,6 +49,8 @@ makeCppNoStl opts cf = do -- It should be a valid C identifier. prefix :: String prefix = snakeCase_ name ++ "_" + compileOpt :: String + compileOpt = "--ansi" parserMode :: ParserMode parserMode = CParser True prefix mkCppFile x = mkfile x comment diff --git a/source/src/BNFC/Backend/CPP/STL.hs b/source/src/BNFC/Backend/CPP/STL.hs index d46f11e3..149be600 100644 --- a/source/src/BNFC/Backend/CPP/STL.hs +++ b/source/src/BNFC/Backend/CPP/STL.hs @@ -46,7 +46,7 @@ makeCppStl opts cf = do mkCppFile "Printer.H" prinH mkCppFile "Printer.C" prinC mkCppFile "Test.C" (cpptest (inPackage opts) cf) - Makefile.mkMakefile opts $ makefile prefix name + Makefile.mkMakefile opts $ makefile prefix name compileOpt where name :: String name = lang opts @@ -55,6 +55,8 @@ makeCppStl opts cf = do -- It should be a valid C identifier. prefix :: String prefix = snakeCase_ name ++ "_" + compileOpt :: String + compileOpt = "--ansi" parserMode :: ParserMode parserMode = CppParser (inPackage opts) prefix mkCppFile x = mkfile x comment @@ -91,6 +93,7 @@ cpptest inPackage cf = unlines $ concat "#include ", "#include ", "#include ", + "#include ", "#include \"Parser.H\"", "#include \"Printer.H\"", "#include \"Absyn.H\"", @@ -144,10 +147,10 @@ cpptest inPackage cf = unlines $ concat " printf(\"\\nParse Successful!\\n\");", " if (!quiet) {", " printf(\"\\n[Abstract Syntax]\\n\");", - " " ++ scope ++ "ShowAbsyn *s = new " ++ scope ++ "ShowAbsyn();", + " " ++ scope ++ "std::unique_ptr " ++ scope ++ "s(new ShowAbsyn());", " printf(\"%s\\n\\n\", s->show(parse_tree));", " printf(\"[Linearized Tree]\\n\");", - " " ++ scope ++ "PrintAbsyn *p = new " ++ scope ++ "PrintAbsyn();", + " " ++ scope ++ "std::unique_ptr " ++ scope ++ "p(new PrintAbsyn());", " printf(\"%s\\n\\n\", p->print(parse_tree));", " }", " delete(parse_tree);", @@ -186,5 +189,5 @@ mkHeaderFile inPackage eps = unlines $ concat 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);" + , identCat (normCat s) ++ "*" +++ "ps" ++ identCat s ++ "(const char *str);" ] diff --git a/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs b/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs index c5e9f3d9..6d2bf314 100644 --- a/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs +++ b/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs @@ -46,8 +46,9 @@ mkHFile rp inPackage cabs cf = unlines "#ifndef " ++ hdef, "#define " ++ hdef, "", - "#include", - "#include", + "#include ", + "#include ", + "#include ", "", "//C++ Abstract Syntax Interface.", nsStart inPackage, From 4f3a15eb13317a3ad36635c232c3a6313da3fa65 Mon Sep 17 00:00:00 2001 From: "hiroyuki.nagata" Date: Sun, 17 Oct 2021 14:19:40 +0900 Subject: [PATCH 2/9] Add switch Ansi/BeyondAnsi * Modify C++ generator module for mainly using unique_ptr --- Makefile | 2 + source/BNFC.cabal | 5 +- source/src/BNFC/Backend/CPP/NoSTL.hs | 2 +- .../{CFtoCPPAbs.hs => CFtoCPPAbsAnsi.hs} | 2 +- source/src/BNFC/Backend/CPP/STL.hs | 11 +- .../STL/{CFtoSTLAbs.hs => CFtoSTLAbsAnsi.hs} | 6 +- .../Backend/CPP/STL/CFtoSTLAbsBeyondAnsi.hs | 290 ++++++++++++++++++ 7 files changed, 309 insertions(+), 9 deletions(-) rename source/src/BNFC/Backend/CPP/NoSTL/{CFtoCPPAbs.hs => CFtoCPPAbsAnsi.hs} (99%) rename source/src/BNFC/Backend/CPP/STL/{CFtoSTLAbs.hs => CFtoSTLAbsAnsi.hs} (96%) create mode 100644 source/src/BNFC/Backend/CPP/STL/CFtoSTLAbsBeyondAnsi.hs diff --git a/Makefile b/Makefile index f2e69ca0..714a8124 100644 --- a/Makefile +++ b/Makefile @@ -13,4 +13,6 @@ internal-tests : test : cd testing && cabal v1-install && bnfc-system-tests && cd .. +tag : + hasktags --etags ./source -o ./source/TAGS #EOF diff --git a/source/BNFC.cabal b/source/BNFC.cabal index 936d9585..a02f25dc 100644 --- a/source/BNFC.cabal +++ b/source/BNFC.cabal @@ -239,11 +239,12 @@ library BNFC.Backend.CPP.Makefile BNFC.Backend.CPP.Naming BNFC.Backend.CPP.NoSTL - BNFC.Backend.CPP.NoSTL.CFtoCPPAbs + BNFC.Backend.CPP.NoSTL.CFtoCPPAbsAnsi -- C++ STL backend BNFC.Backend.CPP.STL - BNFC.Backend.CPP.STL.CFtoSTLAbs + BNFC.Backend.CPP.STL.CFtoSTLAbsAnsi + BNFC.Backend.CPP.STL.CFtoSTLAbsBeyondAnsi BNFC.Backend.CPP.STL.STLUtils BNFC.Backend.CPP.STL.CFtoCVisitSkelSTL diff --git a/source/src/BNFC/Backend/CPP/NoSTL.hs b/source/src/BNFC/Backend/CPP/NoSTL.hs index ba093acd..3efdeac6 100644 --- a/source/src/BNFC/Backend/CPP/NoSTL.hs +++ b/source/src/BNFC/Backend/CPP/NoSTL.hs @@ -16,7 +16,7 @@ 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.NoSTL.CFtoCPPAbs +import BNFC.Backend.CPP.NoSTL.CFtoCPPAbsAnsi import BNFC.Backend.CPP.STL.CFtoCVisitSkelSTL import BNFC.Backend.CPP.PrettyPrinter import qualified BNFC.Backend.Common.Makefile as Makefile diff --git a/source/src/BNFC/Backend/CPP/NoSTL/CFtoCPPAbs.hs b/source/src/BNFC/Backend/CPP/NoSTL/CFtoCPPAbsAnsi.hs similarity index 99% rename from source/src/BNFC/Backend/CPP/NoSTL/CFtoCPPAbs.hs rename to source/src/BNFC/Backend/CPP/NoSTL/CFtoCPPAbsAnsi.hs index c3a31134..e32992f9 100644 --- a/source/src/BNFC/Backend/CPP/NoSTL/CFtoCPPAbs.hs +++ b/source/src/BNFC/Backend/CPP/NoSTL/CFtoCPPAbsAnsi.hs @@ -16,7 +16,7 @@ Modified : 22 May, 2004 / Antti-Juhani Kaijanaho -} -module BNFC.Backend.CPP.NoSTL.CFtoCPPAbs (cf2CPPAbs) where +module BNFC.Backend.CPP.NoSTL.CFtoCPPAbsAnsi (cf2CPPAbs) where import Prelude hiding ((<>)) diff --git a/source/src/BNFC/Backend/CPP/STL.hs b/source/src/BNFC/Backend/CPP/STL.hs index 149be600..ad2622a0 100644 --- a/source/src/BNFC/Backend/CPP/STL.hs +++ b/source/src/BNFC/Backend/CPP/STL.hs @@ -20,7 +20,8 @@ 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.CFtoSTLAbsAnsi +import BNFC.Backend.CPP.STL.CFtoSTLAbsBeyondAnsi import BNFC.Backend.CPP.STL.CFtoCVisitSkelSTL import BNFC.Backend.CPP.PrettyPrinter import BNFC.Backend.CPP.STL.STLUtils @@ -56,11 +57,17 @@ makeCppStl opts cf = do prefix :: String prefix = snakeCase_ name ++ "_" compileOpt :: String - compileOpt = "--ansi" + -- Compile option used by Makefile + compileOpt = if Ansi == ansi opts then "--ansi" else "-std=c++14" parserMode :: ParserMode parserMode = CppParser (inPackage opts) prefix mkCppFile x = mkfile x comment mkCppFileWithHint x = mkfile x commentWithEmacsModeHint + -- Switch C++ generator module + cf2CPPAbs = if Ansi == ansi opts then + cf2CPPAbsAnsi + else + cf2CPPAbsBeyondAnsi printParseErrHeader :: Maybe String -> String printParseErrHeader inPackage = diff --git a/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs b/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbsAnsi.hs similarity index 96% rename from source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs rename to source/src/BNFC/Backend/CPP/STL/CFtoSTLAbsAnsi.hs index 6d2bf314..4fbf7395 100644 --- a/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs +++ b/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbsAnsi.hs @@ -16,7 +16,7 @@ -} -module BNFC.Backend.CPP.STL.CFtoSTLAbs (cf2CPPAbs) where +module BNFC.Backend.CPP.STL.CFtoSTLAbsAnsi (cf2CPPAbsAnsi) where import Data.List ( intercalate, intersperse ) @@ -31,8 +31,8 @@ import BNFC.Backend.CPP.STL.STLUtils --The result is two files (.H file, .C file) -cf2CPPAbs :: RecordPositions -> Maybe String -> String -> CF -> (String, String) -cf2CPPAbs rp inPackage _ cf = (mkHFile rp inPackage cab cf, mkCFile inPackage cab cf) +cf2CPPAbsAnsi :: RecordPositions -> Maybe String -> String -> CF -> (String, String) +cf2CPPAbsAnsi rp inPackage _ cf = (mkHFile rp inPackage cab cf, mkCFile inPackage cab cf) where cab = cf2cabs cf diff --git a/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbsBeyondAnsi.hs b/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbsBeyondAnsi.hs new file mode 100644 index 00000000..c39f413c --- /dev/null +++ b/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbsBeyondAnsi.hs @@ -0,0 +1,290 @@ +{-# LANGUAGE TupleSections #-} + +{- + BNF Converter: C++ abstract syntax generator + Copyright (C) 2004 Author: Michael Pellauer + + Description : This module generates the C++ Abstract Syntax + tree classes. It generates both a Header file + and an Implementation file, and uses the Visitor + design pattern. It uses STL (Standard Template Library). + This module use new C++ feature (after -std=c++14) + + Author : Michael Pellauer + Created : 4 August, 2003 + Modified : 22 May, 2004 / Antti-Juhani Kaijanaho + 29 August, 2006 / Aarne Ranta + 17 October, 2021 / Hiroyuki Nagata + +-} + +module BNFC.Backend.CPP.STL.CFtoSTLAbsBeyondAnsi (cf2CPPAbsBeyondAnsi) where + +import Data.List ( intercalate, intersperse, isPrefixOf ) + +import BNFC.Backend.Common.OOAbstract +import BNFC.CF +import BNFC.Options ( RecordPositions(..) ) +import BNFC.TypeChecker ( ListConstructors(..) ) +import BNFC.Utils ( (+++), applyWhen ) + +import BNFC.Backend.CPP.Common +import BNFC.Backend.CPP.STL.STLUtils + +--The result is two files (.H file, .C file) + +cf2CPPAbsBeyondAnsi :: RecordPositions -> Maybe String -> String -> CF -> (String, String) +cf2CPPAbsBeyondAnsi rp inPackage _ cf = (mkHFile rp inPackage cab cf, mkCFile inPackage cab cf) + where + cab = cf2cabs cf + + +-- **** Header (.H) File Functions **** -- + +--Makes the Header file. +mkHFile :: RecordPositions -> Maybe String -> CAbs -> CF -> String +mkHFile rp inPackage cabs cf = unlines + [ + "#ifndef " ++ hdef, + "#define " ++ hdef, + "", + "#include ", + "#include ", + "#include ", + "#include ", + "", + "//C++ Abstract Syntax Interface.", + nsStart inPackage, + "/******************** Type Alias Section ********************/", + "", + -- using {newtype} = {oldtype}; + unlines ["using " ++ c ++ " = " ++ d ++ ";" | (c,d) <- basetypes], + "", + unlines ["using " ++ s ++ " = std::string;" | s <- tokentypes cabs], + "", + "/******************** Forward Declarations ********************/", + "", + unlines ["class " ++ c ++ ";" | c <- classes, notElem c (defineds cabs), not $ isPrefixOf "List" c ], + -- using NewType = std::vector>; + unlines ["using " ++ l ++ " = std::vector>;" | l <- classes, notElem l (defineds cabs), isPrefixOf "List" l ], + "", + "/******************** Visitor Interfaces ********************/", + prVisitor cabs, + "", + prVisitable, + "", + "/******************** Abstract Syntax Classes ********************/", + "", + unlines [prAbs rp c | c <- absclasses cabs], + "", + unlines [prCon (c,r) | (c,rs) <- signatures cabs, r <- rs], + "", + unlines [prList c | c <- listtypes cabs], + "", + definedRules Nothing cf + "/******************** Defined Constructors ********************/", + nsEnd inPackage, + "#endif" + ] + where + classes = allClasses cabs + hdef = nsDefine inPackage "ABSYN_HEADER" + +-- auxiliaries + +prVisitable :: String +prVisitable = unlines [ + "class Visitable", + "{", + " public:", + -- all classes with virtual methods require a virtual destructor + " virtual ~Visitable() {}", + " virtual void accept(Visitor *v) = 0;", + "};" + ] + +prVisitor :: CAbs -> String +prVisitor cf = unlines [ + "class Visitor", + "{", + "public:", + " virtual ~Visitor() {}", + unlines + [" virtual void visit"++c++"("++c++" *p) = 0;" | c <- allClasses cf, + notElem c (defineds cf)], + "", + unlines + [" virtual void visit"++c++"(" ++c++" x) = 0;" | c <- allNonClasses cf], + "};" + ] + +prAbs :: RecordPositions -> String -> String +prAbs rp c = unlines [ + "class " ++ c ++ " : public Visitable", + "{", + "public:", + " virtual std::unique_ptr<" ++ c ++ "> clone() const = 0;", + if rp == RecordPositions then " int line_number, char_number;" else "", + "};" + ] + +prCon :: (String, CAbsRule) -> String +prCon (c,(f,cs)) = unlines [ + "class " ++f++ " : public " ++ c, + "{", + "public:", + unlines + [" std::unique_ptr<" ++ typ ++ "> " ++ var ++ ";" | (typ,_,var) <- cs], + "", + " " ++ f ++ "(" ++ f ++ " &&);", + " " ++ f ++ "(const " ++ f ++ " &);", + " " ++ f ++ " &operator=(const " ++f++ " &&);", + " " ++ f ++ "(" ++ conargs ++ ");", + " ~" ++f ++ "();", + " virtual void accept(Visitor *v);", + " std::unique_ptr<" ++c++ "> clone() const override;", + "};" + ] + where + conargs = concat $ intersperse ", " + ["std::unique_ptr<" ++ x ++ "> p" ++ show i | ((x,_,_),i) <- zip cs [1..]] + +prList :: (String, Bool) -> String +prList (c, b) = unlines + [ "//class " ++c++ " : public Visitable, public std::vector>" + , "//{" + , "//public:" + , "// virtual void accept(Visitor *v);" + , "//virtual " ++ c ++ " *clone() const;" + , "//};" + , "" + -- cons for this list type + , concat [ "// std::vector> ", "cons", c, "(std::unique_ptr<", bas, "> x, std::vector> xs);" ] + ] + where + bas = applyWhen b (++ "") $ drop 4 c {- drop "List" -} + + +-- **** Implementation (.C) File Functions **** -- + +mkCFile :: Maybe String -> CAbs -> CF -> String +mkCFile inPackage cabs cf = unlines $ [ + "//C++ Abstract Syntax Implementation.", + "#include ", + "#include ", + "#include ", + "#include \"Absyn.H\"", + nsStart inPackage, + unlines [prConC c r | (c,rs) <- signatures cabs, r <- rs], + unlines [prListC l | l <- listtypes cabs], + definedRules (Just $ LC nil cons) cf + "/******************** Defined Constructors ********************/", + nsEnd inPackage + ] + where + nil t = (,dummyType) $ concat [ "new List", identType t, "()" ] + cons t = (,dummyType) $ concat [ "consList", identType t ] + + +prConC :: String -> CAbsRule -> String +prConC c fcs@(f,_) = unlines [ + "/******************** " ++ f ++ " ********************/", + prConstructorC fcs, + prCopyC fcs, + prDestructorC fcs, + prAcceptC f, + prCloneC c f, + "" + ] + +prListC :: (String,Bool) -> String +prListC (c,b) = unlines + [ "/******************** " ++ c ++ " ********************/" + , "" + --, prAcceptC c + -- , prCloneC c + --, prConsC c b + ] + + +--The standard accept function for the Visitor pattern +prAcceptC :: String -> String +prAcceptC ty = unlines [ + "void " ++ ty ++ "::accept(Visitor *v)", + "{", + " v->visit" ++ ty ++ "(this);", + "}" + ] + +--The cloner makes a new deep copy of the object +prCloneC :: String -> String -> String +prCloneC f c = unlines [ + "std::unique_ptr<" ++ f ++ "> " ++ c ++ "::clone() const ", + "{", + " return std::make_unique<" ++ c ++ ">(*this);", + "}" + ] + +-- | Make a list constructor definition. +prConsC :: String -> Bool -> String +prConsC c b = unlines + [ concat [ c, "* ", "cons", c, "(", bas, " x, ", c, "* xs) {" ] + , " xs->insert(xs->begin(), x);" + , " return xs;" + , "}" + ] + where + bas = applyWhen b (++ "*") $ drop 4 c {- drop "List" -} + +--The constructor assigns the parameters to the corresponding instance variables. +prConstructorC :: CAbsRule -> String +prConstructorC (f,cs) = unlines [ + f ++ "::" ++ f ++ "(" ++ conargs ++ ")", + "{", + unlines [" " ++ c ++ " = std::move(" ++ p ++ ");" | (c,p) <- zip cvs pvs], + "}" + ] + where + cvs = [c | (_,_,c) <- cs] + pvs = ['p' : show i | ((_,_,_),i) <- zip cs [1..]] + conargs = intercalate ", " + ["std::unique_ptr<" ++ x ++ ">" +++ v | ((x,_,_),v) <- zip cs pvs] + + +--Copy constructor and copy assignment +prCopyC :: CAbsRule -> String +prCopyC (c,cs) = unlines [ + -- Prog::Prog(const Prog & other) {} + c ++ "::" ++ c ++ "(const" +++ c +++ "& other)", + "{", + -- unlines [" " ++ cv ++ " = std::move(other." ++ cv ++ ");" | (x,_,cv) <- cs], + " *this = std::move(other);", + "}", + "", + -- Prog::Prog(Prog && other) {} + c ++ "::" ++ c ++ "(" ++ c +++ "&& other)", + "{", + unlines [" " ++ cv ++ " = std::move(other." ++ cv ++ ");" | (x,_,cv) <- cs], + "}", + "", + -- Prog &Prog::operator=(const Prog && other) + c +++ "&" ++ c ++ "::" ++ "operator=(const" +++ c +++ "&& other)", + "{", + unlines [" //" ++ cv ++ "->reserve(other." ++ cv ++ "->size());" | (x,_,cv) <- cs], + unlines [" //for (auto const& e : *other." ++ cv ++ ") {" | (x,_,cv) <- cs], + unlines [" // " ++ cv ++ "->push_back(e->clone());" | (x,_,cv) <- cs], + -- unlines [" " ++ cv ++ " = std::move(other." ++ cv ++ ");" | (x,_,cv) <- cs], + " return *this;", + "}" + ] + where + cloneIf st cv = if st then (cv ++ "->clone()") else cv + +--The destructor defined but no operation +prDestructorC :: CAbsRule -> String +prDestructorC (c, _) = unlines [ + c ++ "::~" ++ c ++"()", + "{", + " // NOP", + "}" + ] From dce48458b488db0dd5f6d01577200ec9d50ac92c Mon Sep 17 00:00:00 2001 From: "hiroyuki.nagata" Date: Fri, 22 Oct 2021 21:42:19 +0900 Subject: [PATCH 3/9] Refactor CFtoCPPAbs.hs, CFtoBisonC, CFtoFlexC, Makefile.hs * refacotor prList, prListC --- Makefile | 2 +- source/BNFC.cabal | 5 +- source/src/BNFC/Backend/C/CFtoBisonC.hs | 15 +- source/src/BNFC/Backend/C/CFtoFlexC.hs | 38 +- source/src/BNFC/Backend/CPP/Makefile.hs | 16 +- source/src/BNFC/Backend/CPP/NoSTL.hs | 4 +- .../{CFtoCPPAbsAnsi.hs => CFtoCPPAbs.hs} | 4 +- source/src/BNFC/Backend/CPP/STL.hs | 29 +- source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs | 457 ++++++++++++++++++ .../BNFC/Backend/CPP/STL/CFtoSTLAbsAnsi.hs | 278 ----------- .../Backend/CPP/STL/CFtoSTLAbsBeyondAnsi.hs | 290 ----------- 11 files changed, 527 insertions(+), 611 deletions(-) rename source/src/BNFC/Backend/CPP/NoSTL/{CFtoCPPAbsAnsi.hs => CFtoCPPAbs.hs} (99%) create mode 100644 source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs delete mode 100644 source/src/BNFC/Backend/CPP/STL/CFtoSTLAbsAnsi.hs delete mode 100644 source/src/BNFC/Backend/CPP/STL/CFtoSTLAbsBeyondAnsi.hs diff --git a/Makefile b/Makefile index 714a8124..e0f48ad3 100644 --- a/Makefile +++ b/Makefile @@ -14,5 +14,5 @@ test : cd testing && cabal v1-install && bnfc-system-tests && cd .. tag : - hasktags --etags ./source -o ./source/TAGS + cd ./source && hasktags --etags . #EOF diff --git a/source/BNFC.cabal b/source/BNFC.cabal index a02f25dc..936d9585 100644 --- a/source/BNFC.cabal +++ b/source/BNFC.cabal @@ -239,12 +239,11 @@ library BNFC.Backend.CPP.Makefile BNFC.Backend.CPP.Naming BNFC.Backend.CPP.NoSTL - BNFC.Backend.CPP.NoSTL.CFtoCPPAbsAnsi + BNFC.Backend.CPP.NoSTL.CFtoCPPAbs -- C++ STL backend BNFC.Backend.CPP.STL - BNFC.Backend.CPP.STL.CFtoSTLAbsAnsi - BNFC.Backend.CPP.STL.CFtoSTLAbsBeyondAnsi + BNFC.Backend.CPP.STL.CFtoSTLAbs BNFC.Backend.CPP.STL.STLUtils BNFC.Backend.CPP.STL.CFtoCVisitSkelSTL diff --git a/source/src/BNFC/Backend/C/CFtoBisonC.hs b/source/src/BNFC/Backend/C/CFtoBisonC.hs index 3e6d0fb8..8d297d98 100644 --- a/source/src/BNFC/Backend/C/CFtoBisonC.hs +++ b/source/src/BNFC/Backend/C/CFtoBisonC.hs @@ -35,10 +35,10 @@ import System.FilePath ( (<.>) ) import BNFC.CF import BNFC.Backend.Common.NamedVariables hiding (varName) -import BNFC.Backend.C.CFtoFlexC (ParserMode(..), cParser, stlParser, parserHExt, parserName, parserPackage) +import BNFC.Backend.C.CFtoFlexC (ParserMode(..), cParser, reentrant, stlParser, parserHExt, parserName, parserPackage, variant, automove) import BNFC.Backend.CPP.Naming import BNFC.Backend.CPP.STL.STLUtils -import BNFC.Options (RecordPositions(..), InPackage) +import BNFC.Options (RecordPositions(..), InPackage, Ansi(..) ) import BNFC.PrettyPrint import BNFC.Utils ((+++), table, applyWhen, for, unless, when, whenJust) @@ -96,7 +96,7 @@ header mode cf = unlines $ concat ] , [ "" , "/* Reentrant parser */" - , "%pure_parser" + , reentrant mode , " /* From Bison 2.3b (2008): %define api.pure full */" -- The flag %pure_parser is deprecated with a warning since Bison 3.4, -- but older Bisons like 2.3 (2006, shipped with macOS) don't recognize @@ -110,6 +110,11 @@ header mode cf = unlines $ concat , "/* Argument to the parser to be filled with the parsed tree. */" , "%parse-param { YYSTYPE *result }" , "" + -- Use variant type if c++14 + , unlines $ (variant mode) + -- Use std::move if c++14 + , unlines $ (automove mode) + , "" , "%{" , "/* Begin C preamble code */" , "" @@ -373,7 +378,7 @@ rulesForBison rp mode cf env = map mkOne (ruleGroups cf) ++ posRules mkOne (cat,rules) = constructRule rp mode cf env rules cat posRules :: Rules posRules - | CppParser inPackage _ <- mode = for (positionCats cf) $ \ n -> (TokenCat n, + | CppParser inPackage _ _ <- mode = for (positionCats cf) $ \ n -> (TokenCat n, [( Map.findWithDefault n (Tokentype n) env , addResult cf (TokenCat n) $ concat [ "$$ = new ", nsScope inPackage, n, "($1, @$.first_line);" ] @@ -416,7 +421,7 @@ generateAction :: IsFun a -> [(MetaVar, Bool)] -- ^ Meta-vars; should the list referenced by the var be reversed? -> Action generateAction rp = \case - CppParser ns _ -> generateActionSTL rp ns + CppParser ns _ _ -> generateActionSTL rp ns CParser b _ -> \ nt f r -> generateActionC rp (not b) nt f r . map fst -- | Generates a string containing the semantic action. diff --git a/source/src/BNFC/Backend/C/CFtoFlexC.hs b/source/src/BNFC/Backend/C/CFtoFlexC.hs index c50a6252..f32e6acd 100644 --- a/source/src/BNFC/Backend/C/CFtoFlexC.hs +++ b/source/src/BNFC/Backend/C/CFtoFlexC.hs @@ -17,7 +17,7 @@ module BNFC.Backend.C.CFtoFlexC ( cf2flex - , ParserMode(..), parserName, parserPackage, cParser, stlParser, parserHExt + , ParserMode(..), parserName, parserPackage, reentrant, cParser, stlParser, parserHExt, variant, automove , preludeForBuffer -- C code defining a buffer for lexing string literals. , cMacros -- Lexer definitions. , commentStates -- Stream of names for lexer states for comments. @@ -38,38 +38,58 @@ import BNFC.CF import BNFC.Backend.C.Common ( posixC ) import BNFC.Backend.C.RegToFlex import BNFC.Backend.Common.NamedVariables -import BNFC.Options ( InPackage ) +import BNFC.Options ( InPackage, Ansi(..) ) import BNFC.PrettyPrint import BNFC.Utils ( cstring, symbolToName, unless, when ) data ParserMode - = CParser Bool String -- ^ @C@ (@False@) or @C++ no STL@ (@True@) mode, with @name@ to use as prefix. - | CppParser InPackage String -- ^ @C++@ mode, with optional package name + = CParser Bool String -- ^ @C@ (@False@) or @C++ no STL@ (@True@) mode, with @name@ to use as prefix. + | CppParser InPackage String Ansi -- ^ @C++@ mode, with optional package name, --ansi or -std=c++14 parserName :: ParserMode -> String parserName = \case CParser _ n -> n - CppParser p n -> fromMaybe n p + CppParser p n _ -> fromMaybe n p parserPackage :: ParserMode -> InPackage parserPackage = \case CParser _ _ -> Nothing - CppParser p _ -> p + CppParser p _ _ -> p + +reentrant :: ParserMode -> String +reentrant = \case + CParser _ _ -> "%pure_parser"; + CppParser _ _ ansi | ansi == BeyondAnsi -> "%define api.pure" + | otherwise -> "%pure_parser"; + +variant :: ParserMode -> [String] +variant = \case + CppParser _ _ ansi | ansi == BeyondAnsi -> [ + "/* variant based implementation of semantic values for C++ */" + ,"%define api.value.type variant"] + _ -> [] + +automove :: ParserMode -> [String] +automove = \case + CppParser _ _ ansi | ansi == BeyondAnsi -> [ + "/* every occurrence '$n' is replaced by 'std::move ($n)' */" + , "%define api.value.automove"] + _ -> [] cParser :: ParserMode -> Bool cParser = \case CParser b _ -> not b - CppParser _ _ -> False + CppParser _ _ _ -> False stlParser :: ParserMode -> Bool stlParser = \case CParser _ _ -> False - CppParser _ _ -> True + CppParser _ _ _ -> True parserHExt :: ParserMode -> String parserHExt = \case CParser b _ -> if b then "H" else "h" - CppParser _ _ -> "H" + CppParser _ _ _ -> "H" -- | Entrypoint. cf2flex :: ParserMode -> CF -> (String, SymMap) -- The environment is reused by the parser. diff --git a/source/src/BNFC/Backend/CPP/Makefile.hs b/source/src/BNFC/Backend/CPP/Makefile.hs index 933a0b60..2d3a11d2 100644 --- a/source/src/BNFC/Backend/CPP/Makefile.hs +++ b/source/src/BNFC/Backend/CPP/Makefile.hs @@ -5,8 +5,8 @@ module BNFC.Backend.CPP.Makefile (makefile) where import BNFC.Backend.Common.Makefile import BNFC.PrettyPrint -makefile :: String -> String -> String -> String -> Doc -makefile prefix name compileOpt basename = vcat +makefile :: String -> String -> String -> String -> String -> String -> Doc +makefile prefix name compileOpt lexerExt parserExt basename = vcat [ mkVar "CC" "g++ -g" , mkVar "CCFLAGS" (compileOpt ++ " -W -Wall -Wno-unused-parameter -Wno-unused-function -Wno-unneeded-internal-declaration") , "" @@ -31,8 +31,8 @@ makefile prefix name compileOpt basename = vcat [ "Absyn.C", "Absyn.H" , "Buffer.C", "Buffer.H" , "Test.C" - , "Bison.H", "Parser.C", "Parser.H", "ParserError.H", name ++ ".y" - , "Lexer.C", name ++ ".l" + , "Bison.H", "Parser.C", "Parser.H", "ParserError.H", name ++ parserExt + , "Lexer.C", name ++ lexerExt , "Skeleton.C", "Skeleton.H" , "Printer.C", "Printer.H" , basename @@ -46,10 +46,10 @@ makefile prefix name compileOpt basename = vcat [ "${CC} ${CCFLAGS} -c Absyn.C" ] , mkRule "Buffer.o" [ "Buffer.C", "Buffer.H" ] [ "${CC} ${CCFLAGS} -c Buffer.C " ] - , mkRule "Lexer.C" [ name ++ ".l" ] - [ "${FLEX} ${FLEX_OPTS} -oLexer.C " ++ name ++ ".l" ] - , mkRule "Parser.C Bison.H" [ name ++ ".y" ] - [ "${BISON} ${BISON_OPTS} " ++ name ++ ".y -o Parser.C" ] + , mkRule "Lexer.C" [ name ++ lexerExt ] + [ "${FLEX} ${FLEX_OPTS} -oLexer.C " ++ name ++ lexerExt ] + , mkRule "Parser.C Bison.H" [ name ++ parserExt ] + [ "${BISON} ${BISON_OPTS} " ++ name ++ parserExt ++ " -o Parser.C" ] , mkRule "Lexer.o" [ "CCFLAGS+=-Wno-sign-conversion" ] , mkRule "Lexer.o" [ "Lexer.C", "Bison.H" ] [ "${CC} ${CCFLAGS} -c Lexer.C " ] diff --git a/source/src/BNFC/Backend/CPP/NoSTL.hs b/source/src/BNFC/Backend/CPP/NoSTL.hs index 3efdeac6..3fa88461 100644 --- a/source/src/BNFC/Backend/CPP/NoSTL.hs +++ b/source/src/BNFC/Backend/CPP/NoSTL.hs @@ -16,7 +16,7 @@ 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.NoSTL.CFtoCPPAbsAnsi +import BNFC.Backend.CPP.NoSTL.CFtoCPPAbs import BNFC.Backend.CPP.STL.CFtoCVisitSkelSTL import BNFC.Backend.CPP.PrettyPrinter import qualified BNFC.Backend.Common.Makefile as Makefile @@ -40,7 +40,7 @@ makeCppNoStl opts cf = do mkCppFile "Printer.H" prinH mkCppFile "Printer.C" prinC mkCppFile "Test.C" (cpptest cf) - Makefile.mkMakefile opts $ makefile prefix name compileOpt + Makefile.mkMakefile opts $ makefile prefix name compileOpt ".l" ".y" where name :: String name = lang opts diff --git a/source/src/BNFC/Backend/CPP/NoSTL/CFtoCPPAbsAnsi.hs b/source/src/BNFC/Backend/CPP/NoSTL/CFtoCPPAbs.hs similarity index 99% rename from source/src/BNFC/Backend/CPP/NoSTL/CFtoCPPAbsAnsi.hs rename to source/src/BNFC/Backend/CPP/NoSTL/CFtoCPPAbs.hs index e32992f9..f8f6d598 100644 --- a/source/src/BNFC/Backend/CPP/NoSTL/CFtoCPPAbsAnsi.hs +++ b/source/src/BNFC/Backend/CPP/NoSTL/CFtoCPPAbs.hs @@ -16,7 +16,7 @@ Modified : 22 May, 2004 / Antti-Juhani Kaijanaho -} -module BNFC.Backend.CPP.NoSTL.CFtoCPPAbsAnsi (cf2CPPAbs) where +module BNFC.Backend.CPP.NoSTL.CFtoCPPAbs (cf2CPPAbs) where import Prelude hiding ((<>)) @@ -32,12 +32,10 @@ import BNFC.Backend.Common.NamedVariables import BNFC.Backend.Common.OOAbstract import BNFC.Backend.CPP.Common - --The result is two files (.H file, .C file) cf2CPPAbs :: String -> CF -> (String, String) cf2CPPAbs _ cf = (mkHFile cf, mkCFile cf) - {- **** Header (.H) File Functions **** -} --Makes the Header file. diff --git a/source/src/BNFC/Backend/CPP/STL.hs b/source/src/BNFC/Backend/CPP/STL.hs index ad2622a0..22acac8d 100644 --- a/source/src/BNFC/Backend/CPP/STL.hs +++ b/source/src/BNFC/Backend/CPP/STL.hs @@ -20,8 +20,7 @@ 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.CFtoSTLAbsAnsi -import BNFC.Backend.CPP.STL.CFtoSTLAbsBeyondAnsi +import BNFC.Backend.CPP.STL.CFtoSTLAbs import BNFC.Backend.CPP.STL.CFtoCVisitSkelSTL import BNFC.Backend.CPP.PrettyPrinter import BNFC.Backend.CPP.STL.STLUtils @@ -29,14 +28,14 @@ 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 + let (hfile, cfile) = cf2CPPAbs (linenumbers opts) cppStdMode (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 + mkCppFileWithHint (name ++ lexerExt) flex + mkCppFileWithHint (name ++ parserExt) $ cf2Bison (linenumbers opts) parserMode cf env mkCppFile "Parser.H" $ mkHeaderFile (inPackage opts) (toList $ allEntryPoints cf) mkCppFile "ParserError.H" $ printParseErrHeader (inPackage opts) @@ -47,7 +46,7 @@ makeCppStl opts cf = do mkCppFile "Printer.H" prinH mkCppFile "Printer.C" prinC mkCppFile "Test.C" (cpptest (inPackage opts) cf) - Makefile.mkMakefile opts $ makefile prefix name compileOpt + Makefile.mkMakefile opts $ makefile prefix name compileOpt lexerExt parserExt where name :: String name = lang opts @@ -56,18 +55,24 @@ makeCppStl opts cf = do -- It should be a valid C identifier. prefix :: String prefix = snakeCase_ name ++ "_" - compileOpt :: String -- Compile option used by Makefile + compileOpt :: String compileOpt = if Ansi == ansi opts then "--ansi" else "-std=c++14" + lexerExt :: String + lexerExt = if Ansi == ansi opts then ".l" else ".ll" + parserExt :: String + parserExt = if Ansi == ansi opts then ".y" else ".yy" + parserMode :: ParserMode - parserMode = CppParser (inPackage opts) prefix + parserMode = CppParser (inPackage opts) prefix (ansi opts) mkCppFile x = mkfile x comment mkCppFileWithHint x = mkfile x commentWithEmacsModeHint -- Switch C++ generator module - cf2CPPAbs = if Ansi == ansi opts then - cf2CPPAbsAnsi - else - cf2CPPAbsBeyondAnsi + cppStdMode :: CppStdMode + cppStdMode = if Ansi == ansi opts then + CppStdAnsi (ansi opts) + else + CppStdBeyondAnsi (ansi opts) printParseErrHeader :: Maybe String -> String printParseErrHeader inPackage = diff --git a/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs b/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs new file mode 100644 index 00000000..9c2b35db --- /dev/null +++ b/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs @@ -0,0 +1,457 @@ +{-# LANGUAGE TupleSections #-} + +{- + BNF Converter: C++ abstract syntax generator + Copyright (C) 2004 Author: Michael Pellauer + + Description : This module generates the C++ Abstract Syntax + tree classes. It generates both a Header file + and an Implementation file, and uses the Visitor + design pattern. It uses STL (Standard Template Library). + + Author : Michael Pellauer + Created : 4 August, 2003 + Modified : 22 May, 2004 / Antti-Juhani Kaijanaho + 29 August, 2006 / Aarne Ranta + 22 October, 2021 / Hiroyuki Nagata + +-} + +module BNFC.Backend.CPP.STL.CFtoSTLAbs ( cf2CPPAbs, CppStdMode(..) ) where + +import Data.List ( intercalate, intersperse ) +import Data.Char ( toLower ) + +import BNFC.Backend.Common.OOAbstract +import BNFC.CF +import BNFC.Options ( RecordPositions(..), Ansi(..) ) +import BNFC.TypeChecker ( ListConstructors(..) ) +import BNFC.Utils ( (+++), applyWhen ) + +import BNFC.Backend.CPP.Common +import BNFC.Backend.CPP.STL.STLUtils + +data CppStdMode + = CppStdAnsi Ansi -- ^ @Ansi@ mode. + | CppStdBeyondAnsi Ansi -- ^ @BeyondAnsi@ mode. + +--The result is two files (.H file, .C file) + +cf2CPPAbs :: RecordPositions -> CppStdMode -> Maybe String -> String -> CF -> (String, String) +cf2CPPAbs rp mode inPackage _ cf = (mkHFile rp mode inPackage cab cf, mkCFile mode inPackage cab cf) + where + cab = cf2cabs cf + + +-- **** Header (.H) File Functions **** -- + +--Makes the Header file. +mkHFile :: RecordPositions -> CppStdMode -> Maybe String -> CAbs -> CF -> String +mkHFile rp mode inPackage cabs cf = unlines + [ + "#ifndef " ++ hdef, + "#define " ++ hdef, + "", + case mode of { + CppStdAnsi _ -> unlines [ + "#include ", + "#include ", + "#include "]; + CppStdBeyondAnsi _ -> unlines [ + "#include ", + "#include ", + "#include ", + "#include "]; + }, + "//C++ Abstract Syntax Interface.", + nsStart inPackage, + "/******************** TypeDef Section ********************/", + "", + case mode of { + CppStdAnsi _ -> unlines $ + ["typedef " ++ d ++ " " ++ c ++ ";" | (c,d) <- basetypes] + ++ [" "] + ++ ["typedef std::string " ++ s ++ ";" | s <- tokentypes cabs] + ++ [" "]; + ; + -- use "using" statement + CppStdBeyondAnsi _ -> unlines $ + ["using " ++ c ++ " = " ++ d ++ ";" | (c,d) <- basetypes] + ++ [""] + ++ ["using " ++ s ++ " = std::string;" | s <- tokentypes cabs] + ++ [""]; + }, + "/******************** Forward Declarations ********************/", + "", + case mode of { + CppStdAnsi _ -> unlines $ + ["class " ++ c ++ ";" | c <- classes, notElem c (defineds cabs)] + ; + CppStdBeyondAnsi _ -> unlines $ + ["class " ++ c ++ ";" | c <- classes, notElem c (defineds cabs)] + ; + }, + "", + "/******************** Visitor Interfaces ********************/", + prVisitor cabs, + "", + prVisitable, + "", + "/******************** Abstract Syntax Classes ********************/", + "", + unlines [prAbs mode rp c | c <- absclasses cabs], + "", + unlines [prCon mode (c,r) | (c,rs) <- signatures cabs, r <- rs], + "", + unlines [prList mode c | c <- listtypes cabs], + "", + definedRules Nothing cf + "/******************** Defined Constructors ********************/", + nsEnd inPackage, + "#endif" + ] + where + classes = allClasses cabs + hdef = nsDefine inPackage "ABSYN_HEADER" + +-- auxiliaries + +prVisitable :: String +prVisitable = unlines [ + "class Visitable", + "{", + " public:", + -- all classes with virtual methods require a virtual destructor + " virtual ~Visitable() {}", + " virtual void accept(Visitor *v) = 0;", + "};" + ] + +prVisitor :: CAbs -> String +prVisitor cf = unlines [ + "class Visitor", + "{", + "public:", + " virtual ~Visitor() {}", + unlines + [" virtual void visit"++c++"("++c++" *p) = 0;" | c <- allClasses cf, + notElem c (defineds cf)], + "", + unlines + [" virtual void visit"++c++"(" ++c++" x) = 0;" | c <- allNonClasses cf], + "};" + ] + +prAbs :: CppStdMode -> RecordPositions -> String -> String +prAbs mode rp c = + case mode of { + CppStdAnsi _ -> unlines [ + "class " ++ c ++ " : public Visitable", + "{", + "public:", + " virtual " ++ c ++ " *clone() const = 0;", + if rp == RecordPositions then " int line_number, char_number;" else "", + "};" + ]; + CppStdBeyondAnsi _ -> unlines [ + "class " ++ c ++ " : public Visitable", + "{", + "public:", + " virtual std::unique_ptr<" ++ c ++ "> clone() const = 0;", + if rp == RecordPositions then " int line_number, char_number;" else "", + "};" + ]; + } + +prCon :: CppStdMode -> (String, CAbsRule) -> String +prCon mode (c,(f,cs)) = + case mode of { + CppStdAnsi _ -> unlines [ + "class " ++f++ " : public " ++ c, + "{", + "public:", + unlines + [" "++ typ +++ pointerIf st var ++ ";" | (typ,st,var) <- cs], + " " ++ f ++ "(const " ++ f ++ " &);", + " " ++ f ++ " &operator=(const " ++f++ " &);", + " " ++ f ++ "(" ++ conargs ++ ");", + -- Typ *p1, PIdent *p2, ListStm *p3); + " ~" ++f ++ "();", + " virtual void accept(Visitor *v);", + " virtual " ++f++ " *clone() const;", + " void swap(" ++f++ " &);", + "};" + ]; + CppStdBeyondAnsi _ -> unlines [ + "class " ++f++ " : public " ++ c, + "{", + "private:", + unlines [" std::unique_ptr<" ++ typ ++ "> " ++ var ++ ";" | (typ,_,var) <- cs], + "public:", + -- "right-hand side" operations; for move + " " ++ f ++ "(" ++ f ++ "&& rhs);", + " " ++ f ++ "& operator=(" ++ f ++ "&& rhs);", + " " ++ f ++ "(const" +++ f ++ "& rhs);", + " " ++ f ++ "& operator=(const" +++ f ++ "& rhs);", + " " ++ f ++ "(" ++ conargs ++ ");", + " ~" ++f ++ "();", + " virtual void accept(Visitor *v);", + " std::unique_ptr<" ++c++ "> clone() const override;", + "};" + ]; + } + where + conargs = + case mode of { + CppStdAnsi _ -> + concat $ intersperse ", " + [x +++ pointerIf st ("p" ++ show i) | ((x,st,_),i) <- zip cs [1..]] + ; + CppStdBeyondAnsi _ -> + concat $ intersperse ", " + ["const" +++ x ++ "& p" ++ show i | ((x,_,_),i) <- zip cs [1..]] + ; + } + +prList :: CppStdMode -> (String, Bool) -> String +prList mode (c, b) = case mode of { + CppStdAnsi _ -> unlines [ + "class " ++c++ " : public Visitable, public std::vector<" ++bas++ ">" + , "{" + , "public:" + , " virtual void accept(Visitor *v);" + , " virtual " ++ c ++ " *clone() const;" + , "};" + , "" + -- cons for this list type + , concat [ c, "* ", "cons", c, "(", bas, " x, ", c, "* xs);" ] + ]; + CppStdBeyondAnsi _ -> unlines [ + "class " ++c++ " : public Visitable" + , "{" + , "public:" + , " std::vector>" +++ "list" ++ map toLower childClass ++ "_;" + , "" + -- "right-hand side" operations; for move + , " " ++ c ++ "(" ++ c ++ "&& rhs);" + , " " ++ c ++ "& operator=(" ++ c ++ "&& rhs);" + , " " ++ c ++ "(const" +++ c ++ "& rhs);" + , " " ++ c ++ "& operator=(const" +++ c ++ "& rhs);" + , " ~" ++ c ++ "();" + , " virtual void accept(Visitor *v);" + , " std::unique_ptr<" ++ c ++ "> clone() const;" + , "};" + , "" + ]; + } + where + childClass = drop 4 c + bas = applyWhen b (++ "*") $ drop 4 c {- drop "List" -} + + +-- **** Implementation (.C) File Functions **** -- + +mkCFile :: CppStdMode -> Maybe String -> CAbs -> CF -> String +mkCFile mode inPackage cabs cf = unlines $ [ + "//C++ Abstract Syntax Implementation.", + "#include ", + "#include ", + "#include ", + "#include \"Absyn.H\"", + nsStart inPackage, + unlines [prConC mode c r | (c,rs) <- signatures cabs, r <- rs], + unlines [prListC mode l | l <- listtypes cabs], + definedRules (Just $ LC nil cons) cf + "/******************** Defined Constructors ********************/", + nsEnd inPackage + ] + where + nil t = (,dummyType) $ concat [ "new List", identType t, "()" ] + cons t = (,dummyType) $ concat [ "consList", identType t ] + + +prConC :: CppStdMode -> String -> CAbsRule -> String +prConC mode c fcs@(f,_) = unlines [ + "/******************** " ++ f ++ " ********************/", + prConstructorC mode fcs, + prCopyC mode fcs, + prDestructorC mode fcs, + prAcceptC f, + prCloneC mode c f, + "" + ] + +prListC :: CppStdMode -> (String,Bool) -> String +prListC mode (c,b) = unlines + [ "/******************** " ++ c ++ " ********************/" + , case mode of { + CppStdBeyondAnsi _ -> unlines [ + c ++ "::" ++ c ++ "(" ++ c ++ "&& rhs) = default;", + "", + c ++ "&" +++ c ++ "::operator=(" ++ c ++ "&& rhs) = default;", + "", + c ++ "::" ++ c ++ "(const" +++ c ++ "& rhs)", + "{", + " for (const auto& e : rhs." ++inner++ ")", + " {", + " " ++inner++".push_back(e->clone());", + " }", + "}", + "", + c ++ "&" +++ c ++ "::operator=(const" +++ c ++ "& rhs)", + "{", + " for (const auto& e : rhs." ++inner++ ")", + " {", + " " ++inner++".push_back(e->clone());", + " }", + " return *this;", + "}", + "", + c ++ "::~" ++ c ++"() = default;", + ""]; + } + , prAcceptC c + , prCloneC mode c c + , prConsC mode c b + ] + where + inner = map toLower c ++ "_" + + +--The standard accept function for the Visitor pattern +prAcceptC :: String -> String +prAcceptC ty = unlines [ + "void " ++ ty ++ "::accept(Visitor *v)", + "{", + " v->visit" ++ ty ++ "(this);", + "}" + ] + +--The cloner makes a new deep copy of the object +prCloneC :: CppStdMode -> String -> String -> String +prCloneC mode f c = case mode of { + CppStdAnsi _ -> unlines [ + c +++ "*" ++ c ++ "::clone() const", + "{", + " return new" +++ c ++ "(*this);", + "}" + ]; + CppStdBeyondAnsi _ -> unlines [ + "std::unique_ptr<" ++ f ++ "> " ++ c ++ "::clone() const ", + "{", + " return std::make_unique<" ++ c ++ ">(*this);", + "}" + ]; + } + +-- | Make a list constructor definition. +prConsC :: CppStdMode -> String -> Bool -> String +prConsC mode c b = case mode of { + CppStdAnsi _ -> unlines [ + concat [ c, "* ", "cons", c, "(", bas, " x, ", c, "* xs) {" ] + , " xs->insert(xs->begin(), x);" + , " return xs;" + , "}" + ]; + CppStdBeyondAnsi _ -> unlines [ + concat [ "std::unique_ptr<", c, "> ", "cons", c, "(std::unique_ptr<", bas, "> x, std::unique_ptr<", c, "> xs) {" ] + , " xs->" ++inner++ ".insert(xs->" ++inner++ ".begin(), std::move(x));" + , " return xs;" + , "}" + ]; + } + where + bas = case mode of { + CppStdAnsi _ -> applyWhen b (++ "*") $ drop 4 c {- drop "List" -}; + CppStdBeyondAnsi _ -> drop 4 c; + } + inner = map toLower c ++ "_" + +--The constructor assigns the parameters to the corresponding instance variables. +prConstructorC :: CppStdMode -> CAbsRule -> String +prConstructorC mode (f,cs) = case mode of { + CppStdAnsi _ -> unlines [ + f ++ "::" ++ f ++ "(" ++ conargs ++ ")", + "{", + unlines [" " ++ c ++ " = " ++ p ++ ";" | (c,p) <- zip cvs pvs], + "}" + ]; + CppStdBeyondAnsi _ -> unlines [ + f ++ "::" ++ f ++ "(" ++ conargs ++ ")", + "{", + unlines [" *" ++ c ++ " = " ++ p ++ ";" | (c,p) <- zip cvs pvs], + "}" + ]; + } + where + cvs = [c | (_,_,c) <- cs] + pvs = ['p' : show i | ((_,_,_),i) <- zip cs [1..]] + + conargs = case mode of { + CppStdAnsi _ -> + intercalate ", " [x +++ pointerIf st v | ((x,st,_),v) <- zip cs pvs] + ; + CppStdBeyondAnsi _ -> + intercalate ", " ["const"+++ x ++ "&" +++ v | ((x,_,_),v) <- zip cs pvs] + ; + } + + +--Copy constructor and copy assignment +prCopyC :: CppStdMode -> CAbsRule -> String +prCopyC mode (c,cs) = case mode of { + CppStdAnsi _ -> unlines [ + c ++ "::" ++ c ++ "(const" +++ c +++ "& other)", + "{", + unlines [" " ++ cv ++ " = other." ++ cloneIf st cv ++ ";" | (_,st,cv) <- cs], + "}", + "", + c +++ "&" ++ c ++ "::" ++ "operator=(const" +++ c +++ "& other)", + "{", + " " ++ c +++ "tmp(other);", + " swap(tmp);", + " return *this;", + "}", + "", + "void" +++ c ++ "::swap(" ++ c +++ "& other)", + "{", + unlines [" std::swap(" ++ cv ++ ", other." ++ cv ++ ");" | (_,_,cv) <- cs], + "}" + ]; + CppStdBeyondAnsi _ -> unlines [ + -- "right-hand side" operations; for move + c ++ "::" ++ c ++ "(" ++ c ++ "&& rhs) = default;", + "", + c ++ "&" +++ c ++ "::operator=(" ++ c ++ "&& rhs) = default;", + "", + -- c ++ "::" ++ c ++ "(const" +++ c ++ "& rhs)" ++ if length cs == 0 then "" else ":", + -- intercalate ", \n" [" " ++c++ "(std::make_unique<" ++ x ++ ">(*rhs." ++ c ++ "))" | (x,_,c) <- cs], + c ++ "::" ++ c ++ "(const" +++ c ++ "& rhs)", + "{", + unlines [" *" ++ c ++ " = *rhs." ++ c ++ ";" | (x,st,c) <- cs], + "}", + "", + c ++ "&" +++ c ++ "::operator=(const" +++ c ++ "& rhs)", + "{", + unlines [" *" ++ c ++ " = *rhs." ++ c ++ ";" | (x,st,c) <- cs], + " return *this;", + "}", + "" + ]; + } + where + cloneIf st cv = if st then (cv ++ "->clone()") else cv + +--The destructor deletes all a class's members. +prDestructorC :: CppStdMode -> CAbsRule -> String +prDestructorC mode (c,cs) = case mode of { + CppStdAnsi _ -> unlines [ + c ++ "::~" ++ c ++"()", + "{", + unlines [" delete(" ++ cv ++ ");" | (_,isPointer,cv) <- cs, isPointer], + "}" + ]; + CppStdBeyondAnsi _ -> unlines [ + c ++ "::~" ++ c ++"() = default;" + ]; + } diff --git a/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbsAnsi.hs b/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbsAnsi.hs deleted file mode 100644 index 4fbf7395..00000000 --- a/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbsAnsi.hs +++ /dev/null @@ -1,278 +0,0 @@ -{-# LANGUAGE TupleSections #-} - -{- - BNF Converter: C++ abstract syntax generator - Copyright (C) 2004 Author: Michael Pellauer - - Description : This module generates the C++ Abstract Syntax - tree classes. It generates both a Header file - and an Implementation file, and uses the Visitor - design pattern. It uses STL (Standard Template Library). - - Author : Michael Pellauer - Created : 4 August, 2003 - Modified : 22 May, 2004 / Antti-Juhani Kaijanaho - 29 August, 2006 / Aarne Ranta - --} - -module BNFC.Backend.CPP.STL.CFtoSTLAbsAnsi (cf2CPPAbsAnsi) where - -import Data.List ( intercalate, intersperse ) - -import BNFC.Backend.Common.OOAbstract -import BNFC.CF -import BNFC.Options ( RecordPositions(..) ) -import BNFC.TypeChecker ( ListConstructors(..) ) -import BNFC.Utils ( (+++), applyWhen ) - -import BNFC.Backend.CPP.Common -import BNFC.Backend.CPP.STL.STLUtils - ---The result is two files (.H file, .C file) - -cf2CPPAbsAnsi :: RecordPositions -> Maybe String -> String -> CF -> (String, String) -cf2CPPAbsAnsi rp inPackage _ cf = (mkHFile rp inPackage cab cf, mkCFile inPackage cab cf) - where - cab = cf2cabs cf - - --- **** Header (.H) File Functions **** -- - ---Makes the Header file. -mkHFile :: RecordPositions -> Maybe String -> CAbs -> CF -> String -mkHFile rp inPackage cabs cf = unlines - [ - "#ifndef " ++ hdef, - "#define " ++ hdef, - "", - "#include ", - "#include ", - "#include ", - "", - "//C++ Abstract Syntax Interface.", - nsStart inPackage, - "/******************** TypeDef Section ********************/", - "", - unlines ["typedef " ++ d ++ " " ++ c ++ ";" | (c,d) <- basetypes], - "", - unlines ["typedef std::string " ++ s ++ ";" | s <- tokentypes cabs], - "", - "/******************** Forward Declarations ********************/", - "", - unlines ["class " ++ c ++ ";" | c <- classes, notElem c (defineds cabs)], - "", - "/******************** Visitor Interfaces ********************/", - prVisitor cabs, - "", - prVisitable, - "", - "/******************** Abstract Syntax Classes ********************/", - "", - unlines [prAbs rp c | c <- absclasses cabs], - "", - unlines [prCon (c,r) | (c,rs) <- signatures cabs, r <- rs], - "", - unlines [prList c | c <- listtypes cabs], - "", - definedRules Nothing cf - "/******************** Defined Constructors ********************/", - nsEnd inPackage, - "#endif" - ] - where - classes = allClasses cabs - hdef = nsDefine inPackage "ABSYN_HEADER" - --- auxiliaries - -prVisitable :: String -prVisitable = unlines [ - "class Visitable", - "{", - " public:", - -- all classes with virtual methods require a virtual destructor - " virtual ~Visitable() {}", - " virtual void accept(Visitor *v) = 0;", - "};" - ] - -prVisitor :: CAbs -> String -prVisitor cf = unlines [ - "class Visitor", - "{", - "public:", - " virtual ~Visitor() {}", - unlines - [" virtual void visit"++c++"("++c++" *p) = 0;" | c <- allClasses cf, - notElem c (defineds cf)], - "", - unlines - [" virtual void visit"++c++"(" ++c++" x) = 0;" | c <- allNonClasses cf], - "};" - ] - -prAbs :: RecordPositions -> String -> String -prAbs rp c = unlines [ - "class " ++ c ++ " : public Visitable", - "{", - "public:", - " virtual " ++ c ++ " *clone() const = 0;", - if rp == RecordPositions then " int line_number, char_number;" else "", - "};" - ] - -prCon :: (String, CAbsRule) -> String -prCon (c,(f,cs)) = unlines [ - "class " ++f++ " : public " ++ c, - "{", - "public:", - unlines - [" "++ typ +++ pointerIf st var ++ ";" | (typ,st,var) <- cs], - " " ++ f ++ "(const " ++ f ++ " &);", - " " ++ f ++ " &operator=(const " ++f++ " &);", - " " ++ f ++ "(" ++ conargs ++ ");", - -- Typ *p1, PIdent *p2, ListStm *p3); - " ~" ++f ++ "();", - " virtual void accept(Visitor *v);", - " virtual " ++f++ " *clone() const;", - " void swap(" ++f++ " &);", - "};" - ] - where - conargs = concat $ intersperse ", " - [x +++ pointerIf st ("p" ++ show i) | ((x,st,_),i) <- zip cs [1::Int ..]] - -prList :: (String, Bool) -> String -prList (c, b) = unlines - [ "class " ++c++ " : public Visitable, public std::vector<" ++bas++ ">" - , "{" - , "public:" - , " virtual void accept(Visitor *v);" - , " virtual " ++ c ++ " *clone() const;" - , "};" - , "" - -- cons for this list type - , concat [ c, "* ", "cons", c, "(", bas, " x, ", c, "* xs);" ] - ] - where - bas = applyWhen b (++ "*") $ drop 4 c {- drop "List" -} - - --- **** Implementation (.C) File Functions **** -- - -mkCFile :: Maybe String -> CAbs -> CF -> String -mkCFile inPackage cabs cf = unlines $ [ - "//C++ Abstract Syntax Implementation.", - "#include ", - "#include ", - "#include ", - "#include \"Absyn.H\"", - nsStart inPackage, - unlines [prConC r | (_,rs) <- signatures cabs, r <- rs], - unlines [prListC l | l <- listtypes cabs], - definedRules (Just $ LC nil cons) cf - "/******************** Defined Constructors ********************/", - nsEnd inPackage - ] - where - nil t = (,dummyType) $ concat [ "new List", identType t, "()" ] - cons t = (,dummyType) $ concat [ "consList", identType t ] - - -prConC :: CAbsRule -> String -prConC fcs@(f,_) = unlines [ - "/******************** " ++ f ++ " ********************/", - prConstructorC fcs, - prCopyC fcs, - prDestructorC fcs, - prAcceptC f, - prCloneC f, - "" - ] - -prListC :: (String,Bool) -> String -prListC (c,b) = unlines - [ "/******************** " ++ c ++ " ********************/" - , "" - , prAcceptC c - , prCloneC c - , prConsC c b - ] - - ---The standard accept function for the Visitor pattern -prAcceptC :: String -> String -prAcceptC ty = unlines [ - "void " ++ ty ++ "::accept(Visitor *v)", - "{", - " v->visit" ++ ty ++ "(this);", - "}" - ] - ---The cloner makes a new deep copy of the object -prCloneC :: String -> String -prCloneC c = unlines [ - c +++ "*" ++ c ++ "::clone() const", - "{", - " return new" +++ c ++ "(*this);", - "}" - ] - --- | Make a list constructor definition. -prConsC :: String -> Bool -> String -prConsC c b = unlines - [ concat [ c, "* ", "cons", c, "(", bas, " x, ", c, "* xs) {" ] - , " xs->insert(xs->begin(), x);" - , " return xs;" - , "}" - ] - where - bas = applyWhen b (++ "*") $ drop 4 c {- drop "List" -} - ---The constructor assigns the parameters to the corresponding instance variables. -prConstructorC :: CAbsRule -> String -prConstructorC (f,cs) = unlines [ - f ++ "::" ++ f ++ "(" ++ conargs ++ ")", - "{", - unlines [" " ++ c ++ " = " ++ p ++ ";" | (c,p) <- zip cvs pvs], - "}" - ] - where - cvs = [c | (_,_,c) <- cs] - pvs = ['p' : show i | ((_,_,_),i) <- zip cs [1::Int ..]] - conargs = intercalate ", " - [x +++ pointerIf st v | ((x,st,_),v) <- zip cs pvs] - - ---Copy constructor and copy assignment -prCopyC :: CAbsRule -> String -prCopyC (c,cs) = unlines [ - c ++ "::" ++ c ++ "(const" +++ c +++ "& other)", - "{", - unlines [" " ++ cv ++ " = other." ++ cloneIf st cv ++ ";" | (_,st,cv) <- cs], - "}", - "", - c +++ "&" ++ c ++ "::" ++ "operator=(const" +++ c +++ "& other)", - "{", - " " ++ c +++ "tmp(other);", - " swap(tmp);", - " return *this;", - "}", - "", - "void" +++ c ++ "::swap(" ++ c +++ "& other)", - "{", - unlines [" std::swap(" ++ cv ++ ", other." ++ cv ++ ");" | (_,_,cv) <- cs], - "}" - ] - where - cloneIf st cv = if st then (cv ++ "->clone()") else cv - ---The destructor deletes all a class's members. -prDestructorC :: CAbsRule -> String -prDestructorC (c,cs) = unlines [ - c ++ "::~" ++ c ++"()", - "{", - unlines [" delete(" ++ cv ++ ");" | (_,isPointer,cv) <- cs, isPointer], - "}" - ] diff --git a/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbsBeyondAnsi.hs b/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbsBeyondAnsi.hs deleted file mode 100644 index c39f413c..00000000 --- a/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbsBeyondAnsi.hs +++ /dev/null @@ -1,290 +0,0 @@ -{-# LANGUAGE TupleSections #-} - -{- - BNF Converter: C++ abstract syntax generator - Copyright (C) 2004 Author: Michael Pellauer - - Description : This module generates the C++ Abstract Syntax - tree classes. It generates both a Header file - and an Implementation file, and uses the Visitor - design pattern. It uses STL (Standard Template Library). - This module use new C++ feature (after -std=c++14) - - Author : Michael Pellauer - Created : 4 August, 2003 - Modified : 22 May, 2004 / Antti-Juhani Kaijanaho - 29 August, 2006 / Aarne Ranta - 17 October, 2021 / Hiroyuki Nagata - --} - -module BNFC.Backend.CPP.STL.CFtoSTLAbsBeyondAnsi (cf2CPPAbsBeyondAnsi) where - -import Data.List ( intercalate, intersperse, isPrefixOf ) - -import BNFC.Backend.Common.OOAbstract -import BNFC.CF -import BNFC.Options ( RecordPositions(..) ) -import BNFC.TypeChecker ( ListConstructors(..) ) -import BNFC.Utils ( (+++), applyWhen ) - -import BNFC.Backend.CPP.Common -import BNFC.Backend.CPP.STL.STLUtils - ---The result is two files (.H file, .C file) - -cf2CPPAbsBeyondAnsi :: RecordPositions -> Maybe String -> String -> CF -> (String, String) -cf2CPPAbsBeyondAnsi rp inPackage _ cf = (mkHFile rp inPackage cab cf, mkCFile inPackage cab cf) - where - cab = cf2cabs cf - - --- **** Header (.H) File Functions **** -- - ---Makes the Header file. -mkHFile :: RecordPositions -> Maybe String -> CAbs -> CF -> String -mkHFile rp inPackage cabs cf = unlines - [ - "#ifndef " ++ hdef, - "#define " ++ hdef, - "", - "#include ", - "#include ", - "#include ", - "#include ", - "", - "//C++ Abstract Syntax Interface.", - nsStart inPackage, - "/******************** Type Alias Section ********************/", - "", - -- using {newtype} = {oldtype}; - unlines ["using " ++ c ++ " = " ++ d ++ ";" | (c,d) <- basetypes], - "", - unlines ["using " ++ s ++ " = std::string;" | s <- tokentypes cabs], - "", - "/******************** Forward Declarations ********************/", - "", - unlines ["class " ++ c ++ ";" | c <- classes, notElem c (defineds cabs), not $ isPrefixOf "List" c ], - -- using NewType = std::vector>; - unlines ["using " ++ l ++ " = std::vector>;" | l <- classes, notElem l (defineds cabs), isPrefixOf "List" l ], - "", - "/******************** Visitor Interfaces ********************/", - prVisitor cabs, - "", - prVisitable, - "", - "/******************** Abstract Syntax Classes ********************/", - "", - unlines [prAbs rp c | c <- absclasses cabs], - "", - unlines [prCon (c,r) | (c,rs) <- signatures cabs, r <- rs], - "", - unlines [prList c | c <- listtypes cabs], - "", - definedRules Nothing cf - "/******************** Defined Constructors ********************/", - nsEnd inPackage, - "#endif" - ] - where - classes = allClasses cabs - hdef = nsDefine inPackage "ABSYN_HEADER" - --- auxiliaries - -prVisitable :: String -prVisitable = unlines [ - "class Visitable", - "{", - " public:", - -- all classes with virtual methods require a virtual destructor - " virtual ~Visitable() {}", - " virtual void accept(Visitor *v) = 0;", - "};" - ] - -prVisitor :: CAbs -> String -prVisitor cf = unlines [ - "class Visitor", - "{", - "public:", - " virtual ~Visitor() {}", - unlines - [" virtual void visit"++c++"("++c++" *p) = 0;" | c <- allClasses cf, - notElem c (defineds cf)], - "", - unlines - [" virtual void visit"++c++"(" ++c++" x) = 0;" | c <- allNonClasses cf], - "};" - ] - -prAbs :: RecordPositions -> String -> String -prAbs rp c = unlines [ - "class " ++ c ++ " : public Visitable", - "{", - "public:", - " virtual std::unique_ptr<" ++ c ++ "> clone() const = 0;", - if rp == RecordPositions then " int line_number, char_number;" else "", - "};" - ] - -prCon :: (String, CAbsRule) -> String -prCon (c,(f,cs)) = unlines [ - "class " ++f++ " : public " ++ c, - "{", - "public:", - unlines - [" std::unique_ptr<" ++ typ ++ "> " ++ var ++ ";" | (typ,_,var) <- cs], - "", - " " ++ f ++ "(" ++ f ++ " &&);", - " " ++ f ++ "(const " ++ f ++ " &);", - " " ++ f ++ " &operator=(const " ++f++ " &&);", - " " ++ f ++ "(" ++ conargs ++ ");", - " ~" ++f ++ "();", - " virtual void accept(Visitor *v);", - " std::unique_ptr<" ++c++ "> clone() const override;", - "};" - ] - where - conargs = concat $ intersperse ", " - ["std::unique_ptr<" ++ x ++ "> p" ++ show i | ((x,_,_),i) <- zip cs [1..]] - -prList :: (String, Bool) -> String -prList (c, b) = unlines - [ "//class " ++c++ " : public Visitable, public std::vector>" - , "//{" - , "//public:" - , "// virtual void accept(Visitor *v);" - , "//virtual " ++ c ++ " *clone() const;" - , "//};" - , "" - -- cons for this list type - , concat [ "// std::vector> ", "cons", c, "(std::unique_ptr<", bas, "> x, std::vector> xs);" ] - ] - where - bas = applyWhen b (++ "") $ drop 4 c {- drop "List" -} - - --- **** Implementation (.C) File Functions **** -- - -mkCFile :: Maybe String -> CAbs -> CF -> String -mkCFile inPackage cabs cf = unlines $ [ - "//C++ Abstract Syntax Implementation.", - "#include ", - "#include ", - "#include ", - "#include \"Absyn.H\"", - nsStart inPackage, - unlines [prConC c r | (c,rs) <- signatures cabs, r <- rs], - unlines [prListC l | l <- listtypes cabs], - definedRules (Just $ LC nil cons) cf - "/******************** Defined Constructors ********************/", - nsEnd inPackage - ] - where - nil t = (,dummyType) $ concat [ "new List", identType t, "()" ] - cons t = (,dummyType) $ concat [ "consList", identType t ] - - -prConC :: String -> CAbsRule -> String -prConC c fcs@(f,_) = unlines [ - "/******************** " ++ f ++ " ********************/", - prConstructorC fcs, - prCopyC fcs, - prDestructorC fcs, - prAcceptC f, - prCloneC c f, - "" - ] - -prListC :: (String,Bool) -> String -prListC (c,b) = unlines - [ "/******************** " ++ c ++ " ********************/" - , "" - --, prAcceptC c - -- , prCloneC c - --, prConsC c b - ] - - ---The standard accept function for the Visitor pattern -prAcceptC :: String -> String -prAcceptC ty = unlines [ - "void " ++ ty ++ "::accept(Visitor *v)", - "{", - " v->visit" ++ ty ++ "(this);", - "}" - ] - ---The cloner makes a new deep copy of the object -prCloneC :: String -> String -> String -prCloneC f c = unlines [ - "std::unique_ptr<" ++ f ++ "> " ++ c ++ "::clone() const ", - "{", - " return std::make_unique<" ++ c ++ ">(*this);", - "}" - ] - --- | Make a list constructor definition. -prConsC :: String -> Bool -> String -prConsC c b = unlines - [ concat [ c, "* ", "cons", c, "(", bas, " x, ", c, "* xs) {" ] - , " xs->insert(xs->begin(), x);" - , " return xs;" - , "}" - ] - where - bas = applyWhen b (++ "*") $ drop 4 c {- drop "List" -} - ---The constructor assigns the parameters to the corresponding instance variables. -prConstructorC :: CAbsRule -> String -prConstructorC (f,cs) = unlines [ - f ++ "::" ++ f ++ "(" ++ conargs ++ ")", - "{", - unlines [" " ++ c ++ " = std::move(" ++ p ++ ");" | (c,p) <- zip cvs pvs], - "}" - ] - where - cvs = [c | (_,_,c) <- cs] - pvs = ['p' : show i | ((_,_,_),i) <- zip cs [1..]] - conargs = intercalate ", " - ["std::unique_ptr<" ++ x ++ ">" +++ v | ((x,_,_),v) <- zip cs pvs] - - ---Copy constructor and copy assignment -prCopyC :: CAbsRule -> String -prCopyC (c,cs) = unlines [ - -- Prog::Prog(const Prog & other) {} - c ++ "::" ++ c ++ "(const" +++ c +++ "& other)", - "{", - -- unlines [" " ++ cv ++ " = std::move(other." ++ cv ++ ");" | (x,_,cv) <- cs], - " *this = std::move(other);", - "}", - "", - -- Prog::Prog(Prog && other) {} - c ++ "::" ++ c ++ "(" ++ c +++ "&& other)", - "{", - unlines [" " ++ cv ++ " = std::move(other." ++ cv ++ ");" | (x,_,cv) <- cs], - "}", - "", - -- Prog &Prog::operator=(const Prog && other) - c +++ "&" ++ c ++ "::" ++ "operator=(const" +++ c +++ "&& other)", - "{", - unlines [" //" ++ cv ++ "->reserve(other." ++ cv ++ "->size());" | (x,_,cv) <- cs], - unlines [" //for (auto const& e : *other." ++ cv ++ ") {" | (x,_,cv) <- cs], - unlines [" // " ++ cv ++ "->push_back(e->clone());" | (x,_,cv) <- cs], - -- unlines [" " ++ cv ++ " = std::move(other." ++ cv ++ ");" | (x,_,cv) <- cs], - " return *this;", - "}" - ] - where - cloneIf st cv = if st then (cv ++ "->clone()") else cv - ---The destructor defined but no operation -prDestructorC :: CAbsRule -> String -prDestructorC (c, _) = unlines [ - c ++ "::~" ++ c ++"()", - "{", - " // NOP", - "}" - ] From 64e236705016d86a79f7e3b106d6ae1a1ad0da72 Mon Sep 17 00:00:00 2001 From: "hiroyuki.nagata" Date: Sun, 24 Oct 2021 19:02:21 +0900 Subject: [PATCH 4/9] Bison, fix to use %skeleton as "lalr1.cc" it requires bison >= 3.2 * Implement switching bison %union and variant * Implement C++ parser with driver setting * Implement C++ driver/scanner class * Fix file extension * Fix token type * Fix flex buffer related code * Refactor makefile compile option * Implement reverse function in ListXXX class Add member fields for Driver class to receive parsed objects Update CFtoBisonC and CFtoSTLAbs for wrapping std::uniuqe_ptr Update C++ Abs files and Printer class Update PrettyPrinter code for using smart-ptr Enable to compile testcc * add driver entry codes * modify SkelSTL.hs for header file extension * Enable debugging of lexer/parser Change bison yy file to use shared_ptr instead of unique_ptr --- source/src/BNFC/Backend/C/CFtoBisonC.hs | 369 +++++++++---- source/src/BNFC/Backend/C/CFtoFlexC.hs | 284 ++++++---- source/src/BNFC/Backend/CPP/Common.hs | 24 +- source/src/BNFC/Backend/CPP/Makefile.hs | 80 +-- source/src/BNFC/Backend/CPP/NoSTL.hs | 16 +- source/src/BNFC/Backend/CPP/PrettyPrinter.hs | 265 +++++---- source/src/BNFC/Backend/CPP/STL.hs | 520 ++++++++++++++---- .../BNFC/Backend/CPP/STL/CFtoCVisitSkelSTL.hs | 42 +- source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs | 104 ++-- source/src/BNFC/Backend/Common/OOAbstract.hs | 4 +- 10 files changed, 1175 insertions(+), 533 deletions(-) diff --git a/source/src/BNFC/Backend/C/CFtoBisonC.hs b/source/src/BNFC/Backend/C/CFtoBisonC.hs index 8d297d98..ee5fe1e8 100644 --- a/source/src/BNFC/Backend/C/CFtoBisonC.hs +++ b/source/src/BNFC/Backend/C/CFtoBisonC.hs @@ -22,6 +22,7 @@ module BNFC.Backend.C.CFtoBisonC , resultName, typeName, varName , specialToks, startSymbol , unionBuiltinTokens + , positionCats ) where @@ -30,17 +31,18 @@ import Prelude hiding ((<>)) import Data.Char ( toLower, isUpper ) import Data.Foldable ( toList ) import Data.List ( intercalate, nub ) +import Data.Maybe ( fromMaybe ) import qualified Data.Map as Map import System.FilePath ( (<.>) ) import BNFC.CF import BNFC.Backend.Common.NamedVariables hiding (varName) -import BNFC.Backend.C.CFtoFlexC (ParserMode(..), cParser, reentrant, stlParser, parserHExt, parserName, parserPackage, variant, automove) +import BNFC.Backend.C.CFtoFlexC (ParserMode(..), cParser, stlParser, parserHExt, parserName, parserPackage, isBisonUseUnion, isBisonUseVariant, beyondAnsi) import BNFC.Backend.CPP.Naming import BNFC.Backend.CPP.STL.STLUtils -import BNFC.Options (RecordPositions(..), InPackage, Ansi(..) ) +import BNFC.Options (RecordPositions(..), InPackage, Ansi(..)) import BNFC.PrettyPrint -import BNFC.Utils ((+++), table, applyWhen, for, unless, when, whenJust) +import BNFC.Utils ((+++), table, applyWhen, for, unless, when, whenJust, camelCase_) --This follows the basic structure of CFtoHappy. @@ -54,14 +56,57 @@ type MetaVar = String cf2Bison :: RecordPositions -> ParserMode -> CF -> SymMap -> String cf2Bison rp mode cf env = unlines [ header mode cf - , render $ union mode $ posCats ++ allParserCatsNorm cf - , "" - , unionDependentCode mode - , unlines $ table " " $ concat - [ [ ["%token", "_ERROR_" ] ] - , tokens (map fst $ tokenPragmas cf) env - , specialToks cf - ] + , case isBisonUseUnion mode of { + -- + -- C and CPP(Ansi) ParserMode will genrate following bison code: + -- + -- %union + -- { + -- char* _string; + -- Program* program_; + -- } + -- ... + -- %token _ERROR_ + -- %token _STAR /* * */ + -- ... + -- %token<_string> _STRING_ + -- %token<_int> _INTEGER_ + -- %token<_string> _IDENT_ + -- + -- %type Program + -- + True -> unlines [ + render $ union mode $ posCats ++ allParserCatsNorm cf -- '%union' directive + , "" + , unionDependentCode mode -- yyerror, yyparse part for '%union' + , unlines $ table " " $ concat + [ [ ["%token", "_ERROR_" ] ] -- define %tokens /* x */ + , tokens mode (map fst $ tokenPragmas cf) env -- user-defined regex %tokens + , specialToks mode cf -- built-in %tokens + ]] + ; + -- + -- CPP(BeyondAnsi) ParserMode will genrate following bison code: + -- + -- /** NO union directive ! result will be stored into driver class */ + -- ... + -- %token _ERROR_ + -- %token _STAR /* * */ + -- ... + -- %token _STRING_ + -- %token _ INTEGER_ + -- %token _IDENT_ + -- + -- %type > Program + -- + False -> unlines [ + unlines $ table " " $ concat + [ [ ["%token", "_ERROR_" ] ] -- define %tokens /* x */ + , tokens mode (map fst $ tokenPragmas cf) env -- user-defined regex %tokens + , specialToks mode cf -- built-in %tokens + ]] + ; + } , declarations mode cf , startSymbol cf , "" @@ -71,94 +116,149 @@ cf2Bison rp mode cf env = unlines , "%%" , "" , nsStart inPackage - , entryCode mode cf + , if (beyondAnsi mode) then + unlines [ + "void " ++ns++ "::" ++camelCaseName++ "Parser::error(const " ++camelCaseName++ "Parser::location_type& l, const std::string& m)" + , "{" + , " driver.error(l, m);" + , "}"] + else + entryCode mode cf -- entryCode for beyondAndi is in Driver , nsEnd inPackage ] where - inPackage = parserPackage mode - posCats - | stlParser mode = map TokenCat $ positionCats cf - | otherwise = [] + inPackage = parserPackage mode + posCats + | stlParser mode = map TokenCat $ positionCats cf + | otherwise = [] + name = parserName mode + camelCaseName = camelCase_ name + ns = fromMaybe camelCaseName (parserPackage mode) + positionCats :: CF -> [String] positionCats cf = [ wpThing name | TokenReg name True _ <- cfgPragmas cf ] header :: ParserMode -> CF -> String -header mode cf = unlines $ concat - [ [ "/* Parser definition to be used with Bison. */" - , "" - , "/* Generate header file for lexer. */" - , "%defines \"" ++ ("Bison" <.> h) ++ "\"" - ] +header mode cf = unlines $ concat [ + -- + -- Common header + -- + [ "/* Parser definition to be used with Bison. */" + , "" + , "/* Generate header file for lexer. */" + , "%defines \"" ++ ("Bison" <.> hExt) ++ "\"" + ] + , when (beyondAnsi mode) + [ "%define parse.trace" + , "%define api.namespace {" ++ ns ++ "}" + , "/* Specify the namespace for the C++ parser class. */"] , whenJust (parserPackage mode) $ \ ns -> - [ "%name-prefix = \"" ++ ns ++ "\"" - , " /* From Bison 2.6: %define api.prefix {" ++ ns ++ "} */" - ] - , [ "" - , "/* Reentrant parser */" - , reentrant mode - , " /* From Bison 2.3b (2008): %define api.pure full */" - -- The flag %pure_parser is deprecated with a warning since Bison 3.4, - -- but older Bisons like 2.3 (2006, shipped with macOS) don't recognize - -- %define api.pure full - , "%lex-param { yyscan_t scanner }" - , "%parse-param { yyscan_t scanner }" - , "" - , concat [ "/* Turn on line/column tracking in the ", name, "lloc structure: */" ] - , "%locations" - , "" - , "/* Argument to the parser to be filled with the parsed tree. */" - , "%parse-param { YYSTYPE *result }" - , "" - -- Use variant type if c++14 - , unlines $ (variant mode) - -- Use std::move if c++14 - , unlines $ (automove mode) - , "" - , "%{" - , "/* Begin C preamble code */" - , "" - ] - -- Andreas, 2021-08-26, issue #377: Some C++ compilers want "algorithm". - -- Fixing regression introduced in 2.9.2. - , when (stlParser mode) - [ "#include /* for std::reverse */" -- mandatory e.g. with GNU C++ 11 - ] - , [ "#include " - , "#include " - , "#include " - , "#include \"" ++ ("Absyn" <.> h) ++ "\"" - , "" - , "#define YYMAXDEPTH 10000000" -- default maximum stack size is 10000, but right-recursion needs O(n) stack - , "" - , "/* The type yyscan_t is defined by flex, but we need it in the parser already. */" - , "#ifndef YY_TYPEDEF_YY_SCANNER_T" - , "#define YY_TYPEDEF_YY_SCANNER_T" - , "typedef void* yyscan_t;" - , "#endif" - , "" - -- , "typedef struct " ++ name ++ "_buffer_state *YY_BUFFER_STATE;" - , "typedef struct yy_buffer_state *YY_BUFFER_STATE;" - , "extern YY_BUFFER_STATE " ++ name ++ "_scan_string(const char *str, yyscan_t scanner);" - , "extern void " ++ name ++ "_delete_buffer(YY_BUFFER_STATE buf, yyscan_t scanner);" - , "" - , "extern void " ++ name ++ "lex_destroy(yyscan_t scanner);" - , "extern char* " ++ name ++ "get_text(yyscan_t scanner);" - , "" - , "extern yyscan_t " ++ name ++ "_initialize_lexer(FILE * inp);" - , "" - ] - , unless (stlParser mode) - [ "/* List reversal functions. */" - , concatMap (reverseList mode) $ filter isList $ allParserCatsNorm cf - ] - , [ "/* End C preamble code */" - , "%}" - ] + [ "%name-prefix = \"" ++ ns ++ "\"" + , "/* From Bison 2.6: %define api.prefix {" ++ ns ++ "} */"] + , if beyondAnsi mode then + -- Bison c++ beyond ansi mode + ["" + , "/* Reentrant parser */" + , "/* lalr1.cc always pure parser. needless to define %define api.pure full */" + , "" + , "%define api.parser.class {" ++ camelCaseName ++ "Parser}" + , "%code top {" + , "#include " + , "}" + , "%code requires{" + , "#include \"Absyn" ++ hExt ++ "\"" + , "" + , " namespace " ++ ns ++ " {" + , " class " ++ camelCaseName ++ "Scanner;" + , " class " ++ camelCaseName ++ "Driver;" + , " }" + , "}" + , "%parse-param { " ++ camelCaseName ++ "Scanner &scanner }" + , "%parse-param { " ++ camelCaseName ++ "Driver &driver }" + , "" + , "/* Turn on line/column tracking in the " ++name++ "lloc structure: */" + , "%locations" + , "/* variant based implementation of semantic values for C++ */" + , "%require \"3.2\"" + , "%define api.value.type variant" + , "/* 'yacc.c' does not support variant, so use skeleton 'lalr1.cc' */" + , "%skeleton \"lalr1.cc\"" + , "" + , "%code{" + , "/* Begin C++ preamble code */" + , "#include /* for std::reverse */" + , "#include " + , "#include " + , "#include " + , "" + , "/* include for all driver functions */" + , "#include \"Driver.hh\"" + , "" + , "#undef yylex" + , "#define yylex scanner.lex" + , "}" + , "" + ] + else + -- Bison c/c++ ansi mode + ["" + , "/* Reentrant parser */" + , "%pure_parser" + , "/* From Bison 2.3b (2008): %define api.pure full */" + , "/* The flag %pure_parser is deprecated with a warning since Bison 3.4, */" + , "/* but older Bisons like 2.3 (2006, shipped with macOS) don't recognize %define api.pure full */" + , "" + , "%lex-param { yyscan_t scanner }" + , "%parse-param { yyscan_t scanner }" + , "" + , "/* Turn on line/column tracking in the " ++name++ "lloc structure: */" + , "%locations" + , "/* Argument to the parser to be filled with the parsed tree. */" + , "%parse-param { YYSTYPE *result }" + , "" + , "%{" + , "/* Begin C preamble code */" + , "" + -- Andreas, 2021-08-26, issue #377: Some C++ compilers want "algorithm". + -- Fixing regression introduced in 2.9.2. + , when (stlParser mode) + "#include /* for std::reverse */" -- mandatory e.g. with GNU C++ 11 + , "#include " + , "#include " + , "#include " + , "#include \"" ++ ("Absyn" <.> hExt) ++ "\"" + , "" + , "#define YYMAXDEPTH 10000000" -- default maximum stack size is 10000, but right-recursion needs O(n) stack + , "" + , "/* The type yyscan_t is defined by flex, but we need it in the parser already. */" + , "#ifndef YY_TYPEDEF_YY_SCANNER_T" + , "#define YY_TYPEDEF_YY_SCANNER_T" + , "typedef void* yyscan_t;" + , "#endif" + , "" + , "typedef struct " ++ name ++ "_buffer_state *YY_BUFFER_STATE;" + , "typedef struct yy_buffer_state *YY_BUFFER_STATE;" + , "extern YY_BUFFER_STATE " ++ name ++ "_scan_string(const char *str, yyscan_t scanner);" + , "extern void " ++ name ++ "_delete_buffer(YY_BUFFER_STATE buf, yyscan_t scanner);" + , "" + , "extern void " ++ name ++ "lex_destroy(yyscan_t scanner);" + , "extern char* " ++ name ++ "get_text(yyscan_t scanner);" + , "" + , "extern yyscan_t " ++ name ++ "_initialize_lexer(FILE * inp);" + , "" + , unless (stlParser mode) + unlines [ "/* List reversal functions. */" + , concatMap (reverseList mode) $ filter isList $ allParserCatsNorm cf] + , "/* End C preamble code */" + , "%}" + ] ] where - h = parserHExt mode - name = parserName mode + hExt = "." ++ parserHExt mode + name = parserName mode + camelCaseName = camelCase_ name + ns = fromMaybe camelCaseName (parserPackage mode) -- | Code that needs the @YYSTYPE@ defined by the @%union@ pragma. -- @@ -295,7 +395,7 @@ reverseList mode c0 = unlines -- ListFoo* listfoo_; -- -- >>> let foo2 = CoercCat "Foo" 2 --- >>> union (CppParser Nothing "") [foo, ListCat foo, foo2, ListCat foo2] +-- >>> union (CppParser Nothing "" Ansi) [foo, ListCat foo, foo2, ListCat foo2] -- %union -- { -- int _int; @@ -328,22 +428,29 @@ unionBuiltinTokens = declarations :: ParserMode -> CF -> String declarations mode cf = unlines $ map typeNT $ posCats ++ - filter (not . null . rulesForCat cf) (allParserCats cf) -- don't define internal rules + -- don't define internal rules + filter (not . null . rulesForCat cf) (allParserCats cf) where - typeNT nt = "%type <" ++ varName nt ++ "> " ++ identCat nt - posCats - | stlParser mode = map TokenCat $ positionCats cf - | otherwise = [] + typeNT nt = if isBisonUseVariant mode then + "%type > " ++ identCat nt + else + "%type <" ++ varName nt ++ "> " ++ identCat nt + posCats + | stlParser mode = map TokenCat $ positionCats cf + | otherwise = [] --declares terminal types. -- token name "literal" -- "Syntax error messages passed to yyerror from the parser will reference the literal string instead of the token name." -- https://www.gnu.org/software/bison/manual/html_node/Token-Decl.html -tokens :: [UserDef] -> SymMap -> [[String]] -tokens user env = map declTok $ Map.toList env +tokens :: ParserMode -> [UserDef] -> SymMap -> [[String]] +tokens mode userDefs env = map declTok $ Map.toList env where + stringType = case isBisonUseVariant mode of + True -> ""; + False -> "<_string>"; declTok (Keyword s, r) = tok "" s r - declTok (Tokentype s, r) = tok (if s `elem` user then "<_string>" else "") s r + declTok (Tokentype s, r) = tok (if s `elem` userDefs then stringType else "") s r tok t s r = [ "%token" ++ t, r, " /* " ++ cStringEscape s ++ " */" ] -- | Escape characters inside a C string. @@ -355,16 +462,21 @@ cStringEscape = concatMap escChar | otherwise = [c] -- | Produces a table with the built-in token types. -specialToks :: CF -> [[String]] -specialToks cf = concat - [ ifC catString [ "%token<_string>", "_STRING_" ] - , ifC catChar [ "%token<_char> ", "_CHAR_" ] - , ifC catInteger [ "%token<_int> ", "_INTEGER_" ] - , ifC catDouble [ "%token<_double>", "_DOUBLE_" ] - , ifC catIdent [ "%token<_string>", "_IDENT_" ] +specialToks :: ParserMode -> CF -> [[String]] +specialToks mode cf = concat + [ ifC catString [ "%token"++stringToken, "_STRING_" ] + , ifC catChar [ "%token"++charToken++" ", "_CHAR_" ] + , ifC catInteger [ "%token"++intToken++" ", "_INTEGER_" ] + , ifC catDouble [ "%token"++doubleToken, "_DOUBLE_" ] + , ifC catIdent [ "%token"++stringToken, "_IDENT_" ] ] where ifC cat s = if isUsedCat cf (TokenCat cat) then [s] else [] + stringToken = if isBisonUseVariant mode then "" else "<_string>" + charToken = if isBisonUseVariant mode then "" else "<_char>" + intToken = if isBisonUseVariant mode then "" else "<_int>" + doubleToken = if isBisonUseVariant mode then "" else "<_double>" + -- | Bison only supports a single entrypoint. startSymbol :: CF -> String @@ -380,7 +492,7 @@ rulesForBison rp mode cf env = map mkOne (ruleGroups cf) ++ posRules posRules | CppParser inPackage _ _ <- mode = for (positionCats cf) $ \ n -> (TokenCat n, [( Map.findWithDefault n (Tokentype n) env - , addResult cf (TokenCat n) $ concat + , addResult mode cf (TokenCat n) $ concat [ "$$ = new ", nsScope inPackage, n, "($1, @$.first_line);" ] )]) | otherwise = [] @@ -392,7 +504,7 @@ constructRule -> NonTerminal -- ^ ... this non-terminal. -> (NonTerminal,[(Pattern,Action)]) constructRule rp mode cf env rules nt = (nt,) $ - [ (p,) $ addResult cf nt $ generateAction rp mode (identCat (normCat nt)) (funRule r) b m + [ (p,) $ addResult mode cf nt $ generateAction rp mode (identCat (normCat nt)) (funRule r) b m | r0 <- rules , let (b,r) = if isConsFun (funRule r0) && valCat r0 `elem` cfgReversibleCats cf then (True, revSepListRule r0) @@ -402,14 +514,16 @@ constructRule rp mode cf env rules nt = (nt,) $ -- | Add action if we parse an entrypoint non-terminal: -- Set field in result record to current parse. -addResult :: CF -> NonTerminal -> Action -> Action -addResult cf nt a = - if nt `elem` toList (allEntryPoints cf) - -- Note: Bison has only a single entrypoint, - -- but BNFC works around this by adding dedicated parse methods for all entrypoints. - -- Andreas, 2021-03-24: But see #350: bison still uses only the @%start@ non-terminal. - then concat [ a, " result->", varName (normCat nt), " = $$;" ] - else a +addResult :: ParserMode -> CF -> NonTerminal -> Action -> Action +addResult mode cf nt a = + if nt `elem` toList (allEntryPoints cf) then + -- Note: Bison has only a single entrypoint, + -- but BNFC works around this by adding dedicated parse methods for all entrypoints. + -- Andreas, 2021-03-24: But see #350: bison still uses only the @%start@ non-terminal. + case beyondAnsi mode of + False -> concat [ a, " result->", varName (normCat nt), " = $$;" ] + True -> concat [ a, " driver.", varName (normCat nt), " = $$;" ] + else a -- | Switch between STL or not. generateAction :: IsFun a @@ -421,7 +535,8 @@ generateAction :: IsFun a -> [(MetaVar, Bool)] -- ^ Meta-vars; should the list referenced by the var be reversed? -> Action generateAction rp = \case - CppParser ns _ _ -> generateActionSTL rp ns + CppParser ns _ Ansi -> generateActionSTL rp ns + CppParser ns _ BeyondAnsi -> generateActionSTLBeyondAnsi rp ns CParser b _ -> \ nt f r -> generateActionC rp (not b) nt f r . map fst -- | Generates a string containing the semantic action. @@ -476,6 +591,30 @@ generateActionSTL rp inPackage nt f b mbs = reverses ++ reverses = unwords ["std::reverse(" ++ m ++"->begin(),"++m++"->end()) ;" | (m, True) <- mbs] scope = nsScope inPackage +generateActionSTLBeyondAnsi :: IsFun a => RecordPositions -> InPackage -> String -> a -> Bool -> [(MetaVar,Bool)] -> Action +generateActionSTLBeyondAnsi rp inPackage nt f b mbs = reverses ++ + if | isCoercion f -> concat ["$$ = ", unwords ms, ";", loc] + | isNilFun f -> concat ["$$ = ", "std::make_shared<", scope, nt, ">();"] + | isOneFun f -> concat ["$$ = ", "std::make_shared<", scope, nt, ">(); $$->cons(", head ms, ");"] + | isConsFun f -> concat [lst, "->cons(", el, ");"] + | isDefinedRule f -> concat ["$$ = ", scope, sanitizeCpp (funName f), "(", intercalate ", " ms, ");" ] + | otherwise -> concat ["$$ = ", "std::make_shared<", scope, funName f, ">(", (intercalate ", " ms), ");", loc] + where + -- ms = ["$1", "$1", ...]; + -- Bison's semantic value of the n-th symbol of the right-hand side of the rule. + ms = map fst mbs + -- The following match only happens in the cons case: + [el, lst] = applyWhen b reverse ms -- b: left-recursion transformed? + loc | RecordPositions <- rp + = " $$->line_number = @$.first_line; $$->char_number = @$.first_column;" + | otherwise + = "" + -- TODO: temporary commented reverse() + -- reverses = unwords [m ++"->reverse();" | (m, True) <- mbs] + reverses = unwords ["/*" ++m++ "->reverse(); */" | (m, True) <- mbs] + scope = nsScope inPackage + + -- Generate patterns and a set of metavariables indicating -- where in the pattern the non-terminal generatePatterns :: ParserMode -> CF -> SymMap -> Rule -> (Pattern,[(MetaVar,Bool)]) diff --git a/source/src/BNFC/Backend/C/CFtoFlexC.hs b/source/src/BNFC/Backend/C/CFtoFlexC.hs index f32e6acd..aebef876 100644 --- a/source/src/BNFC/Backend/C/CFtoFlexC.hs +++ b/source/src/BNFC/Backend/C/CFtoFlexC.hs @@ -17,7 +17,7 @@ module BNFC.Backend.C.CFtoFlexC ( cf2flex - , ParserMode(..), parserName, parserPackage, reentrant, cParser, stlParser, parserHExt, variant, automove + , ParserMode(..), parserName, parserPackage, reentrant, cParser, stlParser, parserHExt, variant, beyondAnsi, isBisonUseUnion, isBisonUseVariant , preludeForBuffer -- C code defining a buffer for lexing string literals. , cMacros -- Lexer definitions. , commentStates -- Stream of names for lexer states for comments. @@ -40,7 +40,7 @@ import BNFC.Backend.C.RegToFlex import BNFC.Backend.Common.NamedVariables import BNFC.Options ( InPackage, Ansi(..) ) import BNFC.PrettyPrint -import BNFC.Utils ( cstring, symbolToName, unless, when ) +import BNFC.Utils ( cstring, symbolToName, unless, when, camelCase_ ) data ParserMode = CParser Bool String -- ^ @C@ (@False@) or @C++ no STL@ (@True@) mode, with @name@ to use as prefix. @@ -59,22 +59,33 @@ parserPackage = \case reentrant :: ParserMode -> String reentrant = \case CParser _ _ -> "%pure_parser"; - CppParser _ _ ansi | ansi == BeyondAnsi -> "%define api.pure" + CppParser _ _ ansi | ansi == BeyondAnsi -> "/* \"lalr1.cc\" is always pure parser. needless to define %define api.pure full */" | otherwise -> "%pure_parser"; variant :: ParserMode -> [String] variant = \case CppParser _ _ ansi | ansi == BeyondAnsi -> [ "/* variant based implementation of semantic values for C++ */" - ,"%define api.value.type variant"] + ,"%require \"3.2\"" + ,"%define api.value.type variant" + ,"/* 'yacc.c' does not support variant, so use skeleton 'lalr1.cc' */" + ,"%skeleton \"lalr1.cc\""] _ -> [] -automove :: ParserMode -> [String] -automove = \case - CppParser _ _ ansi | ansi == BeyondAnsi -> [ - "/* every occurrence '$n' is replaced by 'std::move ($n)' */" - , "%define api.value.automove"] - _ -> [] +beyondAnsi :: ParserMode -> Bool +beyondAnsi = \case + CppParser _ _ ansi | ansi == BeyondAnsi -> True + _ -> False + +isBisonUseUnion :: ParserMode -> Bool +isBisonUseUnion = \case + CppParser _ _ ansi | ansi == Ansi -> True + _ -> False + +isBisonUseVariant :: ParserMode -> Bool +isBisonUseVariant = \case + CppParser _ _ ansi | ansi == BeyondAnsi -> True + _ -> False cParser :: ParserMode -> Bool cParser = \case @@ -89,16 +100,17 @@ stlParser = \case parserHExt :: ParserMode -> String parserHExt = \case CParser b _ -> if b then "H" else "h" - CppParser _ _ _ -> "H" + CppParser _ _ ansi | ansi == BeyondAnsi -> "hh" + | otherwise -> "h" -- | Entrypoint. cf2flex :: ParserMode -> CF -> (String, SymMap) -- The environment is reused by the parser. cf2flex mode cf = (, env) $ unlines [ prelude stringLiterals mode , cMacros cf - , lexSymbols env1 - , restOfFlex (parserPackage mode) cf env - , footer -- mode + , lexSymbols mode env1 + , restOfFlex mode cf env + , footer mode ] where env = Map.fromList env2 @@ -113,11 +125,20 @@ prelude :: Bool -> ParserMode -> String prelude stringLiterals mode = unlines $ concat [ [ "/* Lexer definition for use with FLex */" , "" - -- noinput and nounput are most often unused - -- https://stackoverflow.com/questions/39075510/option-noinput-nounput-what-are-they-for - , "%option noyywrap noinput nounput" - , "%option reentrant bison-bridge bison-locations" - , "" + , if (beyondAnsi mode) then + unlines + [ + "%option nodefault noyywrap c++" + , "%option prefix=\"Bnfc\"" + ] + else + unlines + -- noinput and nounput are most often unused + -- https://stackoverflow.com/questions/39075510/option-noinput-nounput-what-are-they-for + [ "%option noyywrap noinput nounput" + , "%option reentrant bison-bridge bison-locations" + , "" + ] ] , when stringLiterals [ "/* Additional data for the lexer: a buffer for lexing string literals. */" @@ -131,7 +152,20 @@ prelude stringLiterals mode = unlines $ concat , posixC , [ "}" ] ] + , when (beyondAnsi mode) + [ "%top{" + , "#include " + , "}" + ] , [ "%{" + , when (beyondAnsi mode) unlines + [ + "#include \"Scanner.hh\"" -- #include for the class inheriting "yyFlexLexer" + , "" + , "/* using \"token\" to make the returns for the tokens shorter to type */" + , "using token = " ++ns++ "::" ++camelCaseName++ "Parser::token;" + , "" + ] , "#include \"" ++ ("Absyn" <.> h) ++ "\"" , "#include \"" ++ ("Bison" <.> h) ++ "\"" , "" @@ -139,65 +173,79 @@ prelude stringLiterals mode = unlines $ concat , [ "#define initialize_lexer " ++ parserName mode ++ "_initialize_lexer" , "" ] - , when stringLiterals $ preludeForBuffer $ "Buffer" <.> h + , when stringLiterals $ preludeForBuffer mode $ "Buffer" <.> h -- https://www.gnu.org/software/bison/manual/html_node/Token-Locations.html -- Flex is responsible for keeping tracking of the yylloc for Bison. -- Flex also doesn't do this automatically so we need this function -- https://stackoverflow.com/a/22125500/425756 - , [ "static void update_loc(YYLTYPE* loc, char* text)" - , "{" - , " loc->first_line = loc->last_line;" - , " loc->first_column = loc->last_column;" - , " int i = 0;" -- put this here as @for (int i...)@ is only allowed in C99 - , " for (; text[i] != '\\0'; ++i) {" - , " if (text[i] == '\\n') {" -- Checking for \n is good enough to also support \r\n (but not \r) - , " ++loc->last_line;" - , " loc->last_column = 0; " - , " } else {" - , " ++loc->last_column; " - , " }" - , " }" - , "}" - , "#define YY_USER_ACTION update_loc(yylloc, yytext);" - , "" - , "%}" - ] + , if beyondAnsi mode then + [ "/* update location on matching */" + , "#define YY_USER_ACTION loc->step(); loc->columns(yyleng);" + , "%}" + ] + else + [ "static void update_loc(YYLTYPE* loc, char* text)" + , "{" + , " loc->first_line = loc->last_line;" + , " loc->first_column = loc->last_column;" + , " int i = 0;" -- put this here as @for (int i...)@ is only allowed in C99 + , " for (; text[i] != '\\0'; ++i) {" + , " if (text[i] == '\\n') {" -- Checking for \n is good enough to also support \r\n (but not \r) + , " ++loc->last_line;" + , " loc->last_column = 0; " + , " } else {" + , " ++loc->last_column; " + , " }" + , " }" + , "}" + , "#define YY_USER_ACTION update_loc(yylloc, yytext);" + , "" + , "%}" + ] ] where - h = parserHExt mode + h = parserHExt mode + name = parserName mode + camelCaseName = camelCase_ name + ns = fromMaybe camelCaseName (parserPackage mode) -- | Part of the lexer prelude needed when string literals are to be lexed. -- Defines an interface to the Buffer. -preludeForBuffer :: String -> [String] -preludeForBuffer bufferH = - [ "/* BEGIN extensible string buffer */" - , "" - , "#include \"" ++ bufferH ++ "\"" - , "" - , "/* The initial size of the buffer to lex string literals. */" - , "#define LITERAL_BUFFER_INITIAL_SIZE 1024" - , "" - , "/* The pointer to the literal buffer. */" - , "#define literal_buffer yyextra" - , "" - , "/* Initialize the literal buffer. */" - , "#define LITERAL_BUFFER_CREATE() literal_buffer = newBuffer(LITERAL_BUFFER_INITIAL_SIZE)" - , "" - , "/* Append characters at the end of the buffer. */" - , "#define LITERAL_BUFFER_APPEND(s) bufferAppendString(literal_buffer, s)" - , "" - , "/* Append a character at the end of the buffer. */" - , "#define LITERAL_BUFFER_APPEND_CHAR(c) bufferAppendChar(literal_buffer, c)" - , "" - , "/* Release the buffer, returning a pointer to its content. */" - , "#define LITERAL_BUFFER_HARVEST() releaseBuffer(literal_buffer)" - , "" - , "/* In exceptional cases, e.g. when reaching EOF, we have to free the buffer. */" - , "#define LITERAL_BUFFER_FREE() freeBuffer(literal_buffer)" - , "" - , "/* END extensible string buffer */" - , "" - ] +preludeForBuffer :: ParserMode -> String -> [String] +preludeForBuffer mode bufferH = + ["/* BEGIN extensible string buffer */" + , "" + , "#include \"" ++ bufferH ++ "\"" + , "" + , "/* The initial size of the buffer to lex string literals. */" + , "#define LITERAL_BUFFER_INITIAL_SIZE 1024" + , "" + , "/* The pointer to the literal buffer. */" + , if (beyondAnsi mode) then + -- yyextra is not available in C++ lexer + -- https://stackoverflow.com/questions/51065292/how-to-use-yyextra-in-c + "Buffer literal_buffer = nullptr;" + else + "#define literal_buffer yyextra" + , "" + , "/* Initialize the literal buffer. */" + , "#define LITERAL_BUFFER_CREATE() literal_buffer = newBuffer(LITERAL_BUFFER_INITIAL_SIZE)" + , "" + , "/* Append characters at the end of the buffer. */" + , "#define LITERAL_BUFFER_APPEND(s) bufferAppendString(literal_buffer, s)" + , "" + , "/* Append a character at the end of the buffer. */" + , "#define LITERAL_BUFFER_APPEND_CHAR(c) bufferAppendChar(literal_buffer, c)" + , "" + , "/* Release the buffer, returning a pointer to its content. */" + , "#define LITERAL_BUFFER_HARVEST() releaseBuffer(literal_buffer)" + , "" + , "/* In exceptional cases, e.g. when reaching EOF, we have to free the buffer. */" + , "#define LITERAL_BUFFER_FREE() freeBuffer(literal_buffer)" + , "" + , "/* END extensible string buffer */" + , "" + ] -- For now all categories are included. -- Optimally only the ones that are used should be generated. @@ -216,42 +264,94 @@ cMacros cf = unlines , "%% /* Rules. */" ] -lexSymbols :: KeywordEnv -> String -lexSymbols ss = concatMap transSym ss +lexSymbols :: ParserMode -> KeywordEnv -> String +lexSymbols mode ss = concatMap transSym ss where transSym (s,r) = - "\"" ++ s' ++ "\" \t return " ++ r ++ ";\n" + "\"" ++ s' ++ "\" \t return " ++ prefix ++ r ++ ";\n" where s' = escapeChars s + prefix = if (beyondAnsi mode) then "token::" else "" -restOfFlex :: InPackage -> CF -> SymMap -> String -restOfFlex _inPackage cf env = unlines $ concat +restOfFlex :: ParserMode -> CF -> SymMap -> String +restOfFlex mode cf env = unlines $ concat [ [ render $ lexComments $ comments cf , "" ] , userDefTokens - , ifC catString $ lexStrings "yylval" "_STRING_" "_ERROR_" - , ifC catChar $ lexChars "yylval" "_CHAR_" - , ifC catDouble [ "{DIGIT}+\".\"{DIGIT}+(\"e\"(\\-)?{DIGIT}+)? \t yylval->_double = atof(yytext); return _DOUBLE_;" ] - , ifC catInteger [ "{DIGIT}+ \t yylval->_int = atoi(yytext); return _INTEGER_;" ] - , ifC catIdent [ "{LETTER}{IDENT}* \t yylval->_string = strdup(yytext); return _IDENT_;" ] + , ifC catString $ lexStrings mode (prefix++"_STRING_") (prefix++"_ERROR_") + , ifC catChar $ lexChars "yylval" (prefix++"_CHAR_") + , ifC catDouble [ "{DIGIT}+\".\"{DIGIT}+(\"e\"(\\-)?{DIGIT}+)? \t " ++ (yylvalCopy mode "double" "yytext") ++ " return " ++prefix++ "_DOUBLE_;" ] + , ifC catInteger [ "{DIGIT}+ \t " ++ (yylvalCopy mode "int" "yytext") ++ " return " ++prefix++ "_INTEGER_;" ] + , ifC catIdent [ "{LETTER}{IDENT}* \t " ++ (yylvalCopy mode "string" "yytext") ++ " return " ++prefix++ "_IDENT_;" ] , [ "[ \\t\\r\\n\\f] \t /* ignore white space. */;" - , ". \t return _ERROR_;" + , ". \t return " ++prefix++ "_ERROR_;" , "" , "%% /* Initialization code. */" ] + , when (beyondAnsi mode) + [ + "namespace " ++ns++ " {" + , "" + , "" ++camelCaseName++ "Scanner::" ++camelCaseName++ "Scanner(std::istream *in)" + , " : BnfcFlexLexer(in)" + , "{" + , " loc = new " ++camelCaseName++ "::" ++camelCaseName++ "Parser::location_type();" + , "}" + , "" + , "" ++camelCaseName++ "Scanner::~" ++camelCaseName++ "Scanner()" + , "{" + , "}" + , "" + , "/* This implementation of " ++camelCaseName++ "FlexLexer::yylex() is required to fill the" + , " * vtable of the class " ++camelCaseName++ "FlexLexer. We define the scanner's main yylex" + , " * function via YY_DECL to reside in the Scanner class instead. */" + , "" + , "}" + , "" + , "#ifdef yylex" + , "#undef yylex" + , "#endif" + , "" + , "int BnfcFlexLexer::yylex()" + , "{" + , " std::cerr << \"in BnfcFlexLexer::yylex() !\" << std::endl;" + , " return 0;" + , "}" + ] ] where - ifC cat s = if isUsedCat cf (TokenCat cat) then s else [] - userDefTokens = - [ "" ++ printRegFlex exp ++ - " \t yylval->_string = strdup(yytext); return " ++ sName name ++ ";" - | (name, exp) <- tokenPragmas cf - ] - where sName n = fromMaybe n $ Map.lookup (Tokentype n) env + name = parserName mode + camelCaseName = camelCase_ name + ns = fromMaybe camelCaseName (parserPackage mode) + _inPackage = parserPackage mode + prefix = if (beyondAnsi mode) then "token::" else "" + ifC cat s = if isUsedCat cf (TokenCat cat) then s else [] + userDefTokens = + [ "" ++ printRegFlex exp ++ + " \t " ++ (yylvalCopy mode "string" "yytext") ++ " return " ++ prefix ++ (sName name) ++ ";" + | (name, exp) <- tokenPragmas cf + ] + where sName n = fromMaybe n $ Map.lookup (Tokentype n) env + +-- | switch yylval->emplace and yylval->_x = conv(yytext) +yylvalCopy :: ParserMode -> String -> String -> String +yylvalCopy mode typeStr arg = + case (beyondAnsi mode, typeStr) of + (True , "string") -> "yylval->emplace(" ++arg++ ");" + (True , "int") -> "yylval->emplace(atoi(" ++arg++ "));" + (True , _ ) -> "yylval->emplace<" ++typeStr++ ">(" ++arg++ ");" + (False, "string") -> "yylval->_string = strdup(" ++arg++ ");" + (False, "int" ) -> "yylval->_int = atoi(" ++arg++ ");" + (False, "double") -> "yylval->_double = atof(" ++arg++ ");" + (False, _ ) -> "" -footer :: String -footer = unlines +footer :: ParserMode -> String +footer mode = + if beyondAnsi mode then + "" -- TODO: Add required code later + else + unlines $ [ "yyscan_t initialize_lexer(FILE *inp)" , "{" , " yyscan_t scanner;" @@ -262,11 +362,11 @@ footer = unlines ] -- | Lexing of strings, converting escaped characters. -lexStrings :: String -> String -> String -> [String] -lexStrings yylval stringToken errorToken = +lexStrings :: ParserMode -> String -> String -> [String] +lexStrings mode stringToken errorToken = [ "\"\\\"\" \t LITERAL_BUFFER_CREATE(); BEGIN STRING;" , "\\\\ \t BEGIN ESCAPED;" - , "\\\" \t " ++ yylval ++ "->_string = LITERAL_BUFFER_HARVEST(); BEGIN INITIAL; return " ++ stringToken ++ ";" + , "\\\" \t " ++ (yylvalCopy mode "string" "LITERAL_BUFFER_HARVEST()") ++ " BEGIN INITIAL; return " ++ stringToken ++ ";" , ". \t LITERAL_BUFFER_APPEND_CHAR(yytext[0]);" , "f \t LITERAL_BUFFER_APPEND_CHAR('\\f'); BEGIN STRING;" , "n \t LITERAL_BUFFER_APPEND_CHAR('\\n'); BEGIN STRING;" diff --git a/source/src/BNFC/Backend/CPP/Common.hs b/source/src/BNFC/Backend/CPP/Common.hs index 89708db2..c098c000 100644 --- a/source/src/BNFC/Backend/CPP/Common.hs +++ b/source/src/BNFC/Backend/CPP/Common.hs @@ -9,7 +9,7 @@ import Data.List ( intercalate ) import BNFC.CF import BNFC.TypeChecker - +import BNFC.Options ( Ansi ) import BNFC.Backend.C ( comment ) import BNFC.Backend.CPP.Naming @@ -72,3 +72,25 @@ definedRules mlc cf banner LitString s -> show s call x es = x ++ "(" ++ intercalate ", " (map loop es) ++ ")" + +data CppStdMode + = CppStdAnsi Ansi -- ^ @Ansi@ mode. + | CppStdBeyondAnsi Ansi -- ^ @BeyondAnsi@ mode. + +wrapPointerIf :: Bool -> String -> String +wrapPointerIf b v = if b then "*" ++ v else v + +wrapUniquePtrIf :: Bool -> String -> String +wrapUniquePtrIf b v = if b then "std::unique_ptr<" ++v++">" else v + +wrapUniquePtr :: String -> String +wrapUniquePtr v = "std::unique_ptr<" ++v++">" + +wrapSharedPtrIf :: Bool -> String -> String +wrapSharedPtrIf b v = if b then "std::shared_ptr<" ++v++">" else v + +wrapSharedPtr :: String -> String +wrapSharedPtr v = "std::shared_ptr<" ++v++">" + +wrapMoveIf :: Bool -> String -> String +wrapMoveIf b v = if b then "std::move(" ++v++")" else v diff --git a/source/src/BNFC/Backend/CPP/Makefile.hs b/source/src/BNFC/Backend/CPP/Makefile.hs index 2d3a11d2..0d6c0f62 100644 --- a/source/src/BNFC/Backend/CPP/Makefile.hs +++ b/source/src/BNFC/Backend/CPP/Makefile.hs @@ -1,14 +1,16 @@ {-# LANGUAGE OverloadedStrings #-} module BNFC.Backend.CPP.Makefile (makefile) where - +import BNFC.Options import BNFC.Backend.Common.Makefile import BNFC.PrettyPrint +import BNFC.Utils (when) -makefile :: String -> String -> String -> String -> String -> String -> Doc -makefile prefix name compileOpt lexerExt parserExt basename = vcat +makefile :: String -> String -> SharedOptions -> String -> Doc +makefile prefix name opts basename = + vcat $ [ mkVar "CC" "g++ -g" - , mkVar "CCFLAGS" (compileOpt ++ " -W -Wall -Wno-unused-parameter -Wno-unused-function -Wno-unneeded-internal-declaration") + , mkVar "CCFLAGS" (compileOpt ++ " -W -Wall -Wsign-conversion -Wno-unused-parameter -Wno-unused-function -Wno-unneeded-internal-declaration") , "" , mkVar "FLEX" "flex" , mkVar "FLEX_OPTS" ("-P" ++ prefix) @@ -16,7 +18,10 @@ makefile prefix name compileOpt lexerExt parserExt basename = vcat , mkVar "BISON" "bison" , mkVar "BISON_OPTS" ("-t -p" ++ prefix) , "" - , mkVar "OBJS" "Absyn.o Buffer.o Lexer.o Parser.o Printer.o" + , if (ansi opts /= Ansi) then + mkVar "OBJS" "Absyn.o Buffer.o Lexer.o Parser.o Driver.o Printer.o" + else + mkVar "OBJS" "Absyn.o Buffer.o Lexer.o Parser.o Printer.o" , "" , mkRule ".PHONY" ["clean", "distclean"] [] @@ -28,13 +33,16 @@ makefile prefix name compileOpt lexerExt parserExt basename = vcat [ name ++ e | e <- [".aux", ".log", ".pdf",".dvi", ".ps", ""]] ] , mkRule "distclean" ["clean"] [ "rm -f " ++ unwords - [ "Absyn.C", "Absyn.H" - , "Buffer.C", "Buffer.H" - , "Test.C" - , "Bison.H", "Parser.C", "Parser.H", "ParserError.H", name ++ parserExt - , "Lexer.C", name ++ lexerExt - , "Skeleton.C", "Skeleton.H" - , "Printer.C", "Printer.H" + [ "Absyn" ++ cppExt, "Absyn" ++ hExt + , "Buffer" ++ cppExt, "Buffer" ++ hExt + , "Test" ++ cppExt + , "Bison" ++ hExt, "Parser" ++ cppExt, "Parser" ++ hExt, "ParserError" ++ hExt, name ++ parserExt + , "Lexer" ++ cppExt, name ++ lexerExt + , "Skeleton" ++ cppExt, "Skeleton" ++ hExt + , "Printer" ++ cppExt, "Printer" ++ hExt + , "Driver" ++ cppExt, "Driver" ++ hExt + , "Scanner" ++ hExt + , "location" ++ hExt , basename , name ++ ".tex" ] @@ -42,24 +50,34 @@ makefile prefix name compileOpt lexerExt parserExt basename = vcat , mkRule testName [ "${OBJS}", "Test.o" ] [ "@echo \"Linking " ++ testName ++ "...\"" , "${CC} ${OBJS} Test.o -o " ++ testName ] - , mkRule "Absyn.o" [ "Absyn.C", "Absyn.H" ] - [ "${CC} ${CCFLAGS} -c Absyn.C" ] - , mkRule "Buffer.o" [ "Buffer.C", "Buffer.H" ] - [ "${CC} ${CCFLAGS} -c Buffer.C " ] - , mkRule "Lexer.C" [ name ++ lexerExt ] - [ "${FLEX} ${FLEX_OPTS} -oLexer.C " ++ name ++ lexerExt ] - , mkRule "Parser.C Bison.H" [ name ++ parserExt ] - [ "${BISON} ${BISON_OPTS} " ++ name ++ parserExt ++ " -o Parser.C" ] + , mkRule "Absyn.o" [ "Absyn" ++ cppExt, "Absyn" ++ hExt ] + [ "${CC} ${CCFLAGS} -c Absyn" ++ cppExt ] + , when (ansi opts /= Ansi) + mkRule "Driver.o" [ "Driver" ++ cppExt, "Driver" ++ hExt ] + [ "${CC} ${CCFLAGS} -c Driver" ++ cppExt ] + , mkRule "Buffer.o" [ "Buffer" ++ cppExt, "Buffer" ++ hExt ] + [ "${CC} ${CCFLAGS} -c Buffer" ++ cppExt ] + , mkRule ("Lexer" ++ cppExt) [ name ++ lexerExt ] + [ "${FLEX} ${FLEX_OPTS} -oLexer" ++ cppExt ++ " " ++ name ++ lexerExt ] + , mkRule ("Parser" ++ cppExt++ " Bison" ++ hExt) [ name ++ parserExt ] + [ "${BISON} ${BISON_OPTS} " ++ name ++ parserExt ++ " -o Parser" ++ cppExt ] , mkRule "Lexer.o" [ "CCFLAGS+=-Wno-sign-conversion" ] - , mkRule "Lexer.o" [ "Lexer.C", "Bison.H" ] - [ "${CC} ${CCFLAGS} -c Lexer.C " ] - , mkRule "Parser.o" [ "Parser.C", "Absyn.H", "Bison.H" ] - [ "${CC} ${CCFLAGS} -c Parser.C" ] - , mkRule "Printer.o" [ "Printer.C", "Printer.H", "Absyn.H" ] - [ "${CC} ${CCFLAGS} -c Printer.C" ] - , mkRule "Skeleton.o" [ "Skeleton.C", "Skeleton.H", "Absyn.H" ] - [ "${CC} ${CCFLAGS} -Wno-unused-parameter -c Skeleton.C" ] - , mkRule "Test.o" [ "Test.C", "Parser.H", "Printer.H", "Absyn.H" ] - [ "${CC} ${CCFLAGS} -c Test.C" ] + [] + , mkRule "Lexer.o" [ "Lexer" ++ cppExt, "Bison" ++ hExt ] + [ "${CC} ${CCFLAGS} -c Lexer" ++ cppExt ] + , mkRule "Parser.o" [ "Parser" ++ cppExt, "Absyn" ++ hExt, "Bison" ++ hExt ] + [ "${CC} ${CCFLAGS} -c Parser" ++ cppExt ] + , mkRule "Printer.o" [ "Printer" ++ cppExt, "Printer" ++ hExt, "Absyn" ++ hExt ] + [ "${CC} ${CCFLAGS} -c Printer" ++ cppExt ] + , mkRule "Skeleton.o" [ "Skeleton" ++ cppExt, "Skeleton" ++ hExt, "Absyn" ++ hExt ] + [ "${CC} ${CCFLAGS} -Wno-unused-parameter -c Skeleton" ++ cppExt ] + , mkRule "Test.o" [ "Test" ++ cppExt, "Parser" ++ hExt, "Printer" ++ hExt, "Absyn" ++ hExt ] + [ "${CC} ${CCFLAGS} -c Test" ++ cppExt ] ] - where testName = "Test" ++ name + where + testName = "Test" ++ name + compileOpt = if Ansi == ansi opts then "--ansi" else "-std=c++14" + lexerExt = if Ansi == ansi opts then ".l" else ".ll" + parserExt = if Ansi == ansi opts then ".y" else ".yy" + cppExt = if Ansi == ansi opts then ".c" else ".cc" + hExt = if Ansi == ansi opts then ".h" else ".hh" diff --git a/source/src/BNFC/Backend/CPP/NoSTL.hs b/source/src/BNFC/Backend/CPP/NoSTL.hs index 3fa88461..382f0b39 100644 --- a/source/src/BNFC/Backend/CPP/NoSTL.hs +++ b/source/src/BNFC/Backend/CPP/NoSTL.hs @@ -6,6 +6,7 @@ module BNFC.Backend.CPP.NoSTL (makeCppNoStl) where import Data.Foldable (toList) +import qualified Data.Map as Map import BNFC.Utils import BNFC.CF @@ -14,7 +15,7 @@ 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.Common ( commentWithEmacsModeHint, CppStdMode(..) ) import BNFC.Backend.CPP.Makefile import BNFC.Backend.CPP.NoSTL.CFtoCPPAbs import BNFC.Backend.CPP.STL.CFtoCVisitSkelSTL @@ -32,15 +33,15 @@ makeCppNoStl opts cf = do mkCppFileWithHint (name ++ ".l") flex mkCppFileWithHint (name ++ ".y") $ cf2Bison (linenumbers opts) parserMode cf env mkCppFile "Parser.H" $ - mkHeaderFile (toList $ allEntryPoints cf) - let (skelH, skelC) = cf2CVisitSkel False Nothing cf + mkHeaderFile cf (allParserCats cf) (toList $ allEntryPoints cf) (Map.elems env) + let (skelH, skelC) = cf2CVisitSkel opts False Nothing cf mkCppFile "Skeleton.H" skelH mkCppFile "Skeleton.C" skelC - let (prinH, prinC) = cf2CPPPrinter False Nothing cf + let (prinH, prinC) = cf2CPPPrinter (CppStdAnsi Ansi) False Nothing cf ".H" mkCppFile "Printer.H" prinH mkCppFile "Printer.C" prinC mkCppFile "Test.C" (cpptest cf) - Makefile.mkMakefile opts $ makefile prefix name compileOpt ".l" ".y" + Makefile.mkMakefile opts $ makefile prefix name opts where name :: String name = lang opts @@ -49,8 +50,6 @@ makeCppNoStl opts cf = do -- It should be a valid C identifier. prefix :: String prefix = snakeCase_ name ++ "_" - compileOpt :: String - compileOpt = "--ansi" parserMode :: ParserMode parserMode = CParser True prefix mkCppFile x = mkfile x comment @@ -128,8 +127,7 @@ cpptest cf = unlines $ concat dat = identCat $ normCat cat def = identCat cat -mkHeaderFile :: [Cat] -> String -mkHeaderFile eps = unlines $ concat +mkHeaderFile _cf _cats eps _env = unlines $ concat [ [ "#ifndef PARSER_HEADER_FILE" , "#define PARSER_HEADER_FILE" , "" diff --git a/source/src/BNFC/Backend/CPP/PrettyPrinter.hs b/source/src/BNFC/Backend/CPP/PrettyPrinter.hs index 915a5b6a..c8564d9c 100644 --- a/source/src/BNFC/Backend/CPP/PrettyPrinter.hs +++ b/source/src/BNFC/Backend/CPP/PrettyPrinter.hs @@ -31,16 +31,17 @@ import BNFC.Utils import BNFC.Backend.Common import BNFC.Backend.Common.NamedVariables import BNFC.Backend.Common.StrUtils (renderCharOrString) +import BNFC.Backend.CPP.Common ( CppStdMode(..), wrapUniquePtr, wrapSharedPtrIf, wrapPointerIf ) import BNFC.Backend.CPP.STL.STLUtils import BNFC.PrettyPrint --Produces (.H file, .C file) -cf2CPPPrinter :: Bool -> Maybe String -> CF -> (String, String) -cf2CPPPrinter useStl inPackage cf = - (mkHFile useStl inPackage cf groups, mkCFile useStl inPackage cf groups) - where +cf2CPPPrinter :: CppStdMode -> Bool -> Maybe String -> CF -> String -> (String, String) +cf2CPPPrinter mode useStl inPackage cf hExt = + (mkHFile mode useStl inPackage cf groups hExt, mkCFile mode useStl inPackage cf groups hExt) + where groups = when useStl (positionRules cf) -- CPP/NoSTL treats position tokens as just tokens - ++ fixCoercions (ruleGroupsInternals cf) + ++ fixCoercions (ruleGroupsInternals cf) positionRules :: CF -> [(Cat,[Rule])] positionRules cf = @@ -51,8 +52,8 @@ positionRules cf = {- **** Header (.H) File Methods **** -} --An extremely large function to make the Header File -mkHFile :: Bool -> Maybe String -> CF -> [(Cat,[Rule])] -> String -mkHFile useStl inPackage cf groups = unlines +mkHFile :: CppStdMode -> Bool -> Maybe String -> CF -> [(Cat,[Rule])] -> String -> String +mkHFile mode useStl inPackage cf groups hExt = unlines [ printHeader , content , classFooter @@ -67,7 +68,7 @@ mkHFile useStl inPackage cf groups = unlines "#ifndef " ++ hdef, "#define " ++ hdef, "", - "#include \"Absyn.H\"", + "#include \"Absyn" ++hExt++ "\"", "#include ", "#include ", "#include ", @@ -100,7 +101,7 @@ mkHFile useStl inPackage cf groups = unlines " char *print(Visitable *v);" ] hdef = nsDefine inPackage "PRINTER_HEADER" - content = concatMap (prDataH useStl) groups + content = concatMap (prDataH mode useStl) groups classFooter = unlines $ [ " void visitInteger(Integer i);", @@ -185,53 +186,64 @@ mkHFile useStl inPackage cf groups = unlines ] --Prints all the required method names and their parameters. -prDataH :: Bool -> (Cat, [Rule]) -> String -prDataH useSTL (cat, rules) - | isList cat = unlines $ concat +prDataH :: CppStdMode -> Bool -> (Cat, [Rule]) -> String +prDataH mode useSTL (cat, rules) + | isList cat = unlines $ concat [ [ concat [ " void visit", cl, "(", cl, " *p);" ] ] - , when useSTL - [ concat [ " void iter", cl, "(", itty, " i, ", itty, " j);" ] ] - ] - | otherwise = abstract ++ concatMap prRuleH rules - where - cl = identCat (normCat cat) - itty = concat [ cl, "::", "const_iterator" ] - abstract = case lookupRule (noPosition $ catToStr cat) rules of - Just _ -> "" - Nothing -> " void visit" ++ cl ++ "(" ++ cl ++ " *p); /* abstract class */\n" + , when useSTL + [ concat [ " void iter", cl, "(", itty, " i, ", itty, " j);" ] ] + ] + | otherwise = abstract ++ concatMap prRuleH rules + where + beyondAnsi = case mode of + CppStdBeyondAnsi _ -> True + CppStdAnsi _ -> False + cl = identCat (normCat cat) + vararg = if beyondAnsi then "p" else "*p" + prRuleH = if beyondAnsi then prRuleHBeyondAnsi else prRuleHAnsi + itty = concat [ cl, "::", "const_iterator" ] + abstract = case lookupRule (noPosition $ catToStr cat) rules of + Just _ -> "" + Nothing -> " void visit" ++ cl ++ "(" ++ cl ++ " *p); /* abstract class */\n" --Prints all the methods to visit a rule. -prRuleH :: IsFun f => Rul f -> String -prRuleH (Rule fun _ _ _) | isProperLabel fun = concat +prRuleHAnsi :: IsFun f => Rul f -> String +prRuleHAnsi (Rule fun _ _ _) | isProperLabel fun = concat + [" void visit", funName fun, "(", funName fun, " *p);\n"] +prRuleHAnsi _ = "" + +prRuleHBeyondAnsi :: IsFun f => Rul f -> String +prRuleHBeyondAnsi (Rule fun _ _ _) | isProperLabel fun = concat [" void visit", funName fun, "(", funName fun, " *p);\n"] -prRuleH _ = "" +prRuleHBeyondAnsi _ = "" {- **** Implementation (.C) File Methods **** -} --This makes the .C file by a similar method. -mkCFile :: Bool -> Maybe String -> CF -> [(Cat,[Rule])] -> String -mkCFile useStl inPackage cf groups = concat +mkCFile :: CppStdMode -> Bool -> Maybe String -> CF -> [(Cat,[Rule])] -> String -> String +mkCFile mode useStl inPackage cf groups hExt = concat [ header, nsStart inPackage ++ "\n", prRender useStl, printEntries, - concatMap (prPrintData useStl inPackage cf) groups, + concatMap (prPrintData useStl mode inPackage cf) groups, printBasics, printTokens, showEntries, - concatMap (prShowData useStl) groups, + concatMap (prShowData useStl mode) groups, showBasics, showTokens, nsEnd inPackage ++ "\n" ] where + header = unlines [ "/*** Pretty Printer and Abstract Syntax Viewer ***/", "", "#include ", - "#include \"Printer.H\"", + "#include \"Printer" ++hExt++ "\"", "#define INDENT_WIDTH 2", "" ] @@ -376,33 +388,30 @@ mkCFile useStl inPackage cf groups = concat {- **** Pretty Printer Methods **** -} -- | Generates methods for the Pretty Printer. -prPrintData :: Bool -> Maybe String -> CF -> (Cat, [Rule]) -> String -prPrintData True {- use STL -} _ _ (cat@(ListCat _), rules) = - render $ genPrintVisitorList (cat, rules) -prPrintData False {- use STL -} _ _ (cat@(ListCat _), rules) = - genPrintVisitorListNoStl (cat, rules) --- Not a list : -prPrintData _ _inPackage cf (TokenCat cat, _rules) | isPositionCat cf cat = unlines $ - -- a position token - [ "void PrintAbsyn::visit" ++ cat ++ "(" ++ cat ++ " *p)" - , "{" - , " visitIdent(p->string_);" - , "}" - , "" - ] -prPrintData _ inPackage _cf (cat, rules) = -- Not a list - abstract ++ concatMap (prPrintRule inPackage) rules +prPrintData :: Bool -> CppStdMode -> Maybe String -> CF -> (Cat, [Rule]) -> String +prPrintData True mode _ _ (cat@(ListCat _), rules) = + render $ genPrintVisitorList (mode, cat, rules) +prPrintData False mode _ _ (cat@(ListCat _), rules) = + genPrintVisitorListNoStl (mode, cat, rules) +prPrintData _ mode _inPackage cf (TokenCat cat, _rules) | + isPositionCat cf cat = genPositionToken cat +prPrintData _ mode inPackage _cf (cat, rules) = + abstract ++ concatMap (prPrintRule beyondAnsi inPackage) rules where - cl = identCat (normCat cat) - abstract = case lookupRule (noPosition $ catToStr cat) rules of - Just _ -> "" - Nothing -> "void PrintAbsyn::visit" ++ cl ++ "(" ++ cl +++ "*p) {} //abstract class\n\n" + beyondAnsi = case mode of + CppStdBeyondAnsi _ -> True + CppStdAnsi _ -> False + cl = identCat (normCat cat) + vararg = "*p" + abstract = case lookupRule (noPosition $ catToStr cat) rules of + Just _ -> "" + Nothing -> "void PrintAbsyn::visit" ++ cl ++ "(" ++ cl +++ "*p) {} //abstract class\n\n" -- | Generate pretty printer visitor for a list category (STL version). -- -genPrintVisitorList :: (Cat, [Rule]) -> Doc -genPrintVisitorList (cat@(ListCat _), rules) = vcat - [ "void PrintAbsyn::visit" <> lty <> parens (lty <+> "*" <> vname) +genPrintVisitorList :: (CppStdMode, Cat, [Rule]) -> Doc +genPrintVisitorList (mode, cat@(ListCat _), rules) = vcat + [ "void PrintAbsyn::visit" <> lty <> parens (ltyarg <> "*" <+> varg) , codeblock 2 [ "iter" <> lty <> parens (vname <> "->begin()" <> comma <+> vname <> "->end()") <> semi ] , "" @@ -433,21 +442,36 @@ genPrintVisitorList (cat@(ListCat _), rules) = vcat , "" ] where - cl = identCat (normCat cat) - lty = text cl -- List type - itty = lty <> "::const_iterator" -- Iterator type - vname = text $ map toLower cl - prules = sortRulesByPrecedence rules - swRules f = switchByPrecedence "_i_" $ + beyondAnsi = case mode of + CppStdBeyondAnsi _ -> True + CppStdAnsi _ -> False + cl = identCat (normCat cat) + lty = text cl -- List type + ltyarg = text cl -- List type arg + itty = lty <> "::const_iterator" -- Iterator type + vname = text $ map toLower cl + varg = text $ (map toLower cl) + prules = sortRulesByPrecedence rules + swRules f = switchByPrecedence "_i_" $ map (second $ sep . prListRule_) $ - uniqOn fst $ filter f prules - -- Discard duplicates, can only handle one rule per precedence. - docs0 = swRules isNilFun - docs1 = swRules isOneFun - docs2 = swRules isConsFun + uniqOn fst $ filter f prules + -- Discard duplicates, can only handle one rule per precedence. + docs0 = swRules isNilFun + docs1 = swRules isOneFun + docs2 = swRules isConsFun genPrintVisitorList _ = error "genPrintVisitorList expects a ListCat" +genPositionToken :: String -> String +genPositionToken cat = unlines $ + -- a position token + [ "void PrintAbsyn::visit" ++ cat ++ "(" ++ cat ++ " *p)" + , "{" + , " visitIdent(p->string_);" + , "}" + , "" + ] + -- | Only render the rhs (items) of a list rule. prListRule_ :: IsFun a => Rul a -> [Doc] @@ -464,8 +488,8 @@ prListRule_ (Rule _ _ items _) = for items $ \case -- This is the only part of the pretty printer that differs significantly -- between the versions with and without STL. -- The present version has been adapted from CFtoCPrinter. -genPrintVisitorListNoStl :: (Cat, [Rule]) -> String -genPrintVisitorListNoStl (cat@(ListCat _), rules) = unlines $ concat +genPrintVisitorListNoStl :: (CppStdMode, Cat, [Rule]) -> String +genPrintVisitorListNoStl (mode, cat@(ListCat _), rules) = unlines $ concat [ [ "void PrintAbsyn::visit" ++ cl ++ "("++ cl ++ " *" ++ vname ++ ")" , "{" , " if (" ++ vname +++ "== 0)" @@ -491,20 +515,24 @@ genPrintVisitorListNoStl (cat@(ListCat _), rules) = unlines $ concat ] ] where - cl = identCat (normCat cat) - vname = map toLower cl - pre = vname ++ "->" - prules = sortRulesByPrecedence rules - swRules f = switchByPrecedence "_i_" $ + beyondAnsi = case mode of + CppStdBeyondAnsi _ -> True + CppStdAnsi _ -> False + cl = identCat (normCat cat) + vname = map toLower cl + varg = map toLower cl + pre = vname ++ "->" + prules = sortRulesByPrecedence rules + swRules f = switchByPrecedence "_i_" $ map (second $ sep . map text . prPrintRule_ pre) $ - uniqOn fst $ filter f prules - -- Discard duplicates, can only handle one rule per precedence. + uniqOn fst $ filter f prules + -- Discard duplicates, can only handle one rule per precedence. genPrintVisitorListNoStl _ = error "genPrintVisitorListNoStl expects a ListCat" --Pretty Printer methods for a rule. -prPrintRule :: Maybe String -> Rule -> String -prPrintRule inPackage r@(Rule fun _ _ _) | isProperLabel fun = unlines $ concat - [ [ "void PrintAbsyn::visit" ++ funName fun ++ "(" ++ funName fun +++ "*" ++ fnm ++ ")" +prPrintRule :: Bool -> Maybe String -> Rule -> String +prPrintRule beyondAnsi inPackage r@(Rule fun _ _ _) | isProperLabel fun = unlines $ concat + [ [ "void PrintAbsyn::visit" ++ visitFunName ++ "(" ++ vararg +++ fnm ++ ")" , "{" , " int oldi = _i_;" , parenCode "_L_PAREN" @@ -519,32 +547,33 @@ prPrintRule inPackage r@(Rule fun _ _ _) | isProperLabel fun = unlines $ concat ] ] where - p = precRule r - parenCode x = " if (oldi > " ++ show p ++ ") render(" ++ nsDefine inPackage x ++ ");" - fnm = "p" --old names could cause conflicts -prPrintRule _ _ = "" + visitFunName = funName fun + vararg = funName fun ++ "*" + p = precRule r + parenCode x = " if (oldi > " ++ show p ++ ") render(" ++ nsDefine inPackage x ++ ");" + fnm = "p" --old names could cause conflicts + +prPrintRule _ _ _ = "" prPrintRule_ :: IsFun a => String -> Rul a -> [String] prPrintRule_ pre (Rule _ _ items _) = map (prPrintItem pre) $ numVars items --This goes on to recurse to the instance variables. prPrintItem :: String -> Either (Cat, Doc) String -> String -prPrintItem _ (Right t) = " render(" ++ snd (renderCharOrString t) ++ ");" +prPrintItem _ (Right t) = " render(" ++ snd (renderCharOrString t) ++ ");" prPrintItem pre (Left (c, nt)) - | Just t <- maybeTokenCat c - = " visit" ++ t ++ "(" ++ pre ++ s ++ ");" - | isList c = " " ++ setI (precCat c) ++ - "visit" ++ elt ++ "(" ++ pre ++ s ++ ");" - | otherwise = " " ++ setI (precCat c) ++ pre ++ s ++ "->accept(this);" + | Just t <- maybeTokenCat c = " visit" ++ t ++ "(" ++ pre ++ s ++ ");" + | isList c = " " ++ setI (precCat c) ++ "visit" ++ elt ++ "(" ++ pre ++ s ++ ".get());" -- TODO: shared_ptr.get is only beyondAnsi + | otherwise = " " ++ setI (precCat c) ++ pre ++ s ++ "->accept(this);" where - s = render nt - elt = identCat $ normCat c + s = render nt + elt = identCat $ normCat c {- **** Abstract Syntax Tree Printer **** -} --This prints the functions for Abstract Syntax tree printing. -prShowData :: Bool -> (Cat, [Rule]) -> String -prShowData True (cat@(ListCat c), _) = unlines +prShowData :: Bool -> CppStdMode -> (Cat, [Rule]) -> String +prShowData True mode (cat@(ListCat c), _) = unlines [ "void ShowAbsyn::visit" ++ cl ++ "("++ cl ++ " *" ++ vname ++ ")", "{", @@ -560,9 +589,14 @@ prShowData True (cat@(ListCat c), _) = unlines "" ] where - cl = identCat (normCat cat) + beyondAnsi = case mode of + CppStdBeyondAnsi _ -> True + CppStdAnsi _ -> False + cl = identCat (normCat cat) vname = map toLower cl -prShowData False (cat@(ListCat c), _) = + varg = vname + +prShowData False mode (cat@(ListCat c), _) = unlines [ "void ShowAbsyn::visit" ++ cl ++ "("++ cl ++ " *" ++ vname ++ ")", @@ -585,38 +619,48 @@ prShowData False (cat@(ListCat c), _) = "" ] where - cl = identCat (normCat cat) - ecl = identCat (normCatOfList cat) - vname = map toLower cl + beyondAnsi = case mode of + CppStdBeyondAnsi _ -> True + CppStdAnsi _ -> False + cl = identCat (normCat cat) + ecl = identCat (normCatOfList cat) + vname = map toLower cl + varg = vname member = map toLower ecl ++ "_" visitMember | Just t <- maybeTokenCat c = " visit" ++ t ++ "(" ++ vname ++ "->" ++ member ++ ");" | otherwise = " " ++ vname ++ "->" ++ member ++ "->accept(this);" -prShowData _ (cat, rules) = --Not a list: - abstract ++ concatMap prShowRule rules + +prShowData _ mode (cat, rules) = --Not a list: + abstract ++ unlines [prShowRule rule beyondAnsi | rule <- rules] where + beyondAnsi = case mode of + CppStdBeyondAnsi _ -> True + CppStdAnsi _ -> False cl = identCat (normCat cat) + varg = "p" abstract = case lookupRule (noPosition $ catToStr cat) rules of Just _ -> "" - Nothing -> "void ShowAbsyn::visit" ++ cl ++ "(" ++ cl ++ " *p) {} //abstract class\n\n" + Nothing -> "void ShowAbsyn::visit" ++ cl ++ "(" ++ cl ++ " *p) {} //abstract class\n\n" --This prints all the methods for Abstract Syntax tree rules. -prShowRule :: IsFun f => Rul f -> String -prShowRule (Rule f _ cats _) | isProperLabel f = concat +prShowRule :: IsFun f => Rul f -> Bool -> String +prShowRule (Rule f _ cats _) beyondAnsi | isProperLabel f = concat [ - "void ShowAbsyn::visit" ++ fun ++ "(" ++ fun +++ "*" ++ fnm ++ ")\n", - "{\n", - lparen, - " bufAppend(\"" ++ fun ++ "\");\n", - optspace, - cats', - rparen, - "}\n" + "void ShowAbsyn::visit" ++ fun ++ "(" ++ vararg +++ fnm ++ ")\n", + "{\n", + lparen, + " bufAppend(\"" ++ fun ++ "\");\n", + optspace, + cats', + rparen, + "}\n" ] - where + where fun = funName f + vararg = funName fun ++ "*" (optspace, lparen, rparen, cats') | null [ () | Left _ <- cats ] -- @all isRight cats@, but Data.Either.isRight requires base >= 4.7 = ("", "", "", "") @@ -628,7 +672,8 @@ prShowRule (Rule f _ cats _) | isProperLabel f = concat then insertSpaces xs else x : " bufAppend(' ');\n" : insertSpaces xs fnm = "p" --other names could cause conflicts -prShowRule _ = "" + +prShowRule _ _ = "" -- This recurses to the instance variables of a class. prShowCat :: String -> Either (Cat, Doc) String -> String diff --git a/source/src/BNFC/Backend/CPP/STL.hs b/source/src/BNFC/Backend/CPP/STL.hs index 22acac8d..13c8e37f 100644 --- a/source/src/BNFC/Backend/CPP/STL.hs +++ b/source/src/BNFC/Backend/CPP/STL.hs @@ -10,15 +10,19 @@ module BNFC.Backend.CPP.STL (makeCppStl,) where import Data.Foldable (toList) +import Data.List ( nub ) +import qualified Data.Map as Map +import Data.Maybe ( fromMaybe ) import BNFC.Utils import BNFC.CF import BNFC.Options +import BNFC.PrettyPrint 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.C.CFtoBisonC ( cf2Bison, unionBuiltinTokens, positionCats, varName ) +import BNFC.Backend.C.CFtoFlexC ( cf2flex, ParserMode(..), beyondAnsi, parserPackage, parserName, stlParser ) +import BNFC.Backend.CPP.Common ( commentWithEmacsModeHint, wrapSharedPtr, CppStdMode(..) ) import BNFC.Backend.CPP.Makefile import BNFC.Backend.CPP.STL.CFtoSTLAbs import BNFC.Backend.CPP.STL.CFtoCVisitSkelSTL @@ -28,25 +32,35 @@ import qualified BNFC.Backend.Common.Makefile as Makefile makeCppStl :: SharedOptions -> CF -> MkFiles () makeCppStl opts cf = do - let (hfile, cfile) = cf2CPPAbs (linenumbers opts) cppStdMode (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 ++ lexerExt) flex - mkCppFileWithHint (name ++ parserExt) $ 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 compileOpt lexerExt parserExt + let (hfile, cfile) = cf2CPPAbs (linenumbers opts) cppStdMode (inPackage opts) name cf + mkCppFile ("Absyn" ++ hExt) hfile + mkCppFile ("Absyn" ++ cppExt) cfile + mkCppFile ("Buffer" ++ hExt) bufferH + mkCppFile ("Buffer" ++ cppExt) $ bufferC ("Buffer" ++ hExt) + -- Generate xxx.ll file + let (flex, env) = cf2flex parserMode cf + mkCppFileWithHint (name ++ lexerExt) flex + -- Generate xxx.yy file + mkCppFileWithHint (name ++ parserExt) $ cf2Bison (linenumbers opts) parserMode cf env + mkCppFile ("Parser" ++ hExt) $ + mkHeaderFile hExt (inPackage opts) cf (allParserCats cf) (toList $ allEntryPoints cf) (Map.elems env) + mkCppFile ("ParserError" ++ hExt) $ printParseErrHeader (inPackage opts) + let (skelH, skelC) = cf2CVisitSkel opts True (inPackage opts) cf + mkCppFile ("Skeleton" ++ hExt) skelH + mkCppFile ("Skeleton" ++ cppExt) skelC + let (prinH, prinC) = cf2CPPPrinter cppStdMode True (inPackage opts) cf hExt + mkCppFile ("Printer" ++ hExt) prinH + mkCppFile ("Printer" ++ cppExt) prinC + mkCppFile ("Test" ++ cppExt) (cpptest parserMode (inPackage opts) cf hExt) + + case (ansi opts) of + BeyondAnsi -> do + mkCppFile ("Driver" ++ cppExt) $ driverC parserMode cf ("Driver" ++ hExt) + mkCppFile ("Driver" ++ hExt) $ driverH parserMode cf cats + mkCppFile ("Scanner" ++ hExt) $ scannerH parserMode; + _ -> + return(); + Makefile.mkMakefile opts $ makefile prefix name opts where name :: String name = lang opts @@ -55,24 +69,22 @@ makeCppStl opts cf = do -- It should be a valid C identifier. prefix :: String prefix = snakeCase_ name ++ "_" - -- Compile option used by Makefile - compileOpt :: String - compileOpt = if Ansi == ansi opts then "--ansi" else "-std=c++14" - lexerExt :: String - lexerExt = if Ansi == ansi opts then ".l" else ".ll" - parserExt :: String - parserExt = if Ansi == ansi opts then ".y" else ".yy" - parserMode :: ParserMode parserMode = CppParser (inPackage opts) prefix (ansi opts) mkCppFile x = mkfile x comment mkCppFileWithHint x = mkfile x commentWithEmacsModeHint -- Switch C++ generator module cppStdMode :: CppStdMode - cppStdMode = if Ansi == ansi opts then - CppStdAnsi (ansi opts) - else - CppStdBeyondAnsi (ansi opts) + cppStdMode = if Ansi == ansi opts then CppStdAnsi (ansi opts) else CppStdBeyondAnsi (ansi opts) + lexerExt = if Ansi == ansi opts then ".l" else ".ll" + parserExt = if Ansi == ansi opts then ".y" else ".yy" + cppExt = if Ansi == ansi opts then ".c" else ".cc" + hExt = if Ansi == ansi opts then ".h" else ".hh" + posCats + | stlParser parserMode = map TokenCat $ positionCats cf + | otherwise = [] + cats = posCats ++ allParserCatsNorm cf + printParseErrHeader :: Maybe String -> String printParseErrHeader inPackage = @@ -98,79 +110,108 @@ printParseErrHeader inPackage = , nsEnd inPackage ] -cpptest :: Maybe String -> CF -> String -cpptest inPackage cf = unlines $ concat +cpptest :: ParserMode -> Maybe String -> CF -> String -> String +cpptest mode inPackage cf hExt = unlines $ concat [ testfileHeader - , [ "", - "#include ", - "#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 ++ "std::unique_ptr " ++ scope ++ "s(new ShowAbsyn());", - " printf(\"%s\\n\\n\", s->show(parse_tree));", - " printf(\"[Linearized Tree]\\n\");", - " " ++ scope ++ "std::unique_ptr " ++ scope ++ "p(new PrintAbsyn());", - " printf(\"%s\\n\\n\", p->print(parse_tree));", - " }", - " delete(parse_tree);", - " return 0;", - " }", - " return 1;", - "}", - "" + , [ "" + , "#include " + , "#include " + , "#include " + , if beyondAnsi mode then + unlines [ + "#include " + , "#include \"Driver" ++hExt++ "\"" + ] + else + "#include \"Parser" ++hExt++ "\"" + , "#include \"Printer" ++hExt++ "\"" + , "#include \"Absyn" ++hExt++ "\"" + , "#include \"ParserError" ++hExt++ "\"" + , "" + , "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;" + , "" + , if beyondAnsi mode then + unlines [ + " /* The default entry point is used. For other options see Parser.H */" + , " " ++ (wrapSharedPtr $ scope ++ dat) ++ " parse_tree = nullptr;" + , " try { " + , " auto driver = std::make_unique<" ++ns++ "::" ++camelCaseName++ "Driver>();" + , " parse_tree = driver->p" ++ def ++ "(filename);" + ] + else + unlines [ + " /* 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 beyondAnsi mode then + unlines [ + " if (!quiet) {" + , " printf(\"\\n[Abstract Syntax]\\n\");" + , " auto s = std::make_unique<" ++ scope ++ "ShowAbsyn>(" ++ scope ++ "ShowAbsyn());" + , " printf(\"%s\\n\\n\", s->show(parse_tree.get()));" + , " printf(\"[Linearized Tree]\\n\");" + , " auto p = std::make_unique<" ++ scope ++ "PrintAbsyn>(" ++ scope ++ "PrintAbsyn());" + , " printf(\"%s\\n\\n\", p->print(parse_tree.get()));" + , " }" + ] + else + unlines [ + " 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 @@ -178,16 +219,20 @@ cpptest inPackage cf = unlines $ concat dat = identCat $ normCat cat def = identCat cat scope = nsScope inPackage + name = parserName mode + camelCaseName = camelCase_ name + ns = fromMaybe camelCaseName (parserPackage mode) + -mkHeaderFile :: Maybe String -> [Cat] -> String -mkHeaderFile inPackage eps = unlines $ concat +mkHeaderFile hExt inPackage _cf _cats eps _env = unlines $ concat [ [ "#ifndef " ++ hdef , "#define " ++ hdef , "" - , "#include" - , "#include" - , "#include" - , "#include \"Absyn.H\"" + , "#include " + , "#include " + , "#include " + , "#include \"Bison" ++ hExt ++ "\"" + , "#include \"Absyn" ++ hExt ++ "\"" , "" , nsStart inPackage ] @@ -203,3 +248,254 @@ mkHeaderFile inPackage eps = unlines $ concat [ identCat (normCat s) ++ "*" +++ "p" ++ identCat s ++ "(FILE *inp);" , identCat (normCat s) ++ "*" +++ "ps" ++ identCat s ++ "(const char *str);" ] + + +-- | C++ lexer/parser driver + +driverH :: ParserMode -> CF -> [Cat] -> String +driverH mode cf cats = unlines + [ "#ifndef __DRIVER_H__" + , "#define __DRIVER_H__ 1" + + , "#include " + , "#include " + , "#include " + , "#include " + , "" + , "#include \"Scanner.hh\"" + , "#include \"Parser.hh\"" + , "" + , "namespace " ++ns++ "{" + , "" + , "class " ++camelCaseName++ "Driver{" + , "public:" + , " " ++camelCaseName++ "Driver() = default;" + , " virtual ~ " ++camelCaseName++ "Driver();" + , "" + , " /**" + , " * parser parsed values defined by bnfc" + , " */" + -- bnfc builtin tokens + , unlines [ prettyShow (" " ++ tok) | tok <- unionBuiltinTokens ] + -- user defined tokens + , unlines [ prettyShow (" std::shared_ptr<" ++ identCat tok ++ ">"+++ varName tok ++";") | tok <- normCats ] + , "" + , unlines [ mkFileEntry ep | ep <- entryPoints ] + , unlines [ mkStringEntry ep | ep <- entryPoints ] + , "" + , " /**" + , " * parse - parse from a file" + , " * @param filename - valid string with input file" + , " */" + , " void parse(const char *filename);" + , " /**" + , " * parse - parse from a c++ input stream" + , " * @param is - std::istream&, valid input stream" + , " */" + , " void parse(std::istream &iss);" + , " /** Error handling with associated line number. This can be modified to" + , " * output the error. */" + , " void error(const class location& l, const std::string& m);" + , "" + , " std::ostream& print(std::ostream &stream);" + , "" + , " // debug flags" + , " bool trace_scanning = false;" + , " bool trace_parsing = false;" + , "" + , "private:" + , "" + , " void parse_helper( std::istream &stream );" + , "" + , " std::unique_ptr<" ++camelCaseName++ "Scanner> scanner = nullptr;" + , " std::unique_ptr<" ++camelCaseName++ "Parser> parser = nullptr;" + , "};" + , "" + , "} /* end namespace " ++ns++ " */" + , "#endif /* END __DRIVER_H__ */" + ] + where + name = parserName mode + camelCaseName = camelCase_ name + ns = fromMaybe camelCaseName (parserPackage mode) + normCats = nub (map normCat cats) + entryPoints = toList (allEntryPoints cf) + mkFileEntry s = + " " ++ (wrapSharedPtr $ identCat (normCat s)) +++ "p" ++ identCat s ++ "(const char *filename);" + mkStringEntry s = + " " ++ (wrapSharedPtr $ identCat (normCat s)) +++ "ps" ++ identCat s ++ "(std::istream &stream);" + + +-- | C++ lexer/parser driver + +driverC :: ParserMode -> CF -> String -> String +driverC mode cf driverH = unlines + [ "#include " + , "#include " + , "#include " + , " " + , "#include \"Driver.hh\"" + , " " + , "" ++ns++ "::" ++camelCaseName++ "Driver::~" ++camelCaseName++ "Driver()" + , "{" + , "}" + , " " + , "void " + , ns++ "::" ++camelCaseName++ "Driver::parse( const char * const filename )" + , "{" + , " /**" + , " * Remember, if you want to have checks in release mode" + , " * then this needs to be an if statement " + , " */" + , " assert( filename != nullptr );" + , " std::ifstream in_file( filename );" + , " if( ! in_file.good() )" + , " {" + , " exit( EXIT_FAILURE );" + , " }" + , " parse_helper( in_file );" + , " return;" + , "}" + , " " + , "void" + , ns++ "::" ++camelCaseName++ "Driver::parse( std::istream &stream )" + , "{" + , " if( ! stream.good() && stream.eof() ) {" + , " return;" + , " }" + , " parse_helper( stream ); " + , " return;" + , "}" + , " " + , "void" + , ns++ "::" ++camelCaseName++ "Driver::error( const class location& l, const std::string& m )" + , "{" + , " std::cerr << l << \": \" << m << std::endl;" + , "}" + , " " + , "void " + , ns++ "::" ++camelCaseName++ "Driver::parse_helper( std::istream &stream )" + , "{" + , "" + , " scanner.reset();" + , " try {" + , " scanner = std::make_unique<" ++ns++ "::" ++camelCaseName++ "Scanner>( &stream );" + , " scanner->set_debug(trace_scanning);" + , " } catch( std::bad_alloc &ba ) {" + , " std::cerr << \"Failed to allocate scanner: (\"" + , " << ba.what() " + , " << \"), exiting!!\\n\";" + , " exit( EXIT_FAILURE );" + , " }" + , "" + , " parser.reset(); " + , " try {" + , " parser = std::make_unique<" ++ns++ "::" ++camelCaseName++ "Parser>((*scanner), (*this));" + , " } catch( std::bad_alloc &ba ) {" + , " std::cerr << \"Failed to allocate parser: (\"" + , " << ba.what() " + , " << \"), exiting!!\\n\";" + , " exit( EXIT_FAILURE );" + , " }" + , " const int accept( 0 );" + , "" + , " parser->set_debug_level (trace_parsing);" + , " if( parser->parse() != accept ) {" + , " std::cerr << \"Parse failed!!\\n\";" + , " }" + , " return;" + , "}" + , "" + , unlines [ mkFileEntry ep | ep <- entryPoints ] + , unlines [ mkStringEntry ep | ep <- entryPoints ] + ] + where + name = parserName mode + camelCaseName = camelCase_ name + ns = fromMaybe camelCaseName (parserPackage mode) + entryPoints = toList (allEntryPoints cf) + mkFileEntry s = + unlines [ + (wrapSharedPtr $ identCat (normCat s)) + , ns++ "::" ++camelCaseName++ "Driver::p" ++ identCat s ++ "(const char *filename)" + , "{" + , " assert( filename != nullptr );" + , " std::ifstream in_file( filename );" + , " if( ! in_file.good() )" + , " {" + , " exit( EXIT_FAILURE );" + , " }" + , " parse_helper( in_file );" + , " return this->" ++ varName s++ ";" + , "}" + ] + mkStringEntry s = + unlines [ + (wrapSharedPtr $ identCat (normCat s)) + , ns++ "::" ++camelCaseName++ "Driver::ps" ++ identCat s ++ "(std::istream &stream)" + , "{" + , " if( ! stream.good() && stream.eof() ) {" + , " return nullptr;" + , " }" + , " parse_helper( stream );" + , " return this->" ++ varName s++ ";" + , "}" + ] + +-- | C++ lexer def + +scannerH :: ParserMode -> String +scannerH mode = unlines + [ "#ifndef __SCANNER_H__" + , "#define __SCANNER_H__ 1" + , "" + , "// Flex expects the signature of yylex to be defined in the macro YY_DECL, and" + , "// the C++ parser expects it to be declared." + , "#ifndef YY_DECL" + , "#define YY_DECL \\" + , " int \\" + , " " ++ns++ "::" ++camelCaseName++ "Scanner::lex( \\" + , " " ++ns++ "::" ++camelCaseName++ "Parser::semantic_type* const yylval, \\" + , " " ++ns++ "::" ++camelCaseName++ "Parser::location_type* yylloc \\" + , " )" + , "#endif" + , "" + , "#ifndef __FLEX_LEXER_H" + , "#define yyFlexLexer BnfcFlexLexer" -- This name is dummy + , "#include \"FlexLexer.h\"" + , "#undef yyFlexLexer" + , "#endif" + , "" + , "#include \"Bison.hh\"" + , "#include \"location.hh\"" + , "" + , "namespace " ++ns++ "{" + , "" + , "class " ++camelCaseName++ "Scanner : public BnfcFlexLexer {" + , "public:" + , "" + , " " ++camelCaseName++ "Scanner(std::istream *in);" + , " virtual ~" ++camelCaseName++ "Scanner();" + , "" + , " virtual" + , " int lex( " ++ns++ "::" ++camelCaseName++ "Parser::semantic_type * const lval," + , " " ++ns++ "::" ++camelCaseName++ "Parser::location_type *location );" + , " // YY_DECL defined in mc_lexer.l" + , " // Method body created by flex in mc_lexer.yy.cc" + , "" + , "" + , "private:" + , " /* yyval ptr */" + , " " ++ns++ "::" ++camelCaseName++ "Parser::semantic_type *yylval = nullptr;" + , " /* location ptr */" + , " " ++ns++ "::" ++camelCaseName++ "Parser::location_type *loc = nullptr;" + , "};" + , "" + , "} /* end namespace " ++ns++ " */" + , "" + , "#endif /* END __SCANNER_H__ */" + ] + where + name = parserName mode + camelCaseName = camelCase_ name + ns = fromMaybe camelCaseName (parserPackage mode) diff --git a/source/src/BNFC/Backend/CPP/STL/CFtoCVisitSkelSTL.hs b/source/src/BNFC/Backend/CPP/STL/CFtoCVisitSkelSTL.hs index c663928f..2651c875 100644 --- a/source/src/BNFC/Backend/CPP/STL/CFtoCVisitSkelSTL.hs +++ b/source/src/BNFC/Backend/CPP/STL/CFtoCVisitSkelSTL.hs @@ -17,30 +17,32 @@ module BNFC.Backend.CPP.STL.CFtoCVisitSkelSTL (cf2CVisitSkel) where import Data.Char import BNFC.CF +import BNFC.Options import BNFC.Utils ((+++), unless) import BNFC.Backend.Common.OOAbstract import BNFC.Backend.CPP.Naming import BNFC.Backend.CPP.STL.STLUtils --Produces (.H file, .C file) -cf2CVisitSkel :: Bool -> Maybe String -> CF -> (String, String) -cf2CVisitSkel useSTL inPackage cf = - ( mkHFile useSTL inPackage cab - , mkCFile useSTL inPackage cab +cf2CVisitSkel :: SharedOptions -> Bool -> Maybe String -> CF -> (String, String) +cf2CVisitSkel opts useSTL inPackage cf = + ( mkHFile useSTL hExt inPackage cab + , mkCFile useSTL hExt inPackage cab ) where - cab = cf2cabs cf + cab = cf2cabs cf + hExt = if Ansi == ansi opts then ".h" else ".hh" -- **** Header (.H) File Functions **** --Generates the Header File -mkHFile :: Bool -> Maybe String -> CAbs -> String -mkHFile useSTL inPackage cf = unlines [ +mkHFile :: Bool -> String -> Maybe String -> CAbs -> String +mkHFile useSTL hExt inPackage cf = unlines [ "#ifndef " ++ hdef, "#define " ++ hdef, "/* You might want to change the above name. */", "", - "#include \"Absyn.H\"", + "#include \"Absyn" ++hExt++ "\"", "", nsStart inPackage, "class Skeleton : public Visitor", @@ -70,17 +72,16 @@ basics useSTL cf = concat -- **** Implementation (.C) File Functions **** --Makes the .C File -mkCFile :: Bool -> Maybe String -> CAbs -> String -mkCFile useSTL inPackage cf = unlines [ - headerC, +mkCFile :: Bool -> String -> Maybe String -> CAbs -> String +mkCFile useSTL hExt inPackage cf = unlines [ + headerC hExt, nsStart inPackage, unlines [ - "void Skeleton::visit" ++ t ++ "(" ++ - t ++ " *t) {} //abstract class" | t <- absclasses cf], - unlines [ prCon r | (_,rs) <- signatures cf, r <- rs, useSTL || not (posRule r) ], - unlines [ prList useSTL cb | cb <- listtypes cf ], - unlines [ prBasic b | b <- base ], - nsEnd inPackage + "void Skeleton::visit" ++ t ++ "(" ++ t ++ " *t) {} //abstract class" | t <- absclasses cf], + unlines [ prCon r | (_,rs) <- signatures cf, r <- rs, useSTL || not (posRule r) ], + unlines [ prList useSTL cb | cb <- listtypes cf ], + unlines [ prBasic b | b <- base ], + nsEnd inPackage ] where -- See OOAbstract 'posdata': @@ -102,19 +103,17 @@ mkCFile useSTL inPackage cf = unlines [ | otherwise = "visit" ++ cat ++ "(" ++ field ++ ");" where field = v ++ "->" ++ var -headerC :: String -headerC = unlines [ +headerC hExt = unlines [ "/*** Visitor Design Pattern Skeleton. ***/", "/* This implements the common visitor design pattern.", " Note that this method uses Visitor-traversal of lists, so", " List->accept() does NOT traverse the list. This allows different", " algorithms to use context information differently. */", "", - "#include \"Skeleton.H\"", + "#include \"Skeleton" ++hExt++ "\"", "" ] -prBasic :: String -> String prBasic c = unlines [ "void Skeleton::visit" ++ c ++ "(" ++ c ++ " x)", "{", @@ -122,7 +121,6 @@ prBasic c = unlines [ "}" ] -prList :: Bool -> (String, Bool) -> String prList True (cl,b) = unlines [ "void Skeleton::visit" ++ cl ++ "("++ cl +++ "*" ++ vname ++ ")", "{", diff --git a/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs b/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs index 9c2b35db..ec76e4a8 100644 --- a/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs +++ b/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs @@ -31,9 +31,6 @@ import BNFC.Utils ( (+++), applyWhen ) import BNFC.Backend.CPP.Common import BNFC.Backend.CPP.STL.STLUtils -data CppStdMode - = CppStdAnsi Ansi -- ^ @Ansi@ mode. - | CppStdBeyondAnsi Ansi -- ^ @BeyondAnsi@ mode. --The result is two files (.H file, .C file) @@ -93,7 +90,7 @@ mkHFile rp mode inPackage cabs cf = unlines }, "", "/******************** Visitor Interfaces ********************/", - prVisitor cabs, + prVisitor mode cabs, "", prVisitable, "", @@ -127,20 +124,21 @@ prVisitable = unlines [ "};" ] -prVisitor :: CAbs -> String -prVisitor cf = unlines [ +prVisitor :: CppStdMode -> CAbs -> String +prVisitor mode cf = unlines [ "class Visitor", "{", "public:", " virtual ~Visitor() {}", unlines - [" virtual void visit"++c++"("++c++" *p) = 0;" | c <- allClasses cf, - notElem c (defineds cf)], + [" virtual void visit"++c++"("++ c +++ vararg ++") = 0;" | c <- allClasses cf, notElem c (defineds cf)], "", unlines - [" virtual void visit"++c++"(" ++c++" x) = 0;" | c <- allNonClasses cf], + [" virtual void visit"++c++"("++c++" x) = 0;" | c <- allNonClasses cf], "};" - ] + ] + where + vararg = "*p" prAbs :: CppStdMode -> RecordPositions -> String -> String prAbs mode rp c = @@ -157,7 +155,7 @@ prAbs mode rp c = "class " ++ c ++ " : public Visitable", "{", "public:", - " virtual std::unique_ptr<" ++ c ++ "> clone() const = 0;", + " virtual" +++ wrapSharedPtr c +++ "clone() const = 0;", if rp == RecordPositions then " int line_number, char_number;" else "", "};" ]; @@ -185,9 +183,8 @@ prCon mode (c,(f,cs)) = CppStdBeyondAnsi _ -> unlines [ "class " ++f++ " : public " ++ c, "{", - "private:", - unlines [" std::unique_ptr<" ++ typ ++ "> " ++ var ++ ";" | (typ,_,var) <- cs], "public:", + unlines [" " ++ wrapSharedPtrIf isClass typ +++ var ++ ";" | (typ,isClass,var) <- cs], -- "right-hand side" operations; for move " " ++ f ++ "(" ++ f ++ "&& rhs);", " " ++ f ++ "& operator=(" ++ f ++ "&& rhs);", @@ -196,7 +193,7 @@ prCon mode (c,(f,cs)) = " " ++ f ++ "(" ++ conargs ++ ");", " ~" ++f ++ "();", " virtual void accept(Visitor *v);", - " std::unique_ptr<" ++c++ "> clone() const override;", + " " ++ wrapSharedPtr c +++ " clone() const override;", "};" ]; } @@ -209,7 +206,7 @@ prCon mode (c,(f,cs)) = ; CppStdBeyondAnsi _ -> concat $ intersperse ", " - ["const" +++ x ++ "& p" ++ show i | ((x,_,_),i) <- zip cs [1..]] + [wrapSharedPtrIf isClass x ++ "& p" ++ show i | ((x,isClass,_),i) <- zip cs [1..]] ; } @@ -230,22 +227,35 @@ prList mode (c, b) = case mode of { "class " ++c++ " : public Visitable" , "{" , "public:" - , " std::vector>" +++ "list" ++ map toLower childClass ++ "_;" + , " std::vector<" ++ wrapSharedPtr childClass++ ">" +++ childClassVarName ++ ";" + , "" + -- ref: https://stackoverflow.com/questions/51148797/how-can-i-define-iterator-and-const-iterator-in-my-class-while-i-uses-stdvecto + , " // define iterator and const_iterator, expose it" + , " using iterator = typename std::vector<" ++ wrapSharedPtr childClass ++ ">::iterator;" + , " using const_iterator = typename std::vector<" ++ wrapSharedPtr childClass++ ">::const_iterator;" + , " auto begin() const { return " ++childClassVarName++ ".begin(); }" + , " auto begin() { return " ++childClassVarName++ ".begin(); }" + , " auto end() const { return " ++childClassVarName++ ".end(); }" + , " auto end() { return " ++childClassVarName++ ".end(); }" , "" -- "right-hand side" operations; for move , " " ++ c ++ "(" ++ c ++ "&& rhs);" , " " ++ c ++ "& operator=(" ++ c ++ "&& rhs);" , " " ++ c ++ "(const" +++ c ++ "& rhs);" , " " ++ c ++ "& operator=(const" +++ c ++ "& rhs);" + , " " ++ c ++ "();" , " ~" ++ c ++ "();" , " virtual void accept(Visitor *v);" - , " std::unique_ptr<" ++ c ++ "> clone() const;" + , " " ++ wrapSharedPtr c +++ " clone() const;" + , " void cons(" ++ wrapSharedPtr childClass ++ ");" + , " void reverse();" , "};" , "" ]; } where childClass = drop 4 c + childClassVarName = "list" ++ map toLower childClass ++ "_" bas = applyWhen b (++ "*") $ drop 4 c {- drop "List" -} @@ -257,7 +267,7 @@ mkCFile mode inPackage cabs cf = unlines $ [ "#include ", "#include ", "#include ", - "#include \"Absyn.H\"", + "#include \"Absyn"++hExt++"\"", nsStart inPackage, unlines [prConC mode c r | (c,rs) <- signatures cabs, r <- rs], unlines [prListC mode l | l <- listtypes cabs], @@ -268,6 +278,9 @@ mkCFile mode inPackage cabs cf = unlines $ [ where nil t = (,dummyType) $ concat [ "new List", identType t, "()" ] cons t = (,dummyType) $ concat [ "consList", identType t ] + hExt = case mode of + CppStdAnsi _ -> ".h"; + CppStdBeyondAnsi _ -> ".hh"; prConC :: CppStdMode -> String -> CAbsRule -> String @@ -276,7 +289,7 @@ prConC mode c fcs@(f,_) = unlines [ prConstructorC mode fcs, prCopyC mode fcs, prDestructorC mode fcs, - prAcceptC f, + prAcceptC mode f, prCloneC mode c f, "" ] @@ -285,6 +298,8 @@ prListC :: CppStdMode -> (String,Bool) -> String prListC mode (c,b) = unlines [ "/******************** " ++ c ++ " ********************/" , case mode of { + CppStdAnsi _ -> [] + ; CppStdBeyondAnsi _ -> unlines [ c ++ "::" ++ c ++ "(" ++ c ++ "&& rhs) = default;", "", @@ -307,10 +322,11 @@ prListC mode (c,b) = unlines " return *this;", "}", "", + c ++ "::" ++ c ++"() = default;", c ++ "::~" ++ c ++"() = default;", ""]; } - , prAcceptC c + , prAcceptC mode c , prCloneC mode c c , prConsC mode c b ] @@ -319,13 +335,21 @@ prListC mode (c,b) = unlines --The standard accept function for the Visitor pattern -prAcceptC :: String -> String -prAcceptC ty = unlines [ - "void " ++ ty ++ "::accept(Visitor *v)", - "{", - " v->visit" ++ ty ++ "(this);", - "}" - ] +prAcceptC :: CppStdMode -> String -> String +prAcceptC mode ty = case mode of { + CppStdAnsi _ -> unlines [ + "void " ++ ty ++ "::accept(Visitor *v)", + "{", + " v->visit" ++ ty ++ "(this);", + "}" + ]; + CppStdBeyondAnsi _ -> unlines [ + "void " ++ty++ "::accept(Visitor *v)", + "{", + " v->visit" ++ ty ++ "(this);", + "}" + ]; + } --The cloner makes a new deep copy of the object prCloneC :: CppStdMode -> String -> String -> String @@ -337,9 +361,9 @@ prCloneC mode f c = case mode of { "}" ]; CppStdBeyondAnsi _ -> unlines [ - "std::unique_ptr<" ++ f ++ "> " ++ c ++ "::clone() const ", + wrapSharedPtr f +++ c ++ "::clone() const ", "{", - " return std::make_unique<" ++ c ++ ">(*this);", + " return std::make_shared<" ++ c ++ ">(*this);", "}" ]; } @@ -354,9 +378,12 @@ prConsC mode c b = case mode of { , "}" ]; CppStdBeyondAnsi _ -> unlines [ - concat [ "std::unique_ptr<", c, "> ", "cons", c, "(std::unique_ptr<", bas, "> x, std::unique_ptr<", c, "> xs) {" ] - , " xs->" ++inner++ ".insert(xs->" ++inner++ ".begin(), std::move(x));" - , " return xs;" + concat [ "void ", c, "::cons(", wrapSharedPtr bas, " x) {" ] + , " " ++inner++ ".insert(" ++inner++ ".begin(), x);" + , "}" + , "" + , "void" +++ c ++ "::reverse() {" + , " std::reverse(" ++inner++ ".begin(), " ++inner++ ".end());" , "}" ]; } @@ -379,20 +406,21 @@ prConstructorC mode (f,cs) = case mode of { CppStdBeyondAnsi _ -> unlines [ f ++ "::" ++ f ++ "(" ++ conargs ++ ")", "{", - unlines [" *" ++ c ++ " = " ++ p ++ ";" | (c,p) <- zip cvs pvs], + unlines [" " ++ c ++ " = " ++ wrapMoveIf isClass p ++ ";" | (c,isClass,p) <- zip3 cvs isClasses pvs], "}" ]; } where cvs = [c | (_,_,c) <- cs] + isClasses = [isClass | (_,isClass,_) <- cs] pvs = ['p' : show i | ((_,_,_),i) <- zip cs [1..]] conargs = case mode of { CppStdAnsi _ -> - intercalate ", " [x +++ pointerIf st v | ((x,st,_),v) <- zip cs pvs] + intercalate ", " [x +++ pointerIf isClass v | ((x,isClass,_),v) <- zip cs pvs] ; CppStdBeyondAnsi _ -> - intercalate ", " ["const"+++ x ++ "&" +++ v | ((x,_,_),v) <- zip cs pvs] + intercalate ", " [wrapSharedPtrIf isClass x ++ "&" +++ v | ((x,isClass,_),v) <- zip cs pvs] ; } @@ -424,16 +452,14 @@ prCopyC mode (c,cs) = case mode of { "", c ++ "&" +++ c ++ "::operator=(" ++ c ++ "&& rhs) = default;", "", - -- c ++ "::" ++ c ++ "(const" +++ c ++ "& rhs)" ++ if length cs == 0 then "" else ":", - -- intercalate ", \n" [" " ++c++ "(std::make_unique<" ++ x ++ ">(*rhs." ++ c ++ "))" | (x,_,c) <- cs], c ++ "::" ++ c ++ "(const" +++ c ++ "& rhs)", "{", - unlines [" *" ++ c ++ " = *rhs." ++ c ++ ";" | (x,st,c) <- cs], + unlines [" " ++ pointerIf isClass c ++ " = " ++ pointerIf isClass "rhs" ++ "." ++ c ++ ";" | (_,isClass,c) <- cs], "}", "", c ++ "&" +++ c ++ "::operator=(const" +++ c ++ "& rhs)", "{", - unlines [" *" ++ c ++ " = *rhs." ++ c ++ ";" | (x,st,c) <- cs], + unlines [" " ++ pointerIf isClass c ++ " = " ++ pointerIf isClass "rhs" ++ "." ++ c ++ ";" | (_,isClass,c) <- cs], " return *this;", "}", "" diff --git a/source/src/BNFC/Backend/Common/OOAbstract.hs b/source/src/BNFC/Backend/Common/OOAbstract.hs index 6e0f7981..94aeff7f 100644 --- a/source/src/BNFC/Backend/Common/OOAbstract.hs +++ b/source/src/BNFC/Backend/Common/OOAbstract.hs @@ -29,10 +29,10 @@ data CAbs = CAbs { tokentypes :: [String], -- user non-position token types listtypes :: [(String,Bool)], -- list types used, whether of classes absclasses :: [String], -- grammar-def cats, normalized names - conclasses :: [Fun], -- constructors, except list ones + conclasses :: [Fun], -- constructors, except list ones signatures :: [(String,[CAbsRule])], -- rules for each class, incl. pos tokens postokens :: [String], -- position token types - defineds :: [Fun] -- defined (non-)constructors + defineds :: [Fun] -- defined (non-)constructors } -- (valcat,(constr,args)), True = is class (not basic), class variable stored From 99f18afe7506563c182c7575a5eb25d2c389ef5c Mon Sep 17 00:00:00 2001 From: "hiroyuki.nagata" Date: Mon, 24 Jan 2022 22:50:24 +0900 Subject: [PATCH 5/9] Update AST classes as simple, use list instead of vector. Fix bison action of list. --- source/src/BNFC/Backend/C/CFtoBisonC.hs | 9 +- source/src/BNFC/Backend/CPP/Common.hs | 9 - source/src/BNFC/Backend/CPP/PrettyPrinter.hs | 40 +--- source/src/BNFC/Backend/CPP/STL.hs | 128 +++++------ source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs | 212 +++++++----------- 5 files changed, 158 insertions(+), 240 deletions(-) diff --git a/source/src/BNFC/Backend/C/CFtoBisonC.hs b/source/src/BNFC/Backend/C/CFtoBisonC.hs index ee5fe1e8..5da087aa 100644 --- a/source/src/BNFC/Backend/C/CFtoBisonC.hs +++ b/source/src/BNFC/Backend/C/CFtoBisonC.hs @@ -150,8 +150,7 @@ header mode cf = unlines $ concat [ , "%defines \"" ++ ("Bison" <.> hExt) ++ "\"" ] , when (beyondAnsi mode) - [ "%define parse.trace" - , "%define api.namespace {" ++ ns ++ "}" + [ "%define api.namespace {" ++ ns ++ "}" , "/* Specify the namespace for the C++ parser class. */"] , whenJust (parserPackage mode) $ \ ns -> [ "%name-prefix = \"" ++ ns ++ "\"" @@ -596,7 +595,7 @@ generateActionSTLBeyondAnsi rp inPackage nt f b mbs = reverses ++ if | isCoercion f -> concat ["$$ = ", unwords ms, ";", loc] | isNilFun f -> concat ["$$ = ", "std::make_shared<", scope, nt, ">();"] | isOneFun f -> concat ["$$ = ", "std::make_shared<", scope, nt, ">(); $$->cons(", head ms, ");"] - | isConsFun f -> concat [lst, "->cons(", el, ");"] + | isConsFun f -> concat [lst, "->cons(", el, "); $$ = ", lst, ";"] | isDefinedRule f -> concat ["$$ = ", scope, sanitizeCpp (funName f), "(", intercalate ", " ms, ");" ] | otherwise -> concat ["$$ = ", "std::make_shared<", scope, funName f, ">(", (intercalate ", " ms), ");", loc] where @@ -609,9 +608,7 @@ generateActionSTLBeyondAnsi rp inPackage nt f b mbs = reverses ++ = " $$->line_number = @$.first_line; $$->char_number = @$.first_column;" | otherwise = "" - -- TODO: temporary commented reverse() - -- reverses = unwords [m ++"->reverse();" | (m, True) <- mbs] - reverses = unwords ["/*" ++m++ "->reverse(); */" | (m, True) <- mbs] + reverses = unwords [m ++"->reverse();" | (m, True) <- mbs] scope = nsScope inPackage diff --git a/source/src/BNFC/Backend/CPP/Common.hs b/source/src/BNFC/Backend/CPP/Common.hs index c098c000..0719534b 100644 --- a/source/src/BNFC/Backend/CPP/Common.hs +++ b/source/src/BNFC/Backend/CPP/Common.hs @@ -80,17 +80,8 @@ data CppStdMode wrapPointerIf :: Bool -> String -> String wrapPointerIf b v = if b then "*" ++ v else v -wrapUniquePtrIf :: Bool -> String -> String -wrapUniquePtrIf b v = if b then "std::unique_ptr<" ++v++">" else v - -wrapUniquePtr :: String -> String -wrapUniquePtr v = "std::unique_ptr<" ++v++">" - wrapSharedPtrIf :: Bool -> String -> String wrapSharedPtrIf b v = if b then "std::shared_ptr<" ++v++">" else v wrapSharedPtr :: String -> String wrapSharedPtr v = "std::shared_ptr<" ++v++">" - -wrapMoveIf :: Bool -> String -> String -wrapMoveIf b v = if b then "std::move(" ++v++")" else v diff --git a/source/src/BNFC/Backend/CPP/PrettyPrinter.hs b/source/src/BNFC/Backend/CPP/PrettyPrinter.hs index c8564d9c..297867b5 100644 --- a/source/src/BNFC/Backend/CPP/PrettyPrinter.hs +++ b/source/src/BNFC/Backend/CPP/PrettyPrinter.hs @@ -31,7 +31,7 @@ import BNFC.Utils import BNFC.Backend.Common import BNFC.Backend.Common.NamedVariables import BNFC.Backend.Common.StrUtils (renderCharOrString) -import BNFC.Backend.CPP.Common ( CppStdMode(..), wrapUniquePtr, wrapSharedPtrIf, wrapPointerIf ) +import BNFC.Backend.CPP.Common (CppStdMode(..)) import BNFC.Backend.CPP.STL.STLUtils import BNFC.PrettyPrint @@ -199,7 +199,6 @@ prDataH mode useSTL (cat, rules) CppStdBeyondAnsi _ -> True CppStdAnsi _ -> False cl = identCat (normCat cat) - vararg = if beyondAnsi then "p" else "*p" prRuleH = if beyondAnsi then prRuleHBeyondAnsi else prRuleHAnsi itty = concat [ cl, "::", "const_iterator" ] abstract = case lookupRule (noPosition $ catToStr cat) rules of @@ -393,7 +392,7 @@ prPrintData True mode _ _ (cat@(ListCat _), rules) = render $ genPrintVisitorList (mode, cat, rules) prPrintData False mode _ _ (cat@(ListCat _), rules) = genPrintVisitorListNoStl (mode, cat, rules) -prPrintData _ mode _inPackage cf (TokenCat cat, _rules) | +prPrintData _ _ _inPackage cf (TokenCat cat, _rules) | isPositionCat cf cat = genPositionToken cat prPrintData _ mode inPackage _cf (cat, rules) = abstract ++ concatMap (prPrintRule beyondAnsi inPackage) rules @@ -402,7 +401,6 @@ prPrintData _ mode inPackage _cf (cat, rules) = CppStdBeyondAnsi _ -> True CppStdAnsi _ -> False cl = identCat (normCat cat) - vararg = "*p" abstract = case lookupRule (noPosition $ catToStr cat) rules of Just _ -> "" Nothing -> "void PrintAbsyn::visit" ++ cl ++ "(" ++ cl +++ "*p) {} //abstract class\n\n" @@ -410,7 +408,7 @@ prPrintData _ mode inPackage _cf (cat, rules) = -- | Generate pretty printer visitor for a list category (STL version). -- genPrintVisitorList :: (CppStdMode, Cat, [Rule]) -> Doc -genPrintVisitorList (mode, cat@(ListCat _), rules) = vcat +genPrintVisitorList (_, cat@(ListCat _), rules) = vcat [ "void PrintAbsyn::visit" <> lty <> parens (ltyarg <> "*" <+> varg) , codeblock 2 [ "iter" <> lty <> parens (vname <> "->begin()" <> comma <+> vname <> "->end()") <> semi ] @@ -427,7 +425,7 @@ genPrintVisitorList (mode, cat@(ListCat _), rules) = vcat , "else" ] , unless (null docs1) - [ "if (i == j-1)" + [ "if (i == std::prev(j, 1))" , "{ /* last */" , nest 2 $ vcat docs1 , "}" @@ -442,9 +440,6 @@ genPrintVisitorList (mode, cat@(ListCat _), rules) = vcat , "" ] where - beyondAnsi = case mode of - CppStdBeyondAnsi _ -> True - CppStdAnsi _ -> False cl = identCat (normCat cat) lty = text cl -- List type ltyarg = text cl -- List type arg @@ -480,7 +475,7 @@ prListRule_ (Rule _ _ items _) = for items $ \case Left c | Just{} <- maybeTokenCat c -> "visit" <> dat <> "(*i);" - | isList c -> "iter" <> dat <> "(i+1, j);" + | isList c -> "iter" <> dat <> "(std::next(i,1), j);" | otherwise -> "(*i)->accept(this);" where dat = text $ identCat $ normCat c @@ -489,7 +484,7 @@ prListRule_ (Rule _ _ items _) = for items $ \case -- between the versions with and without STL. -- The present version has been adapted from CFtoCPrinter. genPrintVisitorListNoStl :: (CppStdMode, Cat, [Rule]) -> String -genPrintVisitorListNoStl (mode, cat@(ListCat _), rules) = unlines $ concat +genPrintVisitorListNoStl (_, cat@(ListCat _), rules) = unlines $ concat [ [ "void PrintAbsyn::visit" ++ cl ++ "("++ cl ++ " *" ++ vname ++ ")" , "{" , " if (" ++ vname +++ "== 0)" @@ -515,12 +510,8 @@ genPrintVisitorListNoStl (mode, cat@(ListCat _), rules) = unlines $ concat ] ] where - beyondAnsi = case mode of - CppStdBeyondAnsi _ -> True - CppStdAnsi _ -> False cl = identCat (normCat cat) vname = map toLower cl - varg = map toLower cl pre = vname ++ "->" prules = sortRulesByPrecedence rules swRules f = switchByPrecedence "_i_" $ @@ -531,7 +522,7 @@ genPrintVisitorListNoStl _ = error "genPrintVisitorListNoStl expects a ListCat" --Pretty Printer methods for a rule. prPrintRule :: Bool -> Maybe String -> Rule -> String -prPrintRule beyondAnsi inPackage r@(Rule fun _ _ _) | isProperLabel fun = unlines $ concat +prPrintRule _ inPackage r@(Rule fun _ _ _) | isProperLabel fun = unlines $ concat [ [ "void PrintAbsyn::visit" ++ visitFunName ++ "(" ++ vararg +++ fnm ++ ")" , "{" , " int oldi = _i_;" @@ -573,7 +564,7 @@ prPrintItem pre (Left (c, nt)) --This prints the functions for Abstract Syntax tree printing. prShowData :: Bool -> CppStdMode -> (Cat, [Rule]) -> String -prShowData True mode (cat@(ListCat c), _) = unlines +prShowData True _ (cat@(ListCat c), _) = unlines [ "void ShowAbsyn::visit" ++ cl ++ "("++ cl ++ " *" ++ vname ++ ")", "{", @@ -583,20 +574,16 @@ prShowData True mode (cat@(ListCat c), _) = unlines if isTokenCat c then " visit" ++ baseName cl ++ "(*i) ;" else " (*i)->accept(this);", - " if (i != " ++ vname ++ "->end() - 1) bufAppend(\", \");", + " if (i != std::prev(" ++ vname ++ "->end(), 1)) bufAppend(\", \");", " }", "}", "" ] where - beyondAnsi = case mode of - CppStdBeyondAnsi _ -> True - CppStdAnsi _ -> False cl = identCat (normCat cat) vname = map toLower cl - varg = vname -prShowData False mode (cat@(ListCat c), _) = +prShowData False _ (cat@(ListCat c), _) = unlines [ "void ShowAbsyn::visit" ++ cl ++ "("++ cl ++ " *" ++ vname ++ ")", @@ -619,13 +606,9 @@ prShowData False mode (cat@(ListCat c), _) = "" ] where - beyondAnsi = case mode of - CppStdBeyondAnsi _ -> True - CppStdAnsi _ -> False cl = identCat (normCat cat) ecl = identCat (normCatOfList cat) vname = map toLower cl - varg = vname member = map toLower ecl ++ "_" visitMember | Just t <- maybeTokenCat c = @@ -640,14 +623,13 @@ prShowData _ mode (cat, rules) = --Not a list: CppStdBeyondAnsi _ -> True CppStdAnsi _ -> False cl = identCat (normCat cat) - varg = "p" abstract = case lookupRule (noPosition $ catToStr cat) rules of Just _ -> "" Nothing -> "void ShowAbsyn::visit" ++ cl ++ "(" ++ cl ++ " *p) {} //abstract class\n\n" --This prints all the methods for Abstract Syntax tree rules. prShowRule :: IsFun f => Rul f -> Bool -> String -prShowRule (Rule f _ cats _) beyondAnsi | isProperLabel f = concat +prShowRule (Rule f _ cats _) _ | isProperLabel f = concat [ "void ShowAbsyn::visit" ++ fun ++ "(" ++ vararg +++ fnm ++ ")\n", "{\n", diff --git a/source/src/BNFC/Backend/CPP/STL.hs b/source/src/BNFC/Backend/CPP/STL.hs index 13c8e37f..19fbe72f 100644 --- a/source/src/BNFC/Backend/CPP/STL.hs +++ b/source/src/BNFC/Backend/CPP/STL.hs @@ -22,7 +22,7 @@ import BNFC.Backend.Base import BNFC.Backend.C ( bufferH, bufferC, comment, testfileHeader ) import BNFC.Backend.C.CFtoBisonC ( cf2Bison, unionBuiltinTokens, positionCats, varName ) import BNFC.Backend.C.CFtoFlexC ( cf2flex, ParserMode(..), beyondAnsi, parserPackage, parserName, stlParser ) -import BNFC.Backend.CPP.Common ( commentWithEmacsModeHint, wrapSharedPtr, CppStdMode(..) ) +import BNFC.Backend.CPP.Common ( commentWithEmacsModeHint, wrapSharedPtr ) import BNFC.Backend.CPP.Makefile import BNFC.Backend.CPP.STL.CFtoSTLAbs import BNFC.Backend.CPP.STL.CFtoCVisitSkelSTL @@ -120,6 +120,7 @@ cpptest mode inPackage cf hExt = unlines $ concat , if beyondAnsi mode then unlines [ "#include " + , "#include " , "#include \"Driver" ++hExt++ "\"" ] else @@ -137,43 +138,68 @@ cpptest mode inPackage cf hExt = unlines $ concat , "}" , "" , "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;" - , "" , if beyondAnsi mode then unlines [ - " /* The default entry point is used. For other options see Parser.H */" + "{" + , " int quiet = 0;" + , " char *filename = NULL;" + , "" + , " if (argc > 1) {" + , " if (strcmp(argv[1], \"-s\") == 0) {" + , " quiet = 1;" + , " if (argc > 2) {" + , " filename = argv[2];" + , " }" + , " } else {" + , " filename = argv[1];" + , " }" + , " }" + , "" + , " /* The default entry point is used. For other options see Parser.H */" , " " ++ (wrapSharedPtr $ scope ++ dat) ++ " parse_tree = nullptr;" , " try { " + , "" , " auto driver = std::make_unique<" ++ns++ "::" ++camelCaseName++ "Driver>();" - , " parse_tree = driver->p" ++ def ++ "(filename);" + , " if (filename) {" + , " std::ifstream input(filename);" + , " if ( ! input.good() ) {" + , " usage();" + , " exit(1);" + , " }" + , " parse_tree = driver->p" ++ def ++ "(input);" + , " } else {" + , " parse_tree = driver->p" ++ def ++ "(std::cin);" + , " }" ] else unlines [ - " /* The default entry point is used. For other options see Parser.H */" + "{" + , " 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);" @@ -223,7 +249,7 @@ cpptest mode inPackage cf hExt = unlines $ concat camelCaseName = camelCase_ name ns = fromMaybe camelCaseName (parserPackage mode) - +mkHeaderFile :: String -> Maybe String -> CF -> [Cat] -> [Cat] -> [String] -> String mkHeaderFile hExt inPackage _cf _cats eps _env = unlines $ concat [ [ "#ifndef " ++ hdef , "#define " ++ hdef @@ -245,9 +271,7 @@ mkHeaderFile hExt inPackage _cf _cats eps _env = unlines $ concat where hdef = nsDefine inPackage "PARSER_HEADER_FILE" mkFuncs s = - [ identCat (normCat s) ++ "*" +++ "p" ++ identCat s ++ "(FILE *inp);" - , identCat (normCat s) ++ "*" +++ "ps" ++ identCat s ++ "(const char *str);" - ] + [ identCat (normCat s) ++ "*" +++ "p" ++ identCat s ++ "(std::istream &stream);" ] -- | C++ lexer/parser driver @@ -280,8 +304,7 @@ driverH mode cf cats = unlines -- user defined tokens , unlines [ prettyShow (" std::shared_ptr<" ++ identCat tok ++ ">"+++ varName tok ++";") | tok <- normCats ] , "" - , unlines [ mkFileEntry ep | ep <- entryPoints ] - , unlines [ mkStringEntry ep | ep <- entryPoints ] + , unlines [ mkStreamEntry ep | ep <- entryPoints ] , "" , " /**" , " * parse - parse from a file" @@ -320,16 +343,14 @@ driverH mode cf cats = unlines ns = fromMaybe camelCaseName (parserPackage mode) normCats = nub (map normCat cats) entryPoints = toList (allEntryPoints cf) - mkFileEntry s = - " " ++ (wrapSharedPtr $ identCat (normCat s)) +++ "p" ++ identCat s ++ "(const char *filename);" - mkStringEntry s = - " " ++ (wrapSharedPtr $ identCat (normCat s)) +++ "ps" ++ identCat s ++ "(std::istream &stream);" + mkStreamEntry s = + " " ++ (wrapSharedPtr $ identCat (normCat s)) +++ "p" ++ identCat s ++ "(std::istream &stream);" -- | C++ lexer/parser driver driverC :: ParserMode -> CF -> String -> String -driverC mode cf driverH = unlines +driverC mode cf _ = unlines [ "#include " , "#include " , "#include " @@ -406,37 +427,18 @@ driverC mode cf driverH = unlines , " return;" , "}" , "" - , unlines [ mkFileEntry ep | ep <- entryPoints ] - , unlines [ mkStringEntry ep | ep <- entryPoints ] + , unlines [ mkStreamEntry ep | ep <- entryPoints ] ] where name = parserName mode camelCaseName = camelCase_ name ns = fromMaybe camelCaseName (parserPackage mode) entryPoints = toList (allEntryPoints cf) - mkFileEntry s = - unlines [ - (wrapSharedPtr $ identCat (normCat s)) - , ns++ "::" ++camelCaseName++ "Driver::p" ++ identCat s ++ "(const char *filename)" - , "{" - , " assert( filename != nullptr );" - , " std::ifstream in_file( filename );" - , " if( ! in_file.good() )" - , " {" - , " exit( EXIT_FAILURE );" - , " }" - , " parse_helper( in_file );" - , " return this->" ++ varName s++ ";" - , "}" - ] - mkStringEntry s = + mkStreamEntry s = unlines [ (wrapSharedPtr $ identCat (normCat s)) - , ns++ "::" ++camelCaseName++ "Driver::ps" ++ identCat s ++ "(std::istream &stream)" + , ns++ "::" ++camelCaseName++ "Driver::p" ++ identCat s ++ "(std::istream &stream)" , "{" - , " if( ! stream.good() && stream.eof() ) {" - , " return nullptr;" - , " }" , " parse_helper( stream );" , " return this->" ++ varName s++ ";" , "}" diff --git a/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs b/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs index ec76e4a8..c4385f75 100644 --- a/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs +++ b/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs @@ -24,7 +24,7 @@ import Data.Char ( toLower ) import BNFC.Backend.Common.OOAbstract import BNFC.CF -import BNFC.Options ( RecordPositions(..), Ansi(..) ) +import BNFC.Options ( RecordPositions(..) ) import BNFC.TypeChecker ( ListConstructors(..) ) import BNFC.Utils ( (+++), applyWhen ) @@ -56,7 +56,7 @@ mkHFile rp mode inPackage cabs cf = unlines "#include "]; CppStdBeyondAnsi _ -> unlines [ "#include ", - "#include ", + "#include ", "#include ", "#include "]; }, @@ -90,7 +90,7 @@ mkHFile rp mode inPackage cabs cf = unlines }, "", "/******************** Visitor Interfaces ********************/", - prVisitor mode cabs, + prVisitor cabs, "", prVisitable, "", @@ -119,22 +119,22 @@ prVisitable = unlines [ "{", " public:", -- all classes with virtual methods require a virtual destructor - " virtual ~Visitable() {}", - " virtual void accept(Visitor *v) = 0;", + " virtual ~Visitable() {}", + " virtual void accept(Visitor *v) = 0;", "};" ] -prVisitor :: CppStdMode -> CAbs -> String -prVisitor mode cf = unlines [ +prVisitor :: CAbs -> String +prVisitor cf = unlines [ "class Visitor", "{", "public:", - " virtual ~Visitor() {}", + " virtual ~Visitor() {}", unlines - [" virtual void visit"++c++"("++ c +++ vararg ++") = 0;" | c <- allClasses cf, notElem c (defineds cf)], + [" virtual void visit"++c++"("++ c +++ vararg ++") = 0;" | c <- allClasses cf, notElem c (defineds cf)], "", unlines - [" virtual void visit"++c++"("++c++" x) = 0;" | c <- allNonClasses cf], + [" virtual void visit"++c++"("++c++" x) = 0;" | c <- allNonClasses cf], "};" ] where @@ -147,16 +147,16 @@ prAbs mode rp c = "class " ++ c ++ " : public Visitable", "{", "public:", - " virtual " ++ c ++ " *clone() const = 0;", - if rp == RecordPositions then " int line_number, char_number;" else "", + " virtual " ++ c ++ " *clone() const = 0;", + if rp == RecordPositions then " int line_number, char_number;" else "", "};" ]; CppStdBeyondAnsi _ -> unlines [ "class " ++ c ++ " : public Visitable", "{", "public:", - " virtual" +++ wrapSharedPtr c +++ "clone() const = 0;", - if rp == RecordPositions then " int line_number, char_number;" else "", + " virtual" +++ wrapSharedPtr c +++ "clone() const = 0;", + if rp == RecordPositions then " int line_number, char_number;" else "", "};" ]; } @@ -169,31 +169,37 @@ prCon mode (c,(f,cs)) = "{", "public:", unlines - [" "++ typ +++ pointerIf st var ++ ";" | (typ,st,var) <- cs], - " " ++ f ++ "(const " ++ f ++ " &);", - " " ++ f ++ " &operator=(const " ++f++ " &);", - " " ++ f ++ "(" ++ conargs ++ ");", + [" "++ typ +++ pointerIf st var ++ ";" | (typ,st,var) <- cs], + " " ++ f ++ "(const " ++ f ++ " &);", + " " ++ f ++ " &operator=(const " ++f++ " &);", + " " ++ f ++ "(" ++ conargs ++ ");", -- Typ *p1, PIdent *p2, ListStm *p3); - " ~" ++f ++ "();", - " virtual void accept(Visitor *v);", - " virtual " ++f++ " *clone() const;", - " void swap(" ++f++ " &);", + " ~" ++f ++ "();", + " virtual void accept(Visitor *v) override;", + " virtual " ++f++ " *clone() const;", + " void swap(" ++f++ " &);", "};" ]; CppStdBeyondAnsi _ -> unlines [ "class " ++f++ " : public " ++ c, "{", "public:", - unlines [" " ++ wrapSharedPtrIf isClass typ +++ var ++ ";" | (typ,isClass,var) <- cs], - -- "right-hand side" operations; for move - " " ++ f ++ "(" ++ f ++ "&& rhs);", - " " ++ f ++ "& operator=(" ++ f ++ "&& rhs);", - " " ++ f ++ "(const" +++ f ++ "& rhs);", - " " ++ f ++ "& operator=(const" +++ f ++ "& rhs);", - " " ++ f ++ "(" ++ conargs ++ ");", - " ~" ++f ++ "();", - " virtual void accept(Visitor *v);", - " " ++ wrapSharedPtr c +++ " clone() const override;", + unlines [" " ++ wrapSharedPtrIf isClass typ +++ var ++ ";" | (typ,isClass,var) <- cs], + if length cs > 0 then + -- Generate following initiliazer; + -- + -- Prog(std::shared_ptr p1) + -- : Program(), liststatement_{p1} {}; + unlines + [ " " ++f++ "(" ++ conargs ++ ")", + " :" +++ c ++ "(), " ++ intercalate ", " [var ++ "{p" ++ show i ++ "}" | ((_,_,var),i) <- zip cs [(1::Integer)..]], + " {};" + ] + else + " " ++f++ "(" ++ conargs ++ "):" +++ c +++ "(){};", + "", + " virtual void accept(Visitor *v) override;", + " " ++ wrapSharedPtr c +++ " clone() const override;", "};" ]; } @@ -202,11 +208,10 @@ prCon mode (c,(f,cs)) = case mode of { CppStdAnsi _ -> concat $ intersperse ", " - [x +++ pointerIf st ("p" ++ show i) | ((x,st,_),i) <- zip cs [1..]] + [x +++ pointerIf st ("p" ++ show i) | ((x,st,_),i) <- zip cs [(1::Integer)..]] ; CppStdBeyondAnsi _ -> - concat $ intersperse ", " - [wrapSharedPtrIf isClass x ++ "& p" ++ show i | ((x,isClass,_),i) <- zip cs [1..]] + intercalate ", " [wrapSharedPtrIf isClass x ++ " p" ++ show i | ((x,isClass,_),i) <- zip cs [(1::Integer)..]] ; } @@ -216,8 +221,8 @@ prList mode (c, b) = case mode of { "class " ++c++ " : public Visitable, public std::vector<" ++bas++ ">" , "{" , "public:" - , " virtual void accept(Visitor *v);" - , " virtual " ++ c ++ " *clone() const;" + , " virtual void accept(Visitor *v);" + , " virtual " ++ c ++ " *clone() const;" , "};" , "" -- cons for this list type @@ -227,28 +232,24 @@ prList mode (c, b) = case mode of { "class " ++c++ " : public Visitable" , "{" , "public:" - , " std::vector<" ++ wrapSharedPtr childClass++ ">" +++ childClassVarName ++ ";" + , " " ++c++ "() : " ++childClassVarName++ "{}" + , " {}" + , "" + , " std::list<" ++ wrapSharedPtr childClass++ ">" +++ childClassVarName ++ ";" , "" -- ref: https://stackoverflow.com/questions/51148797/how-can-i-define-iterator-and-const-iterator-in-my-class-while-i-uses-stdvecto - , " // define iterator and const_iterator, expose it" - , " using iterator = typename std::vector<" ++ wrapSharedPtr childClass ++ ">::iterator;" - , " using const_iterator = typename std::vector<" ++ wrapSharedPtr childClass++ ">::const_iterator;" - , " auto begin() const { return " ++childClassVarName++ ".begin(); }" - , " auto begin() { return " ++childClassVarName++ ".begin(); }" - , " auto end() const { return " ++childClassVarName++ ".end(); }" - , " auto end() { return " ++childClassVarName++ ".end(); }" + , " // define iterator and const_iterator, expose it" + , " using iterator = typename std::list<" ++ wrapSharedPtr childClass ++ ">::iterator;" + , " using const_iterator = typename std::list<" ++ wrapSharedPtr childClass++ ">::const_iterator;" + , " auto begin() const { return " ++childClassVarName++ ".begin(); }" + , " auto begin() { return " ++childClassVarName++ ".begin(); }" + , " auto end() const { return " ++childClassVarName++ ".end(); }" + , " auto end() { return " ++childClassVarName++ ".end(); }" , "" - -- "right-hand side" operations; for move - , " " ++ c ++ "(" ++ c ++ "&& rhs);" - , " " ++ c ++ "& operator=(" ++ c ++ "&& rhs);" - , " " ++ c ++ "(const" +++ c ++ "& rhs);" - , " " ++ c ++ "& operator=(const" +++ c ++ "& rhs);" - , " " ++ c ++ "();" - , " ~" ++ c ++ "();" - , " virtual void accept(Visitor *v);" - , " " ++ wrapSharedPtr c +++ " clone() const;" - , " void cons(" ++ wrapSharedPtr childClass ++ ");" - , " void reverse();" + , " virtual void accept(Visitor *v);" + , " " ++ wrapSharedPtr c +++ " clone() const;" + , " void cons(" ++ wrapSharedPtr childClass ++ ");" + , " void reverse();" , "};" , "" ]; @@ -297,42 +298,10 @@ prConC mode c fcs@(f,_) = unlines [ prListC :: CppStdMode -> (String,Bool) -> String prListC mode (c,b) = unlines [ "/******************** " ++ c ++ " ********************/" - , case mode of { - CppStdAnsi _ -> [] - ; - CppStdBeyondAnsi _ -> unlines [ - c ++ "::" ++ c ++ "(" ++ c ++ "&& rhs) = default;", - "", - c ++ "&" +++ c ++ "::operator=(" ++ c ++ "&& rhs) = default;", - "", - c ++ "::" ++ c ++ "(const" +++ c ++ "& rhs)", - "{", - " for (const auto& e : rhs." ++inner++ ")", - " {", - " " ++inner++".push_back(e->clone());", - " }", - "}", - "", - c ++ "&" +++ c ++ "::operator=(const" +++ c ++ "& rhs)", - "{", - " for (const auto& e : rhs." ++inner++ ")", - " {", - " " ++inner++".push_back(e->clone());", - " }", - " return *this;", - "}", - "", - c ++ "::" ++ c ++"() = default;", - c ++ "::~" ++ c ++"() = default;", - ""]; - } , prAcceptC mode c , prCloneC mode c c , prConsC mode c b ] - where - inner = map toLower c ++ "_" - --The standard accept function for the Visitor pattern prAcceptC :: CppStdMode -> String -> String @@ -340,13 +309,13 @@ prAcceptC mode ty = case mode of { CppStdAnsi _ -> unlines [ "void " ++ ty ++ "::accept(Visitor *v)", "{", - " v->visit" ++ ty ++ "(this);", + " v->visit" ++ ty ++ "(this);", "}" ]; CppStdBeyondAnsi _ -> unlines [ "void " ++ty++ "::accept(Visitor *v)", "{", - " v->visit" ++ ty ++ "(this);", + " v->visit" ++ ty ++ "(this);", "}" ]; } @@ -357,13 +326,13 @@ prCloneC mode f c = case mode of { CppStdAnsi _ -> unlines [ c +++ "*" ++ c ++ "::clone() const", "{", - " return new" +++ c ++ "(*this);", + " return new" +++ c ++ "(*this);", "}" ]; CppStdBeyondAnsi _ -> unlines [ wrapSharedPtr f +++ c ++ "::clone() const ", "{", - " return std::make_shared<" ++ c ++ ">(*this);", + " return std::make_shared<" ++ c ++ ">(*this);", "}" ]; } @@ -373,17 +342,17 @@ prConsC :: CppStdMode -> String -> Bool -> String prConsC mode c b = case mode of { CppStdAnsi _ -> unlines [ concat [ c, "* ", "cons", c, "(", bas, " x, ", c, "* xs) {" ] - , " xs->insert(xs->begin(), x);" - , " return xs;" + , " xs->insert(xs->begin(), x);" + , " return xs;" , "}" ]; CppStdBeyondAnsi _ -> unlines [ concat [ "void ", c, "::cons(", wrapSharedPtr bas, " x) {" ] - , " " ++inner++ ".insert(" ++inner++ ".begin(), x);" + , " " ++inner++ ".push_front(x);" , "}" , "" , "void" +++ c ++ "::reverse() {" - , " std::reverse(" ++inner++ ".begin(), " ++inner++ ".end());" + , " std::reverse(" ++inner++ ".begin(), " ++inner++ ".end());" , "}" ]; } @@ -400,27 +369,22 @@ prConstructorC mode (f,cs) = case mode of { CppStdAnsi _ -> unlines [ f ++ "::" ++ f ++ "(" ++ conargs ++ ")", "{", - unlines [" " ++ c ++ " = " ++ p ++ ";" | (c,p) <- zip cvs pvs], + unlines [" " ++ c ++ " = " ++ p ++ ";" | (c,p) <- zip cvs pvs], "}" ]; CppStdBeyondAnsi _ -> unlines [ - f ++ "::" ++ f ++ "(" ++ conargs ++ ")", - "{", - unlines [" " ++ c ++ " = " ++ wrapMoveIf isClass p ++ ";" | (c,isClass,p) <- zip3 cvs isClasses pvs], - "}" ]; } where cvs = [c | (_,_,c) <- cs] - isClasses = [isClass | (_,isClass,_) <- cs] - pvs = ['p' : show i | ((_,_,_),i) <- zip cs [1..]] + pvs = ['p' : show i | ((_,_,_),i) <- zip cs [(1::Integer)..]] conargs = case mode of { CppStdAnsi _ -> - intercalate ", " [x +++ pointerIf isClass v | ((x,isClass,_),v) <- zip cs pvs] + intercalate ", " [x +++ pointerIf isClass v | ((x,isClass,_),v) <- zip cs pvs] ; CppStdBeyondAnsi _ -> - intercalate ", " [wrapSharedPtrIf isClass x ++ "&" +++ v | ((x,isClass,_),v) <- zip cs pvs] + "" ; } @@ -431,40 +395,23 @@ prCopyC mode (c,cs) = case mode of { CppStdAnsi _ -> unlines [ c ++ "::" ++ c ++ "(const" +++ c +++ "& other)", "{", - unlines [" " ++ cv ++ " = other." ++ cloneIf st cv ++ ";" | (_,st,cv) <- cs], + unlines [" " ++ cv ++ " = other." ++ cloneIf st cv ++ ";" | (_,st,cv) <- cs], "}", "", c +++ "&" ++ c ++ "::" ++ "operator=(const" +++ c +++ "& other)", "{", - " " ++ c +++ "tmp(other);", - " swap(tmp);", - " return *this;", + " " ++ c +++ "tmp(other);", + " swap(tmp);", + " return *this;", "}", "", "void" +++ c ++ "::swap(" ++ c +++ "& other)", "{", - unlines [" std::swap(" ++ cv ++ ", other." ++ cv ++ ");" | (_,_,cv) <- cs], + unlines [" std::swap(" ++ cv ++ ", other." ++ cv ++ ");" | (_,_,cv) <- cs], "}" ]; - CppStdBeyondAnsi _ -> unlines [ - -- "right-hand side" operations; for move - c ++ "::" ++ c ++ "(" ++ c ++ "&& rhs) = default;", - "", - c ++ "&" +++ c ++ "::operator=(" ++ c ++ "&& rhs) = default;", - "", - c ++ "::" ++ c ++ "(const" +++ c ++ "& rhs)", - "{", - unlines [" " ++ pointerIf isClass c ++ " = " ++ pointerIf isClass "rhs" ++ "." ++ c ++ ";" | (_,isClass,c) <- cs], - "}", - "", - c ++ "&" +++ c ++ "::operator=(const" +++ c ++ "& rhs)", - "{", - unlines [" " ++ pointerIf isClass c ++ " = " ++ pointerIf isClass "rhs" ++ "." ++ c ++ ";" | (_,isClass,c) <- cs], - " return *this;", - "}", - "" - ]; - } + CppStdBeyondAnsi _ -> "" + } where cloneIf st cv = if st then (cv ++ "->clone()") else cv @@ -474,10 +421,9 @@ prDestructorC mode (c,cs) = case mode of { CppStdAnsi _ -> unlines [ c ++ "::~" ++ c ++"()", "{", - unlines [" delete(" ++ cv ++ ");" | (_,isPointer,cv) <- cs, isPointer], + unlines [" delete(" ++ cv ++ ");" | (_,isPointer,cv) <- cs, isPointer], "}" ]; - CppStdBeyondAnsi _ -> unlines [ - c ++ "::~" ++ c ++"() = default;" - ]; + CppStdBeyondAnsi _ -> "" + ; } From e7033382b44ef9d5da158396518344c2c87fbae2 Mon Sep 17 00:00:00 2001 From: Andreas Abel Date: Thu, 3 Mar 2022 11:24:49 +0100 Subject: [PATCH 6/9] testing: put C++ tests first, add --ansi --- testing/Main.hs | 2 +- testing/src/ParameterizedTests.hs | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/testing/Main.hs b/testing/Main.hs index 409970ce..da85187e 100644 --- a/testing/Main.hs +++ b/testing/Main.hs @@ -48,7 +48,7 @@ runAllTests = do succeedLBNFTests : failLBNFTests : -- ParameterizedTests.layoutTest : - ParameterizedTests.current : -- Uncomment for prioritized test case. + -- ParameterizedTests.current : -- Uncomment for prioritized test case. -- RegressionTests.current : ParameterizedTests.all : RegressionTests.all : diff --git a/testing/src/ParameterizedTests.hs b/testing/src/ParameterizedTests.hs index 620b94e4..79b6ff5f 100644 --- a/testing/src/ParameterizedTests.hs +++ b/testing/src/ParameterizedTests.hs @@ -343,6 +343,18 @@ haskellRunTestProg _lang args = do parameters :: [TestParameters] parameters = concat [ [] + -- C++ (extras) + , [ cBase { tpName = "C++ (with line numbers)" + , tpBnfcOptions = ["--cpp", "-l"] } + , cBase { tpName = "C++ (with namespace)" + , tpBnfcOptions = ["--cpp", "-p foobar"] } + ] + -- C++ (basic) + , [ cBase { tpName = "C++ (no STL)" + , tpBnfcOptions = ["--cpp-nostl"] } + , cBase { tpName = "C++ (ANSI)" + , tpBnfcOptions = ["--cpp", "--ansi"] } + ] -- OCaml/Menhir , [ ocaml { tpName = "OCaml/Menhir" , tpBnfcOptions = ["--ocaml", "--menhir"] } @@ -351,12 +363,6 @@ parameters = concat , [ ocaml ] -- Functor (Haskell & Agda) , [ haskellAgdaFunctorParameters] - -- C++ (extras) - , [ cBase { tpName = "C++ (with line numbers)" - , tpBnfcOptions = ["--cpp", "-l"] } - , cBase { tpName = "C++ (with namespace)" - , tpBnfcOptions = ["--cpp", "-p foobar"] } - ] -- C , [ TP { tpName = "C" , tpBnfcOptions = ["--c"] @@ -380,12 +386,6 @@ parameters = concat , tpBnfcOptions = ["--c", "--line-numbers"] } ] - -- C++ (basic) - , [ cBase { tpName = "C++ (no STL)" - , tpBnfcOptions = ["--cpp-nostl"] } - , cBase { tpName = "C++" - , tpBnfcOptions = ["--cpp"] } - ] -- Agda , [ haskellAgdaParameters ] -- Java/ANTLR From e0d21a268e838e7a4f08336a65f50bfa89073565 Mon Sep 17 00:00:00 2001 From: hangedman Date: Sun, 13 Mar 2022 17:35:51 +0900 Subject: [PATCH 7/9] Fixing review items and other compile error (#4) Fix following: * Dont' generate `override` keyword on `--ansi` mode * Remove doubly defined YY_BUFFER_STATE in `--ansi` mode * Switch `--ansi` and `-std=c++14` mode in `source/src/BNFC/Backend/CPP/PrettyPrinter.hs` * Fix Parser.h, switch entry points interfaces * Use C++ location/position interface --- source/src/BNFC/Backend/C/CFtoBisonC.hs | 3 +- source/src/BNFC/Backend/CPP/PrettyPrinter.hs | 76 +++++++++++++------ source/src/BNFC/Backend/CPP/STL.hs | 21 +++-- source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs | 2 +- 4 files changed, 70 insertions(+), 32 deletions(-) diff --git a/source/src/BNFC/Backend/C/CFtoBisonC.hs b/source/src/BNFC/Backend/C/CFtoBisonC.hs index 5da087aa..54e0b3a7 100644 --- a/source/src/BNFC/Backend/C/CFtoBisonC.hs +++ b/source/src/BNFC/Backend/C/CFtoBisonC.hs @@ -236,7 +236,6 @@ header mode cf = unlines $ concat [ , "typedef void* yyscan_t;" , "#endif" , "" - , "typedef struct " ++ name ++ "_buffer_state *YY_BUFFER_STATE;" , "typedef struct yy_buffer_state *YY_BUFFER_STATE;" , "extern YY_BUFFER_STATE " ++ name ++ "_scan_string(const char *str, yyscan_t scanner);" , "extern void " ++ name ++ "_delete_buffer(YY_BUFFER_STATE buf, yyscan_t scanner);" @@ -605,7 +604,7 @@ generateActionSTLBeyondAnsi rp inPackage nt f b mbs = reverses ++ -- The following match only happens in the cons case: [el, lst] = applyWhen b reverse ms -- b: left-recursion transformed? loc | RecordPositions <- rp - = " $$->line_number = @$.first_line; $$->char_number = @$.first_column;" + = " $$->line_number = @$.begin.line; $$->char_number = @$.begin.column;" | otherwise = "" reverses = unwords [m ++"->reverse();" | (m, True) <- mbs] diff --git a/source/src/BNFC/Backend/CPP/PrettyPrinter.hs b/source/src/BNFC/Backend/CPP/PrettyPrinter.hs index 297867b5..b6bc0bc9 100644 --- a/source/src/BNFC/Backend/CPP/PrettyPrinter.hs +++ b/source/src/BNFC/Backend/CPP/PrettyPrinter.hs @@ -34,6 +34,7 @@ import BNFC.Backend.Common.StrUtils (renderCharOrString) import BNFC.Backend.CPP.Common (CppStdMode(..)) import BNFC.Backend.CPP.STL.STLUtils import BNFC.PrettyPrint +import BNFC.Options (Ansi(..)) --Produces (.H file, .C file) cf2CPPPrinter :: CppStdMode -> Bool -> Maybe String -> CF -> String -> (String, String) @@ -395,11 +396,8 @@ prPrintData False mode _ _ (cat@(ListCat _), rules) = prPrintData _ _ _inPackage cf (TokenCat cat, _rules) | isPositionCat cf cat = genPositionToken cat prPrintData _ mode inPackage _cf (cat, rules) = - abstract ++ concatMap (prPrintRule beyondAnsi inPackage) rules + abstract ++ concatMap (prPrintRule mode inPackage) rules where - beyondAnsi = case mode of - CppStdBeyondAnsi _ -> True - CppStdAnsi _ -> False cl = identCat (normCat cat) abstract = case lookupRule (noPosition $ catToStr cat) rules of Just _ -> "" @@ -408,7 +406,7 @@ prPrintData _ mode inPackage _cf (cat, rules) = -- | Generate pretty printer visitor for a list category (STL version). -- genPrintVisitorList :: (CppStdMode, Cat, [Rule]) -> Doc -genPrintVisitorList (_, cat@(ListCat _), rules) = vcat +genPrintVisitorList (mode, cat@(ListCat _), rules) = vcat [ "void PrintAbsyn::visit" <> lty <> parens (ltyarg <> "*" <+> varg) , codeblock 2 [ "iter" <> lty <> parens (vname <> "->begin()" <> comma <+> vname <> "->end()") <> semi ] @@ -425,7 +423,7 @@ genPrintVisitorList (_, cat@(ListCat _), rules) = vcat , "else" ] , unless (null docs1) - [ "if (i == std::prev(j, 1))" + [ "if (i == " <> prevJ <> ")" , "{ /* last */" , nest 2 $ vcat docs1 , "}" @@ -448,12 +446,18 @@ genPrintVisitorList (_, cat@(ListCat _), rules) = vcat varg = text $ (map toLower cl) prules = sortRulesByPrecedence rules swRules f = switchByPrecedence "_i_" $ - map (second $ sep . prListRule_) $ + map (second $ sep . prListRuleFn) $ uniqOn fst $ filter f prules -- Discard duplicates, can only handle one rule per precedence. docs0 = swRules isNilFun docs1 = swRules isOneFun docs2 = swRules isConsFun + prevJ = case mode of + CppStdBeyondAnsi _ -> "std::prev(j, 1)" + CppStdAnsi _ -> "j-1" + prListRuleFn = case mode of + CppStdBeyondAnsi _ -> prListRuleBeyondAnsi + CppStdAnsi _ -> prListRuleAnsi genPrintVisitorList _ = error "genPrintVisitorList expects a ListCat" @@ -469,8 +473,8 @@ genPositionToken cat = unlines $ -- | Only render the rhs (items) of a list rule. -prListRule_ :: IsFun a => Rul a -> [Doc] -prListRule_ (Rule _ _ items _) = for items $ \case +prListRuleBeyondAnsi :: IsFun a => Rul a -> [Doc] +prListRuleBeyondAnsi (Rule _ _ items _) = for items $ \case Right t -> "render(" <> text (snd (renderCharOrString t)) <> ");" Left c | Just{} <- maybeTokenCat c @@ -480,11 +484,22 @@ prListRule_ (Rule _ _ items _) = for items $ \case where dat = text $ identCat $ normCat c +prListRuleAnsi :: IsFun a => Rul a -> [Doc] +prListRuleAnsi (Rule _ _ items _) = for items $ \case + Right t -> "render(" <> text (snd (renderCharOrString t)) <> ");" + Left c + | Just{} <- maybeTokenCat c + -> "visit" <> dat <> "(*i);" + | isList c -> "iter" <> dat <> "(i+1, j);" + | otherwise -> "(*i)->accept(this);" + where + dat = text $ identCat $ normCat c + -- This is the only part of the pretty printer that differs significantly -- between the versions with and without STL. -- The present version has been adapted from CFtoCPrinter. genPrintVisitorListNoStl :: (CppStdMode, Cat, [Rule]) -> String -genPrintVisitorListNoStl (_, cat@(ListCat _), rules) = unlines $ concat +genPrintVisitorListNoStl (mode, cat@(ListCat _), rules) = unlines $ concat [ [ "void PrintAbsyn::visit" ++ cl ++ "("++ cl ++ " *" ++ vname ++ ")" , "{" , " if (" ++ vname +++ "== 0)" @@ -514,22 +529,27 @@ genPrintVisitorListNoStl (_, cat@(ListCat _), rules) = unlines $ concat vname = map toLower cl pre = vname ++ "->" prules = sortRulesByPrecedence rules + prPrintRuleFn = case mode of + CppStdBeyondAnsi _ -> prPrintRuleBeyondAnsi + CppStdAnsi _ -> prPrintRuleAnsi swRules f = switchByPrecedence "_i_" $ - map (second $ sep . map text . prPrintRule_ pre) $ + map (second $ sep . map text . prPrintRuleFn pre) $ uniqOn fst $ filter f prules -- Discard duplicates, can only handle one rule per precedence. + + genPrintVisitorListNoStl _ = error "genPrintVisitorListNoStl expects a ListCat" --Pretty Printer methods for a rule. -prPrintRule :: Bool -> Maybe String -> Rule -> String -prPrintRule _ inPackage r@(Rule fun _ _ _) | isProperLabel fun = unlines $ concat +prPrintRule :: CppStdMode -> Maybe String -> Rule -> String +prPrintRule mode inPackage r@(Rule fun _ _ _) | isProperLabel fun = unlines $ concat [ [ "void PrintAbsyn::visit" ++ visitFunName ++ "(" ++ vararg +++ fnm ++ ")" , "{" , " int oldi = _i_;" , parenCode "_L_PAREN" , "" ] - , prPrintRule_ (fnm ++ "->") r + , prPrintRuleFn (fnm ++ "->") r , [ "" , parenCode "_R_PAREN" , " _i_ = oldi;" @@ -543,28 +563,38 @@ prPrintRule _ inPackage r@(Rule fun _ _ _) | isProperLabel fun = unlines $ conca p = precRule r parenCode x = " if (oldi > " ++ show p ++ ") render(" ++ nsDefine inPackage x ++ ");" fnm = "p" --old names could cause conflicts + prPrintRuleFn = case mode of + CppStdBeyondAnsi _ -> prPrintRuleBeyondAnsi + CppStdAnsi _ -> prPrintRuleAnsi prPrintRule _ _ _ = "" -prPrintRule_ :: IsFun a => String -> Rul a -> [String] -prPrintRule_ pre (Rule _ _ items _) = map (prPrintItem pre) $ numVars items +prPrintRuleAnsi :: IsFun a => String -> Rul a -> [String] +prPrintRuleAnsi pre (Rule _ _ items _) = map (prPrintItem (CppStdAnsi Ansi) pre) $ numVars items + +prPrintRuleBeyondAnsi :: IsFun a => String -> Rul a -> [String] +prPrintRuleBeyondAnsi pre (Rule _ _ items _) = map (prPrintItem (CppStdBeyondAnsi Ansi) pre) $ numVars items --This goes on to recurse to the instance variables. -prPrintItem :: String -> Either (Cat, Doc) String -> String -prPrintItem _ (Right t) = " render(" ++ snd (renderCharOrString t) ++ ");" -prPrintItem pre (Left (c, nt)) +prPrintItem :: CppStdMode -> String -> Either (Cat, Doc) String -> String +prPrintItem _ _ (Right t) = " render(" ++ snd (renderCharOrString t) ++ ");" +prPrintItem mode pre (Left (c, nt)) | Just t <- maybeTokenCat c = " visit" ++ t ++ "(" ++ pre ++ s ++ ");" - | isList c = " " ++ setI (precCat c) ++ "visit" ++ elt ++ "(" ++ pre ++ s ++ ".get());" -- TODO: shared_ptr.get is only beyondAnsi + | isList c = " " ++ setI (precCat c) ++ "visit" ++ elt ++ "(" ++ pre ++ s ++ toRawPtr ++ ");" | otherwise = " " ++ setI (precCat c) ++ pre ++ s ++ "->accept(this);" where s = render nt elt = identCat $ normCat c + toRawPtr = case mode of + CppStdBeyondAnsi _ -> ".get()" + CppStdAnsi _ -> "" + {- **** Abstract Syntax Tree Printer **** -} --This prints the functions for Abstract Syntax tree printing. prShowData :: Bool -> CppStdMode -> (Cat, [Rule]) -> String -prShowData True _ (cat@(ListCat c), _) = unlines +prShowData True mode (cat@(ListCat c), _) = unlines [ "void ShowAbsyn::visit" ++ cl ++ "("++ cl ++ " *" ++ vname ++ ")", "{", @@ -574,7 +604,9 @@ prShowData True _ (cat@(ListCat c), _) = unlines if isTokenCat c then " visit" ++ baseName cl ++ "(*i) ;" else " (*i)->accept(this);", - " if (i != std::prev(" ++ vname ++ "->end(), 1)) bufAppend(\", \");", + case mode of + CppStdBeyondAnsi _ -> " if (i != std::prev(" ++ vname ++ "->end(), 1)) bufAppend(\", \");" + CppStdAnsi _ -> " if (i != " ++ vname ++ "->end() - 1) bufAppend(\", \");", " }", "}", "" diff --git a/source/src/BNFC/Backend/CPP/STL.hs b/source/src/BNFC/Backend/CPP/STL.hs index 19fbe72f..e6703b42 100644 --- a/source/src/BNFC/Backend/CPP/STL.hs +++ b/source/src/BNFC/Backend/CPP/STL.hs @@ -43,7 +43,7 @@ makeCppStl opts cf = do -- Generate xxx.yy file mkCppFileWithHint (name ++ parserExt) $ cf2Bison (linenumbers opts) parserMode cf env mkCppFile ("Parser" ++ hExt) $ - mkHeaderFile hExt (inPackage opts) cf (allParserCats cf) (toList $ allEntryPoints cf) (Map.elems env) + mkHeaderFile parserMode hExt (inPackage opts) cf (allParserCats cf) (toList $ allEntryPoints cf) (Map.elems env) mkCppFile ("ParserError" ++ hExt) $ printParseErrHeader (inPackage opts) let (skelH, skelC) = cf2CVisitSkel opts True (inPackage opts) cf mkCppFile ("Skeleton" ++ hExt) skelH @@ -249,17 +249,19 @@ cpptest mode inPackage cf hExt = unlines $ concat camelCaseName = camelCase_ name ns = fromMaybe camelCaseName (parserPackage mode) -mkHeaderFile :: String -> Maybe String -> CF -> [Cat] -> [Cat] -> [String] -> String -mkHeaderFile hExt inPackage _cf _cats eps _env = unlines $ concat +mkHeaderFile :: ParserMode -> String -> Maybe String -> CF -> [Cat] -> [Cat] -> [String] -> String +mkHeaderFile mode hExt inPackage _cf _cats eps _env = unlines $ concat [ [ "#ifndef " ++ hdef , "#define " ++ hdef , "" , "#include " , "#include " , "#include " - , "#include \"Bison" ++ hExt ++ "\"" , "#include \"Absyn" ++ hExt ++ "\"" - , "" + , if beyondAnsi mode then + "#include \"Bison" ++ hExt ++ "\"" + else + "" , nsStart inPackage ] , concatMap mkFuncs eps @@ -270,8 +272,13 @@ mkHeaderFile hExt inPackage _cf _cats eps _env = unlines $ concat ] where hdef = nsDefine inPackage "PARSER_HEADER_FILE" - mkFuncs s = - [ identCat (normCat s) ++ "*" +++ "p" ++ identCat s ++ "(std::istream &stream);" ] + mkFuncs s = if beyondAnsi mode then + [ identCat (normCat s) ++ "*" +++ "p" ++ identCat s ++ "(std::istream &stream);" ] + else + [ identCat (normCat s) ++ "*" +++ "p" ++ identCat s ++ "(FILE *inp);" + , identCat (normCat s) ++ "*" +++ "p" ++ identCat s ++ "(const char *str);" + ] + -- | C++ lexer/parser driver diff --git a/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs b/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs index c4385f75..de73d244 100644 --- a/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs +++ b/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs @@ -175,7 +175,7 @@ prCon mode (c,(f,cs)) = " " ++ f ++ "(" ++ conargs ++ ");", -- Typ *p1, PIdent *p2, ListStm *p3); " ~" ++f ++ "();", - " virtual void accept(Visitor *v) override;", + " virtual void accept(Visitor *v);", " virtual " ++f++ " *clone() const;", " void swap(" ++f++ " &);", "};" From fd2531cbe18e53a9bcfffa4f3409195b076163aa Mon Sep 17 00:00:00 2001 From: hangedman Date: Tue, 3 May 2022 19:43:54 +0900 Subject: [PATCH 8/9] Make enable filtering of bnfc-system-tests, fix failing system tests (#5) * Make enable filtering of bnfc-system-tests * Remove override keyword from clone() C++ * Add work-around of "transition table overflow, automaton is too big" https://stackoverflow.com/a/63461031/2565527 * Add yylval->emplace(); for escaped charcters * Deal with C++ NO STL * Add switching of smart-pointer on pp and absyn * Fix skelton code generator * Absyn list should append the last when adding the element * Remove dummy FlexLexer class * Fix C/C++ namespace problem * Fix bnfc define statement problem * Switch using shared-ptr or not, according to base-classes or token-classes * Fix cons impl in definedRules * Fix error handling * deal with reversible classes such that it can do left recursion --- source/src/BNFC/Backend/C.hs | 2 +- source/src/BNFC/Backend/C/CFtoBisonC.hs | 43 ++-- source/src/BNFC/Backend/C/CFtoFlexC.hs | 65 ++++-- source/src/BNFC/Backend/CPP/Common.hs | 29 ++- source/src/BNFC/Backend/CPP/Makefile.hs | 17 +- .../src/BNFC/Backend/CPP/NoSTL/CFtoCPPAbs.hs | 5 +- source/src/BNFC/Backend/CPP/PrettyPrinter.hs | 189 +++++++++--------- source/src/BNFC/Backend/CPP/STL.hs | 126 +++++++----- .../BNFC/Backend/CPP/STL/CFtoCVisitSkelSTL.hs | 40 ++-- source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs | 70 +++++-- source/src/BNFC/Backend/OCaml.hs | 2 +- testing/Main.hs | 19 +- testing/Makefile | 13 +- 13 files changed, 380 insertions(+), 240 deletions(-) diff --git a/source/src/BNFC/Backend/C.hs b/source/src/BNFC/Backend/C.hs index a35ed0e1..747c497a 100644 --- a/source/src/BNFC/Backend/C.hs +++ b/source/src/BNFC/Backend/C.hs @@ -62,7 +62,7 @@ makeC opts cf = do makefile :: String -> String -> String -> Doc makefile name prefix basename = vcat [ "CC = gcc -g" - , "CCFLAGS = --ansi -W -Wall -Wsign-conversion -Wno-unused-parameter -Wno-unused-function -Wno-unneeded-internal-declaration ${CC_OPTS}" + , "CCFLAGS = --ansi -W -Wall -Wsign-conversion -Wno-unused-parameter -Wno-unused-function ${CC_OPTS}" -- The @#define _POSIX_C_SOURCE 200809L@ is now placed locally in -- the generated lexer. -- , "CCFLAGS = --ansi -W -Wall -Wno-unused-parameter -Wno-unused-function -Wno-unneeded-internal-declaration -D_POSIX_C_SOURCE=200809L ${CC_OPTS}" diff --git a/source/src/BNFC/Backend/C/CFtoBisonC.hs b/source/src/BNFC/Backend/C/CFtoBisonC.hs index 54e0b3a7..a85f4996 100644 --- a/source/src/BNFC/Backend/C/CFtoBisonC.hs +++ b/source/src/BNFC/Backend/C/CFtoBisonC.hs @@ -31,7 +31,7 @@ import Prelude hiding ((<>)) import Data.Char ( toLower, isUpper ) import Data.Foldable ( toList ) import Data.List ( intercalate, nub ) -import Data.Maybe ( fromMaybe ) +import Data.Maybe ( fromMaybe, isJust ) import qualified Data.Map as Map import System.FilePath ( (<.>) ) @@ -115,16 +115,16 @@ cf2Bison rp mode cf env = unlines , prRules $ rulesForBison rp mode cf env , "%%" , "" - , nsStart inPackage + , nsStart ns , if (beyondAnsi mode) then unlines [ - "void " ++ns++ "::" ++camelCaseName++ "Parser::error(const " ++camelCaseName++ "Parser::location_type& l, const std::string& m)" + "void " ++nsScope parserNs++camelCaseName++ "Parser::error(const " ++nsScope parserNs++camelCaseName++ "Parser::location_type& l, const std::string& m)" , "{" - , " driver.error(l, m);" + , " driver.error(*scanner.loc, m);" , "}"] else entryCode mode cf -- entryCode for beyondAndi is in Driver - , nsEnd inPackage + , nsEnd ns ] where inPackage = parserPackage mode @@ -133,8 +133,10 @@ cf2Bison rp mode cf env = unlines | otherwise = [] name = parserName mode camelCaseName = camelCase_ name - ns = fromMaybe camelCaseName (parserPackage mode) - + ns = inPackage -- bnfc -p "package" + parserNs = case ns of + Just _ -> Nothing; -- Using above namespace, so not necessary parser name namespace + Nothing -> Just name; -- Using namespace generated by bison (see Makefile) positionCats :: CF -> [String] positionCats cf = [ wpThing name | TokenReg name True _ <- cfgPragmas cf ] @@ -149,12 +151,9 @@ header mode cf = unlines $ concat [ , "/* Generate header file for lexer. */" , "%defines \"" ++ ("Bison" <.> hExt) ++ "\"" ] - , when (beyondAnsi mode) - [ "%define api.namespace {" ++ ns ++ "}" + , when (and (beyondAnsi mode, isJust ns)) + [ "%define api.namespace {" ++ nsString ns ++ "}" , "/* Specify the namespace for the C++ parser class. */"] - , whenJust (parserPackage mode) $ \ ns -> - [ "%name-prefix = \"" ++ ns ++ "\"" - , "/* From Bison 2.6: %define api.prefix {" ++ ns ++ "} */"] , if beyondAnsi mode then -- Bison c++ beyond ansi mode ["" @@ -168,13 +167,13 @@ header mode cf = unlines $ concat [ , "%code requires{" , "#include \"Absyn" ++ hExt ++ "\"" , "" - , " namespace " ++ ns ++ " {" + , " " ++ nsStart ns , " class " ++ camelCaseName ++ "Scanner;" , " class " ++ camelCaseName ++ "Driver;" - , " }" + , " " ++ nsEnd ns , "}" - , "%parse-param { " ++ camelCaseName ++ "Scanner &scanner }" - , "%parse-param { " ++ camelCaseName ++ "Driver &driver }" + , "%parse-param { " ++ nsScope ns ++ camelCaseName ++ "Scanner &scanner }" + , "%parse-param { " ++ nsScope ns ++ camelCaseName ++ "Driver &driver }" , "" , "/* Turn on line/column tracking in the " ++name++ "lloc structure: */" , "%locations" @@ -256,7 +255,7 @@ header mode cf = unlines $ concat [ hExt = "." ++ parserHExt mode name = parserName mode camelCaseName = camelCase_ name - ns = fromMaybe camelCaseName (parserPackage mode) + ns = parserPackage mode -- | Code that needs the @YYSTYPE@ defined by the @%union@ pragma. -- @@ -486,12 +485,18 @@ rulesForBison :: RecordPositions -> ParserMode -> CF -> SymMap -> Rules rulesForBison rp mode cf env = map mkOne (ruleGroups cf) ++ posRules where mkOne (cat,rules) = constructRule rp mode cf env rules cat + scope = nsScope (parserPackage mode) posRules :: Rules posRules - | CppParser inPackage _ _ <- mode = for (positionCats cf) $ \ n -> (TokenCat n, + | CppParser inPackage _ Ansi <- mode = for (positionCats cf) $ \ n -> (TokenCat n, + [( Map.findWithDefault n (Tokentype n) env + , addResult mode cf (TokenCat n) $ concat + [ "$$ = new ", scope, n, "($1, @$.first_line);" ] + )]) + | CppParser inPackage _ BeyondAnsi <- mode = for (positionCats cf) $ \ n -> (TokenCat n, [( Map.findWithDefault n (Tokentype n) env , addResult mode cf (TokenCat n) $ concat - [ "$$ = new ", nsScope inPackage, n, "($1, @$.first_line);" ] + [ "$$ = std::make_shared<", scope, n, ">($1, @$.begin.line);" ] )]) | otherwise = [] diff --git a/source/src/BNFC/Backend/C/CFtoFlexC.hs b/source/src/BNFC/Backend/C/CFtoFlexC.hs index aebef876..45be18df 100644 --- a/source/src/BNFC/Backend/C/CFtoFlexC.hs +++ b/source/src/BNFC/Backend/C/CFtoFlexC.hs @@ -38,6 +38,7 @@ import BNFC.CF import BNFC.Backend.C.Common ( posixC ) import BNFC.Backend.C.RegToFlex import BNFC.Backend.Common.NamedVariables +import BNFC.Backend.CPP.STL.STLUtils import BNFC.Options ( InPackage, Ansi(..) ) import BNFC.PrettyPrint import BNFC.Utils ( cstring, symbolToName, unless, when, camelCase_ ) @@ -79,8 +80,8 @@ beyondAnsi = \case isBisonUseUnion :: ParserMode -> Bool isBisonUseUnion = \case - CppParser _ _ ansi | ansi == Ansi -> True - _ -> False + CppParser _ _ ansi | ansi == BeyondAnsi -> False + _ -> True isBisonUseVariant :: ParserMode -> Bool isBisonUseVariant = \case @@ -128,8 +129,8 @@ prelude stringLiterals mode = unlines $ concat , if (beyondAnsi mode) then unlines [ + -- note: bison bridge not supported for the C++ scanner. "%option nodefault noyywrap c++" - , "%option prefix=\"Bnfc\"" ] else unlines @@ -163,7 +164,7 @@ prelude stringLiterals mode = unlines $ concat "#include \"Scanner.hh\"" -- #include for the class inheriting "yyFlexLexer" , "" , "/* using \"token\" to make the returns for the tokens shorter to type */" - , "using token = " ++ns++ "::" ++camelCaseName++ "Parser::token;" + , "using token = " ++nsScope parserNs ++ camelCaseName++ "Parser::token;" , "" ] , "#include \"" ++ ("Absyn" <.> h) ++ "\"" @@ -180,7 +181,18 @@ prelude stringLiterals mode = unlines $ concat -- https://stackoverflow.com/a/22125500/425756 , if beyondAnsi mode then [ "/* update location on matching */" - , "#define YY_USER_ACTION loc->step(); loc->columns(yyleng);" + , "#define YY_USER_ACTION \\" + , "loc->begin.line = loc->end.line; \\" + , "loc->begin.column = loc->end.column; \\" + , "for(int i = 0; yytext[i] != '\\0'; i++) { \\" + , " if(yytext[i] == '\\n') { \\" + , " loc->end.line++; \\" + , " loc->end.column = 0; \\" + , " } \\" + , " else { \\" + , " loc->end.column++; \\" + , " } \\" + , "}" , "%}" ] else @@ -207,7 +219,11 @@ prelude stringLiterals mode = unlines $ concat h = parserHExt mode name = parserName mode camelCaseName = camelCase_ name - ns = fromMaybe camelCaseName (parserPackage mode) + ns = parserPackage mode -- bnfc -p "package" + parserNs = case ns of + Just _ -> ns; -- Using above namespace + Nothing -> Just name; -- Using namespace generated by bison (see Makefile) + -- | Part of the lexer prelude needed when string literals are to be lexed. -- Defines an interface to the Buffer. @@ -280,7 +296,7 @@ restOfFlex mode cf env = unlines $ concat ] , userDefTokens , ifC catString $ lexStrings mode (prefix++"_STRING_") (prefix++"_ERROR_") - , ifC catChar $ lexChars "yylval" (prefix++"_CHAR_") + , ifC catChar $ lexChars mode "yylval" (prefix++"_CHAR_") , ifC catDouble [ "{DIGIT}+\".\"{DIGIT}+(\"e\"(\\-)?{DIGIT}+)? \t " ++ (yylvalCopy mode "double" "yytext") ++ " return " ++prefix++ "_DOUBLE_;" ] , ifC catInteger [ "{DIGIT}+ \t " ++ (yylvalCopy mode "int" "yytext") ++ " return " ++prefix++ "_INTEGER_;" ] , ifC catIdent [ "{LETTER}{IDENT}* \t " ++ (yylvalCopy mode "string" "yytext") ++ " return " ++prefix++ "_IDENT_;" ] @@ -291,12 +307,12 @@ restOfFlex mode cf env = unlines $ concat ] , when (beyondAnsi mode) [ - "namespace " ++ns++ " {" + nsStart ns , "" , "" ++camelCaseName++ "Scanner::" ++camelCaseName++ "Scanner(std::istream *in)" - , " : BnfcFlexLexer(in)" + , " : yyFlexLexer(in)" , "{" - , " loc = new " ++camelCaseName++ "::" ++camelCaseName++ "Parser::location_type();" + , " loc = new " ++ nsScope parserNs ++camelCaseName++ "Parser::location_type();" , "}" , "" , "" ++camelCaseName++ "Scanner::~" ++camelCaseName++ "Scanner()" @@ -307,15 +323,15 @@ restOfFlex mode cf env = unlines $ concat , " * vtable of the class " ++camelCaseName++ "FlexLexer. We define the scanner's main yylex" , " * function via YY_DECL to reside in the Scanner class instead. */" , "" - , "}" + , nsEnd ns , "" , "#ifdef yylex" , "#undef yylex" , "#endif" , "" - , "int BnfcFlexLexer::yylex()" + , "int yyFlexLexer::yylex()" , "{" - , " std::cerr << \"in BnfcFlexLexer::yylex() !\" << std::endl;" + , " std::cerr << \"in yyFlexLexer::yylex() !\" << std::endl;" , " return 0;" , "}" ] @@ -323,8 +339,10 @@ restOfFlex mode cf env = unlines $ concat where name = parserName mode camelCaseName = camelCase_ name - ns = fromMaybe camelCaseName (parserPackage mode) - _inPackage = parserPackage mode + ns = parserPackage mode + parserNs = case ns of -- bnfc -p "package" + Just _ -> Nothing; -- Using above namespace, so not necessary parser name namespace + Nothing -> Just name; -- Using namespace generated by bison (see Makefile) prefix = if (beyondAnsi mode) then "token::" else "" ifC cat s = if isUsedCat cf (TokenCat cat) then s else [] userDefTokens = @@ -340,6 +358,7 @@ yylvalCopy mode typeStr arg = case (beyondAnsi mode, typeStr) of (True , "string") -> "yylval->emplace(" ++arg++ ");" (True , "int") -> "yylval->emplace(atoi(" ++arg++ "));" + (True , "double") -> "yylval->emplace(atof(" ++arg++ "));" (True , _ ) -> "yylval->emplace<" ++typeStr++ ">(" ++arg++ ");" (False, "string") -> "yylval->_string = strdup(" ++arg++ ");" (False, "int" ) -> "yylval->_int = atoi(" ++arg++ ");" @@ -379,8 +398,20 @@ lexStrings mode stringToken errorToken = ] -- | Lexing of characters, converting escaped characters. -lexChars :: String -> String -> [String] -lexChars yylval charToken = +lexChars :: ParserMode -> String -> String -> [String] +lexChars mode yylval charToken = + if isBisonUseVariant mode then + [ "\"'\" \tBEGIN CHAR;" + , "\\\\ \t BEGIN CHARESC;" + , "[^'] \t BEGIN CHAREND; " ++ yylval ++ "->emplace(yytext[0]); return " ++ charToken ++ ";" + , "f \t BEGIN CHAREND; " ++ yylval ++ "->emplace('\\f'); return " ++ charToken ++ ";" + , "n \t BEGIN CHAREND; " ++ yylval ++ "->emplace('\\n'); return " ++ charToken ++ ";" + , "r \t BEGIN CHAREND; " ++ yylval ++ "->emplace('\\r'); return " ++ charToken ++ ";" + , "t \t BEGIN CHAREND; " ++ yylval ++ "->emplace('\\t'); return " ++ charToken ++ ";" + , ". \t BEGIN CHAREND; " ++ yylval ++ "->emplace(yytext[0]); return " ++ charToken ++ ";" + , "\"'\" \t BEGIN INITIAL;" + ] + else [ "\"'\" \tBEGIN CHAR;" , "\\\\ \t BEGIN CHARESC;" , "[^'] \t BEGIN CHAREND; " ++ yylval ++ "->_char = yytext[0]; return " ++ charToken ++ ";" diff --git a/source/src/BNFC/Backend/CPP/Common.hs b/source/src/BNFC/Backend/CPP/Common.hs index 0719534b..5977d99f 100644 --- a/source/src/BNFC/Backend/CPP/Common.hs +++ b/source/src/BNFC/Backend/CPP/Common.hs @@ -21,8 +21,8 @@ commentWithEmacsModeHint = comment . ("-*- c++ -*- " ++) -- | C++ code for the @define@d constructors. -- -- @definedRules Nothing@ only prints the header. -definedRules :: Maybe ListConstructors -> CF -> String -> String -definedRules mlc cf banner +definedRules :: CppStdMode -> Maybe ListConstructors -> CF -> String -> String +definedRules mode mlc cf banner | null theLines = [] | otherwise = unlines $ banner : "" : theLines where @@ -42,13 +42,26 @@ definedRules mlc cf banner header = cppType t ++ " " ++ sanitizeCpp (funName f) ++ "(" ++ intercalate ", " (map cppArg args) ++ ")" + -- if ansi mode: T* + -- if beyond ansi mode: shared_ptr + wrapSharedPtrByMode :: String -> String + wrapSharedPtrByMode x = case mode of + CppStdAnsi _ -> x ++ "*" + CppStdBeyondAnsi _ -> wrapSharedPtr x + -- ansi mode: new T + -- beyond ansi mode: std::make_shared + wrapInstantiateByMode :: String -> String + wrapInstantiateByMode x = case mode of + CppStdAnsi _ -> "new " ++ x + CppStdBeyondAnsi _ -> wrapMakeShared x + cppType :: Base -> String - cppType (ListT (BaseT x)) = "List" ++ x ++ "*" - cppType (ListT t) = cppType t ++ "*" + cppType (ListT (BaseT x)) = wrapSharedPtrByMode ("List" ++ x) + cppType (ListT t) = wrapSharedPtrByMode (cppType t) cppType (BaseT x) | x `elem` baseTokenCatNames = x | isToken x ctx = "String" - | otherwise = x ++ "*" + | otherwise = wrapSharedPtrByMode x cppArg :: (String, Base) -> String cppArg (x,t) = cppType t ++ " " ++ x ++ "_" @@ -63,7 +76,7 @@ definedRules mlc cf banner App t _ [e] | isToken t ctx -> loop e App x _ es - | isUpper (head x) -> call ("new " ++ x) es + | isUpper (head x) -> call (wrapInstantiateByMode x) es | x `elem` args -> call (x ++ "_") es | otherwise -> call (sanitizeCpp x) es LitInt n -> show n @@ -73,6 +86,7 @@ definedRules mlc cf banner call x es = x ++ "(" ++ intercalate ", " (map loop es) ++ ")" + data CppStdMode = CppStdAnsi Ansi -- ^ @Ansi@ mode. | CppStdBeyondAnsi Ansi -- ^ @BeyondAnsi@ mode. @@ -85,3 +99,6 @@ wrapSharedPtrIf b v = if b then "std::shared_ptr<" ++v++">" else v wrapSharedPtr :: String -> String wrapSharedPtr v = "std::shared_ptr<" ++v++">" + +wrapMakeShared :: String -> String +wrapMakeShared v = "std::make_shared<" ++v++">" diff --git a/source/src/BNFC/Backend/CPP/Makefile.hs b/source/src/BNFC/Backend/CPP/Makefile.hs index 0d6c0f62..f0c8b098 100644 --- a/source/src/BNFC/Backend/CPP/Makefile.hs +++ b/source/src/BNFC/Backend/CPP/Makefile.hs @@ -6,6 +6,7 @@ import BNFC.Backend.Common.Makefile import BNFC.PrettyPrint import BNFC.Utils (when) + makefile :: String -> String -> SharedOptions -> String -> Doc makefile prefix name opts basename = vcat $ @@ -18,7 +19,7 @@ makefile prefix name opts basename = , mkVar "BISON" "bison" , mkVar "BISON_OPTS" ("-t -p" ++ prefix) , "" - , if (ansi opts /= Ansi) then + , if isBeyondAnsiCpp then mkVar "OBJS" "Absyn.o Buffer.o Lexer.o Parser.o Driver.o Printer.o" else mkVar "OBJS" "Absyn.o Buffer.o Lexer.o Parser.o Printer.o" @@ -52,7 +53,7 @@ makefile prefix name opts basename = , "${CC} ${OBJS} Test.o -o " ++ testName ] , mkRule "Absyn.o" [ "Absyn" ++ cppExt, "Absyn" ++ hExt ] [ "${CC} ${CCFLAGS} -c Absyn" ++ cppExt ] - , when (ansi opts /= Ansi) + , when isBeyondAnsiCpp mkRule "Driver.o" [ "Driver" ++ cppExt, "Driver" ++ hExt ] [ "${CC} ${CCFLAGS} -c Driver" ++ cppExt ] , mkRule "Buffer.o" [ "Buffer" ++ cppExt, "Buffer" ++ hExt ] @@ -76,8 +77,10 @@ makefile prefix name opts basename = ] where testName = "Test" ++ name - compileOpt = if Ansi == ansi opts then "--ansi" else "-std=c++14" - lexerExt = if Ansi == ansi opts then ".l" else ".ll" - parserExt = if Ansi == ansi opts then ".y" else ".yy" - cppExt = if Ansi == ansi opts then ".c" else ".cc" - hExt = if Ansi == ansi opts then ".h" else ".hh" + isBeyondAnsiCpp = and [ansi opts == BeyondAnsi, target opts == TargetCpp] + (compileOpt, lexerExt, parserExt, cppExt, hExt) = + case (ansi opts, target opts) of + (_, TargetCppNoStl) -> ("--ansi" , ".l" , ".y" , ".C ", ".H" ) + (Ansi, TargetCpp) -> ("--ansi" , ".l" , ".y" , ".c ", ".h" ) + (BeyondAnsi, _) -> ("-std=c++14", ".ll", ".yy", ".cc", ".hh") + (_, _) -> ("", "", "", "", "") diff --git a/source/src/BNFC/Backend/CPP/NoSTL/CFtoCPPAbs.hs b/source/src/BNFC/Backend/CPP/NoSTL/CFtoCPPAbs.hs index f8f6d598..d5aec77c 100644 --- a/source/src/BNFC/Backend/CPP/NoSTL/CFtoCPPAbs.hs +++ b/source/src/BNFC/Backend/CPP/NoSTL/CFtoCPPAbs.hs @@ -31,6 +31,7 @@ import BNFC.Utils ( (+++), (++++) ) import BNFC.Backend.Common.NamedVariables import BNFC.Backend.Common.OOAbstract import BNFC.Backend.CPP.Common +import BNFC.Options --The result is two files (.H file, .C file) cf2CPPAbs :: String -> CF -> (String, String) @@ -56,7 +57,7 @@ mkHFile cf = unlines "/******************** Abstract Syntax Classes ********************/\n", concatMap (prDataH user) (getAbstractSyntax cf), "", - definedRules Nothing cf + definedRules (CppStdAnsi Ansi) Nothing cf "/******************** Defined Constructors ********************/", "", "#endif" @@ -227,7 +228,7 @@ mkCFile cf = unlines [ header, concatMap (prDataC user) (getAbstractSyntax cf), - definedRules (Just $ LC nil cons) cf + definedRules (CppStdAnsi Ansi) (Just $ LC nil cons) cf "/******************** Defined Constructors ********************/" ] where diff --git a/source/src/BNFC/Backend/CPP/PrettyPrinter.hs b/source/src/BNFC/Backend/CPP/PrettyPrinter.hs index b6bc0bc9..923388ee 100644 --- a/source/src/BNFC/Backend/CPP/PrettyPrinter.hs +++ b/source/src/BNFC/Backend/CPP/PrettyPrinter.hs @@ -29,12 +29,13 @@ import Data.Char (toLower) import BNFC.CF import BNFC.Utils import BNFC.Backend.Common +import BNFC.Backend.Common.OOAbstract import BNFC.Backend.Common.NamedVariables import BNFC.Backend.Common.StrUtils (renderCharOrString) import BNFC.Backend.CPP.Common (CppStdMode(..)) import BNFC.Backend.CPP.STL.STLUtils import BNFC.PrettyPrint -import BNFC.Options (Ansi(..)) +import BNFC.Options() --Produces (.H file, .C file) cf2CPPPrinter :: CppStdMode -> Bool -> Maybe String -> CF -> String -> (String, String) @@ -231,13 +232,13 @@ mkCFile mode useStl inPackage cf groups hExt = concat printBasics, printTokens, showEntries, - concatMap (prShowData useStl mode) groups, + concatMap (prShowData useStl mode cabs) groups, showBasics, showTokens, nsEnd inPackage ++ "\n" ] where - + cabs = cf2cabs cf header = unlines [ "/*** Pretty Printer and Abstract Syntax Viewer ***/", @@ -389,24 +390,29 @@ mkCFile mode useStl inPackage cf groups hExt = concat -- | Generates methods for the Pretty Printer. prPrintData :: Bool -> CppStdMode -> Maybe String -> CF -> (Cat, [Rule]) -> String -prPrintData True mode _ _ (cat@(ListCat _), rules) = - render $ genPrintVisitorList (mode, cat, rules) -prPrintData False mode _ _ (cat@(ListCat _), rules) = - genPrintVisitorListNoStl (mode, cat, rules) + +prPrintData True mode _ cf (cat@(ListCat _), rules) = + render $ genPrintVisitorList (mode, cat, rules, cf) + +prPrintData False mode _ cf (cat@(ListCat _), rules) = + genPrintVisitorListNoStl (mode, cf2cabs cf, cat, rules) + prPrintData _ _ _inPackage cf (TokenCat cat, _rules) | isPositionCat cf cat = genPositionToken cat -prPrintData _ mode inPackage _cf (cat, rules) = - abstract ++ concatMap (prPrintRule mode inPackage) rules + +prPrintData _ mode inPackage cf (cat, rules) = + abstract ++ concatMap (prPrintRule mode cabs inPackage) rules where cl = identCat (normCat cat) + cabs = cf2cabs cf abstract = case lookupRule (noPosition $ catToStr cat) rules of Just _ -> "" Nothing -> "void PrintAbsyn::visit" ++ cl ++ "(" ++ cl +++ "*p) {} //abstract class\n\n" -- | Generate pretty printer visitor for a list category (STL version). -- -genPrintVisitorList :: (CppStdMode, Cat, [Rule]) -> Doc -genPrintVisitorList (mode, cat@(ListCat _), rules) = vcat +genPrintVisitorList :: (CppStdMode, Cat, [Rule], CF) -> Doc +genPrintVisitorList (mode, cat@(ListCat _), rules, cf) = vcat [ "void PrintAbsyn::visit" <> lty <> parens (ltyarg <> "*" <+> varg) , codeblock 2 [ "iter" <> lty <> parens (vname <> "->begin()" <> comma <+> vname <> "->end()") <> semi ] @@ -438,6 +444,8 @@ genPrintVisitorList (mode, cat@(ListCat _), rules) = vcat , "" ] where + cabs = cf2cabs cf + primitives = [c | (c,_) <- basetypes] ++ tokentypes cabs cl = identCat (normCat cat) lty = text cl -- List type ltyarg = text cl -- List type arg @@ -445,19 +453,35 @@ genPrintVisitorList (mode, cat@(ListCat _), rules) = vcat vname = text $ map toLower cl varg = text $ (map toLower cl) prules = sortRulesByPrecedence rules - swRules f = switchByPrecedence "_i_" $ - map (second $ sep . prListRuleFn) $ - uniqOn fst $ filter f prules - -- Discard duplicates, can only handle one rule per precedence. + -- Discard duplicates, can only handle one rule per precedence. + swRules f = switchByPrecedence "_i_" $ map (second $ sep . prListRuleFn) $ uniqOn fst $ filter f prules docs0 = swRules isNilFun docs1 = swRules isOneFun docs2 = swRules isConsFun + + -- | Only render the rhs (items) of a list rule. + prListRuleFn :: IsFun a => Rul a -> [Doc] + prListRuleFn (Rule _ _ items _) = for items $ \case + Right t -> "render(" <> text (snd (renderCharOrString t)) <> ");" + Left c + | Just{} <- maybeTokenCat c + -> "visit" <> dat <> "(" <> visitArg <> ");" + | isList c -> "iter" <> dat <> "(" <> nextArg <> ");" + | otherwise -> "(*i)->accept(this);" + where + dat = text $ identCat $ normCat c + bas = show dat + isPrimitive = elem bas primitives + nextArg = case mode of + CppStdBeyondAnsi _ -> "std::next(i,1), j" + CppStdAnsi _ -> "i+1, j" + visitArg = case (mode, isPrimitive) of + (CppStdBeyondAnsi _, _) -> "*i->get()" + (CppStdAnsi _, _) -> "*i" + prevJ = case mode of CppStdBeyondAnsi _ -> "std::prev(j, 1)" CppStdAnsi _ -> "j-1" - prListRuleFn = case mode of - CppStdBeyondAnsi _ -> prListRuleBeyondAnsi - CppStdAnsi _ -> prListRuleAnsi genPrintVisitorList _ = error "genPrintVisitorList expects a ListCat" @@ -471,35 +495,12 @@ genPositionToken cat = unlines $ , "" ] --- | Only render the rhs (items) of a list rule. - -prListRuleBeyondAnsi :: IsFun a => Rul a -> [Doc] -prListRuleBeyondAnsi (Rule _ _ items _) = for items $ \case - Right t -> "render(" <> text (snd (renderCharOrString t)) <> ");" - Left c - | Just{} <- maybeTokenCat c - -> "visit" <> dat <> "(*i);" - | isList c -> "iter" <> dat <> "(std::next(i,1), j);" - | otherwise -> "(*i)->accept(this);" - where - dat = text $ identCat $ normCat c - -prListRuleAnsi :: IsFun a => Rul a -> [Doc] -prListRuleAnsi (Rule _ _ items _) = for items $ \case - Right t -> "render(" <> text (snd (renderCharOrString t)) <> ");" - Left c - | Just{} <- maybeTokenCat c - -> "visit" <> dat <> "(*i);" - | isList c -> "iter" <> dat <> "(i+1, j);" - | otherwise -> "(*i)->accept(this);" - where - dat = text $ identCat $ normCat c -- This is the only part of the pretty printer that differs significantly -- between the versions with and without STL. -- The present version has been adapted from CFtoCPrinter. -genPrintVisitorListNoStl :: (CppStdMode, Cat, [Rule]) -> String -genPrintVisitorListNoStl (mode, cat@(ListCat _), rules) = unlines $ concat +genPrintVisitorListNoStl :: (CppStdMode, CAbs, Cat, [Rule]) -> String +genPrintVisitorListNoStl (mode, cabs, cat@(ListCat _), rules) = unlines $ concat [ [ "void PrintAbsyn::visit" ++ cl ++ "("++ cl ++ " *" ++ vname ++ ")" , "{" , " if (" ++ vname +++ "== 0)" @@ -525,24 +526,25 @@ genPrintVisitorListNoStl (mode, cat@(ListCat _), rules) = unlines $ concat ] ] where + prPrintRuleFn :: IsFun a => String -> Rul a -> [String] + prPrintRuleFn pre (Rule _ _ items _) = map (prPrintItem mode cabs pre) $ numVars items + cl = identCat (normCat cat) vname = map toLower cl pre = vname ++ "->" prules = sortRulesByPrecedence rules - prPrintRuleFn = case mode of - CppStdBeyondAnsi _ -> prPrintRuleBeyondAnsi - CppStdAnsi _ -> prPrintRuleAnsi swRules f = switchByPrecedence "_i_" $ map (second $ sep . map text . prPrintRuleFn pre) $ uniqOn fst $ filter f prules -- Discard duplicates, can only handle one rule per precedence. + genPrintVisitorListNoStl _ = error "genPrintVisitorListNoStl expects a ListCat" --Pretty Printer methods for a rule. -prPrintRule :: CppStdMode -> Maybe String -> Rule -> String -prPrintRule mode inPackage r@(Rule fun _ _ _) | isProperLabel fun = unlines $ concat +prPrintRule :: CppStdMode -> CAbs -> Maybe String -> Rule -> String +prPrintRule mode cabs inPackage r@(Rule fun _ _ _) | isProperLabel fun = unlines $ concat [ [ "void PrintAbsyn::visit" ++ visitFunName ++ "(" ++ vararg +++ fnm ++ ")" , "{" , " int oldi = _i_;" @@ -563,38 +565,37 @@ prPrintRule mode inPackage r@(Rule fun _ _ _) | isProperLabel fun = unlines $ co p = precRule r parenCode x = " if (oldi > " ++ show p ++ ") render(" ++ nsDefine inPackage x ++ ");" fnm = "p" --old names could cause conflicts - prPrintRuleFn = case mode of - CppStdBeyondAnsi _ -> prPrintRuleBeyondAnsi - CppStdAnsi _ -> prPrintRuleAnsi - -prPrintRule _ _ _ = "" -prPrintRuleAnsi :: IsFun a => String -> Rul a -> [String] -prPrintRuleAnsi pre (Rule _ _ items _) = map (prPrintItem (CppStdAnsi Ansi) pre) $ numVars items + prPrintRuleFn :: IsFun a => String -> Rul a -> [String] + prPrintRuleFn pre (Rule _ _ items _) = map (prPrintItem mode cabs pre) $ numVars items -prPrintRuleBeyondAnsi :: IsFun a => String -> Rul a -> [String] -prPrintRuleBeyondAnsi pre (Rule _ _ items _) = map (prPrintItem (CppStdBeyondAnsi Ansi) pre) $ numVars items +prPrintRule _ _ _ _ = "" -- note: this is otherwise pattern, is there any good code style? --This goes on to recurse to the instance variables. -prPrintItem :: CppStdMode -> String -> Either (Cat, Doc) String -> String -prPrintItem _ _ (Right t) = " render(" ++ snd (renderCharOrString t) ++ ");" -prPrintItem mode pre (Left (c, nt)) - | Just t <- maybeTokenCat c = " visit" ++ t ++ "(" ++ pre ++ s ++ ");" - | isList c = " " ++ setI (precCat c) ++ "visit" ++ elt ++ "(" ++ pre ++ s ++ toRawPtr ++ ");" +prPrintItem :: CppStdMode -> CAbs -> String -> Either (Cat, Doc) String -> String +prPrintItem _ _ _ (Right t) = " render(" ++ snd (renderCharOrString t) ++ ");" +prPrintItem mode cabs pre (Left (c, nt)) + | Just t <- maybeTokenCat c = " visit" ++ t ++ "(" ++ pre ++ visitArg ++ ");" + | isList c = " " ++ setI (precCat c) ++ "visit" ++ elt ++ "(" ++ pre ++ visitArg ++ ");" | otherwise = " " ++ setI (precCat c) ++ pre ++ s ++ "->accept(this);" where - s = render nt elt = identCat $ normCat c - toRawPtr = case mode of - CppStdBeyondAnsi _ -> ".get()" - CppStdAnsi _ -> "" + s = render nt + primitives = [c | (c,_) <- basetypes] ++ tokentypes cabs + visitArg = case (mode, maybeTokenCat c) of + (CppStdBeyondAnsi _, Just t) + | not $ elem t primitives -> s ++ ".get()" -- not primitive + | otherwise -> s -- primitive + (CppStdBeyondAnsi _, Nothing) + | otherwise -> s ++ ".get()" -- list is not primitive + (CppStdAnsi _, _) -> s -- ansi using raw pointer {- **** Abstract Syntax Tree Printer **** -} --This prints the functions for Abstract Syntax tree printing. -prShowData :: Bool -> CppStdMode -> (Cat, [Rule]) -> String -prShowData True mode (cat@(ListCat c), _) = unlines +prShowData :: Bool -> CppStdMode -> CAbs -> (Cat, [Rule]) -> String +prShowData True mode _ (cat@(ListCat c), _) = unlines [ "void ShowAbsyn::visit" ++ cl ++ "("++ cl ++ " *" ++ vname ++ ")", "{", @@ -602,7 +603,7 @@ prShowData True mode (cat@(ListCat c), _) = unlines vname++"->begin() ; i != " ++vname ++"->end() ; ++i)", " {", if isTokenCat c - then " visit" ++ baseName cl ++ "(*i) ;" + then " visit" ++ baseName cl ++ "(" ++visitArg++ ") ;" else " (*i)->accept(this);", case mode of CppStdBeyondAnsi _ -> " if (i != std::prev(" ++ vname ++ "->end(), 1)) bufAppend(\", \");" @@ -614,8 +615,12 @@ prShowData True mode (cat@(ListCat c), _) = unlines where cl = identCat (normCat cat) vname = map toLower cl + visitArg = case mode of + CppStdBeyondAnsi _ -> "*i->get()" + _ -> "*i" + -prShowData False _ (cat@(ListCat c), _) = +prShowData False _ _ (cat@(ListCat c), _) = unlines [ "void ShowAbsyn::visit" ++ cl ++ "("++ cl ++ " *" ++ vname ++ ")", @@ -648,10 +653,10 @@ prShowData False _ (cat@(ListCat c), _) = | otherwise = " " ++ vname ++ "->" ++ member ++ "->accept(this);" -prShowData _ mode (cat, rules) = --Not a list: - abstract ++ unlines [prShowRule rule beyondAnsi | rule <- rules] +prShowData _ mode cabs (cat, rules) = -- Not a list: + abstract ++ unlines [prShowRule rule isBeyondAnsi cabs | rule <- rules] where - beyondAnsi = case mode of + isBeyondAnsi = case mode of CppStdBeyondAnsi _ -> True CppStdAnsi _ -> False cl = identCat (normCat cat) @@ -660,8 +665,8 @@ prShowData _ mode (cat, rules) = --Not a list: Nothing -> "void ShowAbsyn::visit" ++ cl ++ "(" ++ cl ++ " *p) {} //abstract class\n\n" --This prints all the methods for Abstract Syntax tree rules. -prShowRule :: IsFun f => Rul f -> Bool -> String -prShowRule (Rule f _ cats _) _ | isProperLabel f = concat +prShowRule :: IsFun f => Rul f -> Bool -> CAbs -> String +prShowRule (Rule f _ cats _) isBeyondAnsi cabs | isProperLabel f = concat [ "void ShowAbsyn::visit" ++ fun ++ "(" ++ vararg +++ fnm ++ ")\n", "{\n", @@ -674,33 +679,31 @@ prShowRule (Rule f _ cats _) _ | isProperLabel f = concat ] where fun = funName f + fnm = "p" --other names could cause conflicts vararg = funName fun ++ "*" (optspace, lparen, rparen, cats') | null [ () | Left _ <- cats ] -- @all isRight cats@, but Data.Either.isRight requires base >= 4.7 = ("", "", "", "") | otherwise = (" bufAppend(' ');\n", " bufAppend('(');\n"," bufAppend(')');\n" - , concat (insertSpaces (map (prShowCat fnm) (numVars cats)))) + , concat (insertSpaces (map prShowCatFn (numVars cats)))) insertSpaces [] = [] insertSpaces (x:[]) = [x] insertSpaces (x:xs) = if x == "" then insertSpaces xs else x : " bufAppend(' ');\n" : insertSpaces xs - fnm = "p" --other names could cause conflicts + -- To set cpp information, use partial application of function + prShowCatFn = prShowCat fnm isBeyondAnsi cabs -prShowRule _ _ = "" +prShowRule _ _ _ = "" -- This recurses to the instance variables of a class. -prShowCat :: String -> Either (Cat, Doc) String -> String -prShowCat _ (Right _) = "" -prShowCat fnm (Left (cat, nt)) +prShowCat :: String -> Bool -> CAbs -> Either (Cat, Doc) String -> String +prShowCat _ _ _ (Right _) = "" +prShowCat fnm isBeyondAnsi cabs (Left (cat, nt)) | Just t <- maybeTokenCat cat = - unlines - [ " visit" ++ t ++ "(" ++ fnm ++ "->" ++ s ++ ");" - ] + " visit" ++ t ++ "(" ++ fnm ++ "->" ++ visitArg ++ ");" | catToStr (normCat $ strToCat s) /= s = - unlines - [ accept - ] + unlines [ accept ] | otherwise = unlines [ " bufAppend('[');" @@ -708,8 +711,16 @@ prShowCat fnm (Left (cat, nt)) , " bufAppend(']');" ] where - s = render nt - accept = " " ++ fnm ++ "->" ++ s ++ "->accept(this);" + s = render nt + accept = " " ++ fnm ++ "->" ++ s ++ "->accept(this);" + primitives = [c | (c,_) <- basetypes] ++ tokentypes cabs + visitArg = case (isBeyondAnsi, maybeTokenCat cat) of + (True, Just t) + | not $ elem t primitives -> s ++ ".get()" -- not primitive + | otherwise -> s -- primitive + (True, Nothing) + | otherwise -> s ++ ".get()" -- list is not primitive + (False, _) -> s -- ansi using raw pointer {- **** Helper Functions Section **** -} diff --git a/source/src/BNFC/Backend/CPP/STL.hs b/source/src/BNFC/Backend/CPP/STL.hs index e6703b42..5639697f 100644 --- a/source/src/BNFC/Backend/CPP/STL.hs +++ b/source/src/BNFC/Backend/CPP/STL.hs @@ -12,12 +12,13 @@ module BNFC.Backend.CPP.STL (makeCppStl,) where import Data.Foldable (toList) import Data.List ( nub ) import qualified Data.Map as Map -import Data.Maybe ( fromMaybe ) +import Data.Maybe() import BNFC.Utils import BNFC.CF import BNFC.Options import BNFC.PrettyPrint +import BNFC.Backend.Common.OOAbstract import BNFC.Backend.Base import BNFC.Backend.C ( bufferH, bufferC, comment, testfileHeader ) import BNFC.Backend.C.CFtoBisonC ( cf2Bison, unionBuiltinTokens, positionCats, varName ) @@ -159,7 +160,7 @@ cpptest mode inPackage cf hExt = unlines $ concat , " " ++ (wrapSharedPtr $ scope ++ dat) ++ " parse_tree = nullptr;" , " try { " , "" - , " auto driver = std::make_unique<" ++ns++ "::" ++camelCaseName++ "Driver>();" + , " auto driver = std::make_unique<" ++nsScope driverNS++camelCaseName++ "Driver>();" , " if (filename) {" , " std::ifstream input(filename);" , " if ( ! input.good() ) {" @@ -202,7 +203,7 @@ cpptest mode inPackage cf hExt = unlines $ concat , " /* The default entry point is used. For other options see Parser.H */" , " " ++ scope ++ dat ++ " *parse_tree = NULL;" , " try { " - ," parse_tree = " ++ scope ++ "p" ++ def ++ "(input);" + ," parse_tree = p" ++ def ++ "(input);" ] , " } catch( " ++ scope ++ "parse_error &e) {" , " std::cerr << \"Parse error on line \" << e.getLine() << \"\\n\"; " @@ -213,23 +214,23 @@ cpptest mode inPackage cf hExt = unlines $ concat , " printf(\"\\nParse Successful!\\n\");" , if beyondAnsi mode then unlines [ - " if (!quiet) {" + " if (!quiet) {" , " printf(\"\\n[Abstract Syntax]\\n\");" - , " auto s = std::make_unique<" ++ scope ++ "ShowAbsyn>(" ++ scope ++ "ShowAbsyn());" + , " auto s = std::make_unique<" ++nsScope ns++"ShowAbsyn>(" ++nsScope ns++"ShowAbsyn());" , " printf(\"%s\\n\\n\", s->show(parse_tree.get()));" , " printf(\"[Linearized Tree]\\n\");" - , " auto p = std::make_unique<" ++ scope ++ "PrintAbsyn>(" ++ scope ++ "PrintAbsyn());" + , " auto p = std::make_unique<" ++nsScope ns++"PrintAbsyn>(" ++nsScope ns++"PrintAbsyn());" , " printf(\"%s\\n\\n\", p->print(parse_tree.get()));" , " }" ] else unlines [ - " if (!quiet) {" + " if (!quiet) {" , " printf(\"\\n[Abstract Syntax]\\n\");" - , " "++ scope ++ "ShowAbsyn *s = new " ++ scope ++ "ShowAbsyn();" + , " " ++nsScope ns++"ShowAbsyn *s = new " ++nsScope ns++"ShowAbsyn();" , " printf(\"%s\\n\\n\", s->show(parse_tree));" , " printf(\"[Linearized Tree]\\n\");" - , " " ++ scope ++ "PrintAbsyn *p = new " ++ scope ++ "PrintAbsyn();" + , " " ++nsScope ns++"PrintAbsyn *p = new " ++nsScope ns++"PrintAbsyn();" , " printf(\"%s\\n\\n\", p->print(parse_tree));" , " }" , " delete(parse_tree);" @@ -247,7 +248,8 @@ cpptest mode inPackage cf hExt = unlines $ concat scope = nsScope inPackage name = parserName mode camelCaseName = camelCase_ name - ns = fromMaybe camelCaseName (parserPackage mode) + ns = inPackage + driverNS = inPackage mkHeaderFile :: ParserMode -> String -> Maybe String -> CF -> [Cat] -> [Cat] -> [String] -> String mkHeaderFile mode hExt inPackage _cf _cats eps _env = unlines $ concat @@ -296,7 +298,7 @@ driverH mode cf cats = unlines , "#include \"Scanner.hh\"" , "#include \"Parser.hh\"" , "" - , "namespace " ++ns++ "{" + , nsStart ns , "" , "class " ++camelCaseName++ "Driver{" , "public:" @@ -323,9 +325,8 @@ driverH mode cf cats = unlines , " * @param is - std::istream&, valid input stream" , " */" , " void parse(std::istream &iss);" - , " /** Error handling with associated line number. This can be modified to" - , " * output the error. */" - , " void error(const class location& l, const std::string& m);" + , " /** Error handling with associated line number. This can be modified to output the error. */" + , " void error(const " ++nsScope parserNs++camelCaseName++ "Parser::location_type& l, const std::string& m);" , "" , " std::ostream& print(std::ostream &stream);" , "" @@ -333,21 +334,24 @@ driverH mode cf cats = unlines , " bool trace_scanning = false;" , " bool trace_parsing = false;" , "" - , "private:" + , " std::unique_ptr<" ++camelCaseName++ "Scanner> scanner = nullptr;" + , " std::unique_ptr<" ++ nsScope parserNs ++camelCaseName++ "Parser> parser = nullptr;" , "" + , "private:" , " void parse_helper( std::istream &stream );" , "" - , " std::unique_ptr<" ++camelCaseName++ "Scanner> scanner = nullptr;" - , " std::unique_ptr<" ++camelCaseName++ "Parser> parser = nullptr;" , "};" , "" - , "} /* end namespace " ++ns++ " */" + , nsEnd ns , "#endif /* END __DRIVER_H__ */" ] where name = parserName mode camelCaseName = camelCase_ name - ns = fromMaybe camelCaseName (parserPackage mode) + ns = parserPackage mode -- bnfc -p "package" + parserNs = case ns of + Just ns -> Just ns; -- Using above namespace + Nothing -> Just name; -- Using namespace generated by bison (see Makefile) normCats = nub (map normCat cats) entryPoints = toList (allEntryPoints cf) mkStreamEntry s = @@ -361,15 +365,16 @@ driverC mode cf _ = unlines [ "#include " , "#include " , "#include " - , " " + , "" , "#include \"Driver.hh\"" - , " " - , "" ++ns++ "::" ++camelCaseName++ "Driver::~" ++camelCaseName++ "Driver()" + , nsStart ns + , "" + , "" ++camelCaseName++ "Driver::~" ++camelCaseName++ "Driver()" , "{" , "}" , " " , "void " - , ns++ "::" ++camelCaseName++ "Driver::parse( const char * const filename )" + , camelCaseName++ "Driver::parse( const char * const filename )" , "{" , " /**" , " * Remember, if you want to have checks in release mode" @@ -386,7 +391,7 @@ driverC mode cf _ = unlines , "}" , " " , "void" - , ns++ "::" ++camelCaseName++ "Driver::parse( std::istream &stream )" + , camelCaseName++ "Driver::parse( std::istream &stream )" , "{" , " if( ! stream.good() && stream.eof() ) {" , " return;" @@ -396,18 +401,23 @@ driverC mode cf _ = unlines , "}" , " " , "void" - , ns++ "::" ++camelCaseName++ "Driver::error( const class location& l, const std::string& m )" + , camelCaseName++ "Driver::error( const " ++nsScope parserNs++camelCaseName++ "Parser::location_type& l, const std::string& m )" , "{" - , " std::cerr << l << \": \" << m << std::endl;" + , " std::cerr << \"error: \"" + , " << scanner->loc->begin.line << \",\" << scanner->loc->begin.column" + , " << \": \"" + , " << m" + , " << \" at \" << std::string(scanner->YYText())" + , " << std::endl;" , "}" - , " " + , "" , "void " - , ns++ "::" ++camelCaseName++ "Driver::parse_helper( std::istream &stream )" + , camelCaseName++ "Driver::parse_helper( std::istream &stream )" , "{" , "" , " scanner.reset();" , " try {" - , " scanner = std::make_unique<" ++ns++ "::" ++camelCaseName++ "Scanner>( &stream );" + , " scanner = std::make_unique<" ++camelCaseName++ "Scanner>( &stream );" , " scanner->set_debug(trace_scanning);" , " } catch( std::bad_alloc &ba ) {" , " std::cerr << \"Failed to allocate scanner: (\"" @@ -418,7 +428,7 @@ driverC mode cf _ = unlines , "" , " parser.reset(); " , " try {" - , " parser = std::make_unique<" ++ns++ "::" ++camelCaseName++ "Parser>((*scanner), (*this));" + , " parser = std::make_unique<" ++nsScope parserNs++camelCaseName++ "Parser>((*scanner), (*this));" , " } catch( std::bad_alloc &ba ) {" , " std::cerr << \"Failed to allocate parser: (\"" , " << ba.what() " @@ -429,29 +439,39 @@ driverC mode cf _ = unlines , "" , " parser->set_debug_level (trace_parsing);" , " if( parser->parse() != accept ) {" - , " std::cerr << \"Parse failed!!\\n\";" + , " exit( EXIT_FAILURE );" , " }" , " return;" , "}" , "" , unlines [ mkStreamEntry ep | ep <- entryPoints ] + , nsEnd ns ] where name = parserName mode camelCaseName = camelCase_ name - ns = fromMaybe camelCaseName (parserPackage mode) + ns = parserPackage mode -- bnfc -p "package" + parserNs = case ns of + Just _ -> ns; -- Using above namespace, so not necessary parser name namespace + Nothing -> Just name; -- Using namespace generated by bison (see Makefile) entryPoints = toList (allEntryPoints cf) + reversibleCats = cfgReversibleCats cf + mkStreamEntry s = unlines [ (wrapSharedPtr $ identCat (normCat s)) - , ns++ "::" ++camelCaseName++ "Driver::p" ++ identCat s ++ "(std::istream &stream)" + , camelCaseName++ "Driver::p" ++ identCat s ++ "(std::istream &stream)" , "{" , " parse_helper( stream );" + , if isList s && not (s `elem` reversibleCats) then + " this->" ++ varName s++ "->reverse();" + else + "" , " return this->" ++ varName s++ ";" , "}" ] --- | C++ lexer def +-- | C++ lexer def (scanner.hh) scannerH :: ParserMode -> String scannerH mode = unlines @@ -463,48 +483,48 @@ scannerH mode = unlines , "#ifndef YY_DECL" , "#define YY_DECL \\" , " int \\" - , " " ++ns++ "::" ++camelCaseName++ "Scanner::lex( \\" - , " " ++ns++ "::" ++camelCaseName++ "Parser::semantic_type* const yylval, \\" - , " " ++ns++ "::" ++camelCaseName++ "Parser::location_type* yylloc \\" + , " " ++ nsScope ns ++camelCaseName++ "Scanner::lex( \\" + , " " ++ nsScope parserNs ++camelCaseName++ "Parser::semantic_type* const yylval, \\" + , " " ++ nsScope parserNs ++camelCaseName++ "Parser::location_type* yylloc \\" , " )" , "#endif" , "" - , "#ifndef __FLEX_LEXER_H" - , "#define yyFlexLexer BnfcFlexLexer" -- This name is dummy - , "#include \"FlexLexer.h\"" - , "#undef yyFlexLexer" + -- Inherit from yyFlexLexer, create a subclass with naming "XXXScanner" + -- https://stackoverflow.com/a/40665154/2565527 + , "#if !defined(yyFlexLexerOnce)" + , "# include \"FlexLexer.h\"" , "#endif" , "" , "#include \"Bison.hh\"" , "#include \"location.hh\"" , "" - , "namespace " ++ns++ "{" + , nsStart ns , "" - , "class " ++camelCaseName++ "Scanner : public BnfcFlexLexer {" + , "class " ++camelCaseName++ "Scanner : public yyFlexLexer {" , "public:" , "" , " " ++camelCaseName++ "Scanner(std::istream *in);" , " virtual ~" ++camelCaseName++ "Scanner();" , "" , " virtual" - , " int lex( " ++ns++ "::" ++camelCaseName++ "Parser::semantic_type * const lval," - , " " ++ns++ "::" ++camelCaseName++ "Parser::location_type *location );" - , " // YY_DECL defined in mc_lexer.l" - , " // Method body created by flex in mc_lexer.yy.cc" - , "" + , " int lex( " ++ nsScope parserNs ++camelCaseName++ "Parser::semantic_type * const lval," + , " " ++ nsScope parserNs ++camelCaseName++ "Parser::location_type *location );" + , " // YY_DECL defined in .ll file. Method body created by flex in Lexer.cc" , "" - , "private:" , " /* yyval ptr */" - , " " ++ns++ "::" ++camelCaseName++ "Parser::semantic_type *yylval = nullptr;" + , " " ++ nsScope parserNs ++camelCaseName++ "Parser::semantic_type *yylval = nullptr;" , " /* location ptr */" - , " " ++ns++ "::" ++camelCaseName++ "Parser::location_type *loc = nullptr;" + , " " ++ nsScope parserNs ++camelCaseName++ "Parser::location_type *loc = nullptr;" , "};" , "" - , "} /* end namespace " ++ns++ " */" + , nsEnd ns , "" , "#endif /* END __SCANNER_H__ */" ] where name = parserName mode camelCaseName = camelCase_ name - ns = fromMaybe camelCaseName (parserPackage mode) + ns = parserPackage mode -- bnfc -p "package" + parserNs = case ns of + Just _ -> Nothing; -- Using above namespace, so not necessary parser name namespace + Nothing -> Just name; -- Using namespace generated by bison (see Makefile) diff --git a/source/src/BNFC/Backend/CPP/STL/CFtoCVisitSkelSTL.hs b/source/src/BNFC/Backend/CPP/STL/CFtoCVisitSkelSTL.hs index 2651c875..6a7ba093 100644 --- a/source/src/BNFC/Backend/CPP/STL/CFtoCVisitSkelSTL.hs +++ b/source/src/BNFC/Backend/CPP/STL/CFtoCVisitSkelSTL.hs @@ -21,23 +21,27 @@ import BNFC.Options import BNFC.Utils ((+++), unless) import BNFC.Backend.Common.OOAbstract import BNFC.Backend.CPP.Naming +import BNFC.Backend.CPP.Common (CppStdMode(..)) import BNFC.Backend.CPP.STL.STLUtils ---Produces (.H file, .C file) +--Produces (header file, c/c++ file) cf2CVisitSkel :: SharedOptions -> Bool -> Maybe String -> CF -> (String, String) cf2CVisitSkel opts useSTL inPackage cf = - ( mkHFile useSTL hExt inPackage cab - , mkCFile useSTL hExt inPackage cab + ( mkHFile mode useSTL hExt inPackage cab + , mkCFile mode useSTL hExt inPackage cab ) where cab = cf2cabs cf - hExt = if Ansi == ansi opts then ".h" else ".hh" + (mode, hExt) = case (ansi opts, useSTL) of + (BeyondAnsi, True ) -> ( CppStdBeyondAnsi (ansi opts), ".hh" ) + ( Ansi, True ) -> ( CppStdAnsi (ansi opts) , ".h" ) + (_ , False) -> ( CppStdAnsi (ansi opts) , ".H" ) -- **** Header (.H) File Functions **** --Generates the Header File -mkHFile :: Bool -> String -> Maybe String -> CAbs -> String -mkHFile useSTL hExt inPackage cf = unlines [ +mkHFile :: CppStdMode -> Bool -> String -> Maybe String -> CAbs -> String +mkHFile _ useSTL hExt inPackage cf = unlines [ "#ifndef " ++ hdef, "#define " ++ hdef, "/* You might want to change the above name. */", @@ -72,14 +76,14 @@ basics useSTL cf = concat -- **** Implementation (.C) File Functions **** --Makes the .C File -mkCFile :: Bool -> String -> Maybe String -> CAbs -> String -mkCFile useSTL hExt inPackage cf = unlines [ +mkCFile :: CppStdMode -> Bool -> String -> Maybe String -> CAbs -> String +mkCFile mode useSTL hExt inPackage cf = unlines [ headerC hExt, nsStart inPackage, unlines [ "void Skeleton::visit" ++ t ++ "(" ++ t ++ " *t) {} //abstract class" | t <- absclasses cf], unlines [ prCon r | (_,rs) <- signatures cf, r <- rs, useSTL || not (posRule r) ], - unlines [ prList useSTL cb | cb <- listtypes cf ], + unlines [ prList mode useSTL cb | cb <- listtypes cf ], unlines [ prBasic b | b <- base ], nsEnd inPackage ] @@ -103,6 +107,7 @@ mkCFile useSTL hExt inPackage cf = unlines [ | otherwise = "visit" ++ cat ++ "(" ++ field ++ ");" where field = v ++ "->" ++ var +headerC :: [Char] -> String headerC hExt = unlines [ "/*** Visitor Design Pattern Skeleton. ***/", "/* This implements the common visitor design pattern.", @@ -114,6 +119,7 @@ headerC hExt = unlines [ "" ] +prBasic :: [Char] -> String prBasic c = unlines [ "void Skeleton::visit" ++ c ++ "(" ++ c ++ " x)", "{", @@ -121,7 +127,11 @@ prBasic c = unlines [ "}" ] -prList True (cl,b) = unlines [ + +prList :: CppStdMode -> Bool -> (String, Bool) -> String + +-- useSTL = True +prList mode True (cl,b) = unlines [ "void Skeleton::visit" ++ cl ++ "("++ cl +++ "*" ++ vname ++ ")", "{", " for ("++ cl ++"::iterator i = " ++ @@ -129,14 +139,20 @@ prList True (cl,b) = unlines [ " {", if b then " (*i)->accept(this);" - else " visit" ++ drop 4 cl ++ "(*i) ;", + else " visit" ++ drop 4 cl ++ "(" ++visitArg++ ") ;", " }", "}" ] where vname = mkVariable cl + childCl = drop 4 cl -- drop "List" + visitArg = case mode of + CppStdBeyondAnsi _ -> "*i->get()" + _ -> "*i" + -prList False (cl,b) = unlines +-- useSTL = False +prList _ False (cl,b) = unlines [ "void Skeleton::visit" ++ cl ++ "("++ cl +++ "*" ++ vname ++ ")" , "{" , " while (" ++ vname ++ ")" diff --git a/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs b/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs index de73d244..a74eaee0 100644 --- a/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs +++ b/source/src/BNFC/Backend/CPP/STL/CFtoSTLAbs.hs @@ -35,9 +35,9 @@ import BNFC.Backend.CPP.STL.STLUtils --The result is two files (.H file, .C file) cf2CPPAbs :: RecordPositions -> CppStdMode -> Maybe String -> String -> CF -> (String, String) -cf2CPPAbs rp mode inPackage _ cf = (mkHFile rp mode inPackage cab cf, mkCFile mode inPackage cab cf) +cf2CPPAbs rp mode inPackage _ cf = (mkHFile rp mode inPackage cabs cf, mkCFile mode inPackage cabs cf) where - cab = cf2cabs cf + cabs = cf2cabs cf -- **** Header (.H) File Functions **** -- @@ -100,9 +100,9 @@ mkHFile rp mode inPackage cabs cf = unlines "", unlines [prCon mode (c,r) | (c,rs) <- signatures cabs, r <- rs], "", - unlines [prList mode c | c <- listtypes cabs], + unlines [prList mode primitives c | c <- listtypes cabs], "", - definedRules Nothing cf + definedRules mode Nothing cf "/******************** Defined Constructors ********************/", nsEnd inPackage, "#endif" @@ -110,6 +110,7 @@ mkHFile rp mode inPackage cabs cf = unlines where classes = allClasses cabs hdef = nsDefine inPackage "ABSYN_HEADER" + primitives = [c | (c,_) <- basetypes] ++ tokentypes cabs -- auxiliaries @@ -199,7 +200,7 @@ prCon mode (c,(f,cs)) = " " ++f++ "(" ++ conargs ++ "):" +++ c +++ "(){};", "", " virtual void accept(Visitor *v) override;", - " " ++ wrapSharedPtr c +++ " clone() const override;", + " " ++ wrapSharedPtr c +++ " clone() const;", "};" ]; } @@ -215,8 +216,8 @@ prCon mode (c,(f,cs)) = ; } -prList :: CppStdMode -> (String, Bool) -> String -prList mode (c, b) = case mode of { +prList :: CppStdMode -> [String] -> (String, Bool) -> String +prList mode primitives (c, b) = case mode of { CppStdAnsi _ -> unlines [ "class " ++c++ " : public Visitable, public std::vector<" ++bas++ ">" , "{" @@ -248,7 +249,7 @@ prList mode (c, b) = case mode of { , "" , " virtual void accept(Visitor *v);" , " " ++ wrapSharedPtr c +++ " clone() const;" - , " void cons(" ++ wrapSharedPtr childClass ++ ");" + , " void cons(" ++ wrapSharedPtrIf isNotBaseClass childClass ++ ");" , " void reverse();" , "};" , "" @@ -258,6 +259,8 @@ prList mode (c, b) = case mode of { childClass = drop 4 c childClassVarName = "list" ++ map toLower childClass ++ "_" bas = applyWhen b (++ "*") $ drop 4 c {- drop "List" -} + -- if list element is primitive type, not to use smart-ptr for argument type + isNotBaseClass = not $ elem childClass primitives -- **** Implementation (.C) File Functions **** -- @@ -271,17 +274,22 @@ mkCFile mode inPackage cabs cf = unlines $ [ "#include \"Absyn"++hExt++"\"", nsStart inPackage, unlines [prConC mode c r | (c,rs) <- signatures cabs, r <- rs], - unlines [prListC mode l | l <- listtypes cabs], - definedRules (Just $ LC nil cons) cf + unlines [prListC mode primitives l | l <- listtypes cabs], + definedRules mode (Just $ LC nil cons) cf "/******************** Defined Constructors ********************/", nsEnd inPackage ] where - nil t = (,dummyType) $ concat [ "new List", identType t, "()" ] - cons t = (,dummyType) $ concat [ "consList", identType t ] - hExt = case mode of - CppStdAnsi _ -> ".h"; - CppStdBeyondAnsi _ -> ".hh"; + primitives = [c | (c,_) <- basetypes] ++ tokentypes cabs + nil t = case mode of + CppStdAnsi _ -> (,dummyType) $ concat [ "new List", identType t, "()" ] + CppStdBeyondAnsi _ -> (,dummyType) $ wrapMakeShared ("List" ++ identType t) ++ "()" + cons t = case mode of + CppStdAnsi _ -> (,dummyType) $ concat [ "consList", identType t ] + CppStdBeyondAnsi _ -> (,dummyType) $ concat [ "consList", identType t ] + hExt = case mode of + CppStdAnsi _ -> ".h" + CppStdBeyondAnsi _ -> ".hh" prConC :: CppStdMode -> String -> CAbsRule -> String @@ -295,12 +303,12 @@ prConC mode c fcs@(f,_) = unlines [ "" ] -prListC :: CppStdMode -> (String,Bool) -> String -prListC mode (c,b) = unlines +prListC :: CppStdMode -> [String] -> (String,Bool) -> String +prListC mode primitives (c,b) = unlines [ "/******************** " ++ c ++ " ********************/" , prAcceptC mode c , prCloneC mode c c - , prConsC mode c b + , prConsC mode primitives c b ] --The standard accept function for the Visitor pattern @@ -338,8 +346,8 @@ prCloneC mode f c = case mode of { } -- | Make a list constructor definition. -prConsC :: CppStdMode -> String -> Bool -> String -prConsC mode c b = case mode of { +prConsC :: CppStdMode -> [String] -> String -> Bool -> String +prConsC mode primitives c b = case mode of { CppStdAnsi _ -> unlines [ concat [ c, "* ", "cons", c, "(", bas, " x, ", c, "* xs) {" ] , " xs->insert(xs->begin(), x);" @@ -347,8 +355,22 @@ prConsC mode c b = case mode of { , "}" ]; CppStdBeyondAnsi _ -> unlines [ - concat [ "void ", c, "::cons(", wrapSharedPtr bas, " x) {" ] - , " " ++inner++ ".push_front(x);" + -- Append a element into list tail (In C ++ term, "push_back") + concat [ "void ", c, "::cons(", consArg, " x) {" ] + , if isNotBaseClass then + " " ++inner++ ".push_back(x);" + else + " " ++inner++ ".push_back(std::make_unique<" ++bas++ ">(x));" + , "}" + , "" + -- Insert a element into list head (In C ++ term, "push_front" / in lisp term ? "cons") + -- This implementation is required in definedRules + , concat [wrapSharedPtr c, " cons", c, "(", consArg, " x, ", wrapSharedPtr c, " xs) {"] + , if isNotBaseClass then + " xs->" ++inner++ ".push_front(x);" + else + " xs->" ++inner++ ".push_front(std::make_unique<" ++bas++ ">(x));" + , " return xs;" , "}" , "" , "void" +++ c ++ "::reverse() {" @@ -362,6 +384,10 @@ prConsC mode c b = case mode of { CppStdBeyondAnsi _ -> drop 4 c; } inner = map toLower c ++ "_" + -- if list element is primitive type, not to use smart-ptr for argument type + isNotBaseClass = not $ elem bas primitives + consArg = wrapSharedPtrIf isNotBaseClass bas + --The constructor assigns the parameters to the corresponding instance variables. prConstructorC :: CppStdMode -> CAbsRule -> String diff --git a/source/src/BNFC/Backend/OCaml.hs b/source/src/BNFC/Backend/OCaml.hs index a1d408fc..0cd54080 100644 --- a/source/src/BNFC/Backend/OCaml.hs +++ b/source/src/BNFC/Backend/OCaml.hs @@ -114,7 +114,7 @@ makefile :: SharedOptions -> String -> Doc makefile opts basename = vcat [ mkVar "OCAMLC" "ocamlc" , mkVar "OCAMLYACC" $ ocamlParserName opts - , mkVar "OCAMLLEX" "ocamllex" + , mkVar "OCAMLLEX" "ocamllex -ml" -- prevent error of "transition table overflow, automaton is too big" https://stackoverflow.com/a/63461031/2565527 , mkVar "OCAMLCFLAGS" "" , mkRule "all" [] [ "$(OCAMLYACC) " ++ ocamlyaccFile opts diff --git a/testing/Main.hs b/testing/Main.hs index da85187e..f9db77ad 100644 --- a/testing/Main.hs +++ b/testing/Main.hs @@ -5,7 +5,7 @@ module Main (main) where import Data.String.QQ (s) import System.Environment (getArgs) -import Test.Framework (htfMain) +import Test.Framework (htfMainWithArgs) import License import qualified SucceedLBNFTests @@ -20,7 +20,7 @@ main = do if | "--license" `elem` args -> greet license | "--help" `elem` args -> greet usage | "-h" `elem` args -> greet usage - | otherwise -> runAllTests + | otherwise -> runAllTests args -- All other args will pass into HTF greet :: String -> IO () greet msg = do @@ -33,18 +33,23 @@ usage = [s| Start bnfc-system-tests from inside `testing` directory. Options: ---license Print copyright and license text. ---help, -h Print this help text. + -n PATTERN --not=PATTERN Tests to exclude. + -l --list List all matching tests. + --fail-fast Fail and abort test run as soon as the first test fails. + --license Print copyright and license text. + -h --help Print this help text. |] -runAllTests = do +runAllTests :: [String] -> IO () +runAllTests args = do succeedLBNFTests <- SucceedLBNFTests.all failLBNFTests <- FailLBNFTests.all - htfMain $ + htfMainWithArgs + args -- Use : and [] for this list such that lines can be swapped swiftly -- (avoids the usual problems when trying to switch the first line -- with a later line). - + $ succeedLBNFTests : failLBNFTests : -- ParameterizedTests.layoutTest : diff --git a/testing/Makefile b/testing/Makefile index 011c8262..be2de626 100644 --- a/testing/Makefile +++ b/testing/Makefile @@ -1,13 +1,18 @@ .PHONY: build license test usage -test: build - cabal run +SHELL := /bin/bash + +test: build exec-test + +exec-test: + cabal v2-install BNFC:exes --overwrite-policy=always + source ./scripts/env && cabal run bnfc-system-tests #-- "Parameterized tests:C\+\+ \(with namespace\):Examples:cpp" usage: build - cabal run --help + cabal run bnfc-system-tests -- --help license: build - cabal run --license + cabal run bnfc-system-tests -- --license build: make -C src From 58824b123b09c3774f3f918ed8b7bc46bf4918db Mon Sep 17 00:00:00 2001 From: "hiroyuki.nagata" Date: Fri, 6 May 2022 00:18:55 +0900 Subject: [PATCH 9/9] Fix memory-leak problem in pretty-print --- source/src/BNFC/Backend/C/CFtoFlexC.hs | 2 ++ source/src/BNFC/Backend/CPP/PrettyPrinter.hs | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/source/src/BNFC/Backend/C/CFtoFlexC.hs b/source/src/BNFC/Backend/C/CFtoFlexC.hs index 45be18df..c18f2366 100644 --- a/source/src/BNFC/Backend/C/CFtoFlexC.hs +++ b/source/src/BNFC/Backend/C/CFtoFlexC.hs @@ -317,6 +317,8 @@ restOfFlex mode cf env = unlines $ concat , "" , "" ++camelCaseName++ "Scanner::~" ++camelCaseName++ "Scanner()" , "{" + , " delete loc;" + , " delete yylval;" , "}" , "" , "/* This implementation of " ++camelCaseName++ "FlexLexer::yylex() is required to fill the" diff --git a/source/src/BNFC/Backend/CPP/PrettyPrinter.hs b/source/src/BNFC/Backend/CPP/PrettyPrinter.hs index 923388ee..aeb2709f 100644 --- a/source/src/BNFC/Backend/CPP/PrettyPrinter.hs +++ b/source/src/BNFC/Backend/CPP/PrettyPrinter.hs @@ -259,6 +259,10 @@ mkCFile mode useStl inPackage cf groups hExt = concat "", "PrintAbsyn::~PrintAbsyn(void)", "{", + " if (buf_ && strlen(buf_) > 0)", + " {", + " delete[] buf_;", + " }", "}", "", "char *PrintAbsyn::print(Visitable *v)", @@ -280,6 +284,10 @@ mkCFile mode useStl inPackage cf groups hExt = concat "", "ShowAbsyn::~ShowAbsyn(void)", "{", + " if (buf_ && strlen(buf_) > 0)", + " {", + " delete[] buf_;", + " }", "}", "", "char *ShowAbsyn::show(Visitable *v)",