From ed7408367f4509b30a05cc134bb6f9be70988fe0 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Wed, 22 Feb 2023 20:57:00 -0500 Subject: [PATCH] Replace CFile builder with Yacc and Lex builders - close #166 --- build_tests/cfile/Rsconscript | 4 --- build_tests/cfile/error_unknown_extension.rb | 3 -- build_tests/lex_yacc/Rsconscript | 4 +++ build_tests/{cfile => lex_yacc}/lexer.l | 0 build_tests/{cfile => lex_yacc}/parser.y | 0 doc/user_guide.md | 38 +++++++++++++------- lib/rscons.rb | 6 ++-- lib/rscons/builders/cfile.rb | 35 ------------------ lib/rscons/builders/lex.rb | 24 +++++++++++++ lib/rscons/builders/yacc.rb | 24 +++++++++++++ lib/rscons/default_construction_variables.rb | 2 -- spec/build_tests_spec.rb | 17 +++------ 12 files changed, 86 insertions(+), 71 deletions(-) delete mode 100644 build_tests/cfile/Rsconscript delete mode 100644 build_tests/cfile/error_unknown_extension.rb create mode 100644 build_tests/lex_yacc/Rsconscript rename build_tests/{cfile => lex_yacc}/lexer.l (100%) rename build_tests/{cfile => lex_yacc}/parser.y (100%) delete mode 100644 lib/rscons/builders/cfile.rb create mode 100644 lib/rscons/builders/lex.rb create mode 100644 lib/rscons/builders/yacc.rb diff --git a/build_tests/cfile/Rsconscript b/build_tests/cfile/Rsconscript deleted file mode 100644 index 8ade2c1..0000000 --- a/build_tests/cfile/Rsconscript +++ /dev/null @@ -1,4 +0,0 @@ -env do |env| - env.CFile("lexer.c", "lexer.l") - env.CFile("parser.c", "parser.y") -end diff --git a/build_tests/cfile/error_unknown_extension.rb b/build_tests/cfile/error_unknown_extension.rb deleted file mode 100644 index cea81f6..0000000 --- a/build_tests/cfile/error_unknown_extension.rb +++ /dev/null @@ -1,3 +0,0 @@ -env do |env| - env.CFile("file.c", "foo.bar") -end diff --git a/build_tests/lex_yacc/Rsconscript b/build_tests/lex_yacc/Rsconscript new file mode 100644 index 0000000..13b649b --- /dev/null +++ b/build_tests/lex_yacc/Rsconscript @@ -0,0 +1,4 @@ +env do |env| + env.Lex("lexer.c", "lexer.l") + env.Yacc("parser.c", "parser.y") +end diff --git a/build_tests/cfile/lexer.l b/build_tests/lex_yacc/lexer.l similarity index 100% rename from build_tests/cfile/lexer.l rename to build_tests/lex_yacc/lexer.l diff --git a/build_tests/cfile/parser.y b/build_tests/lex_yacc/parser.y similarity index 100% rename from build_tests/cfile/parser.y rename to build_tests/lex_yacc/parser.y diff --git a/doc/user_guide.md b/doc/user_guide.md index f27a652..d33c46c 100644 --- a/doc/user_guide.md +++ b/doc/user_guide.md @@ -925,11 +925,11 @@ There are several default builders that are built-in to Rscons: * `Command`, which executes a user-defined command to produce the target. * `Copy`, which copies files or directories to a specified destination. - * `CFile`, which builds a C or C++ source file from a lex or yacc input file. * `Directory`, which creates a directory. * `Disassemble`, which disassembles an object file to a disassembly listing. * `Install`, which installs files or directories to a specified destination. * `InstallDirectory`, which creates a directory in an install destination. + * `Lex`, which builds a source file from a lex input file. * `Library`, which collects object files into a static library archive file. * `Object`, which compiles source files to produce an object file. * `Preprocess`, which invokes the C/C++ preprocessor on a source file. @@ -939,6 +939,7 @@ There are several default builders that are built-in to Rscons: * `SharedObject`, which compiles source files to produce an object file, in a way that is able to be used to create a shared library. * `Size`, which runs the 'size' utility on an executable file. + * `Yacc`, which builds a source file from a yacc input file. ####> The Command Builder @@ -965,17 +966,6 @@ The `Command` builder supports the following construction variables: `CMD_STDOUT` is expanded for variable references, so the token `${_TARGET}` can be used, for example. -####> The CFile Builder - -```ruby -env.CFile(target, source) -# Example -env.CFile("^/parser/parser.c", "parser.y") -``` - -The `CFile` builder will generate a C or C++ source file from a lex (.l, .ll) -or yacc (.y, .yy) input file. - ####> The Copy Builder ```ruby @@ -1048,6 +1038,17 @@ the `InstallDirectory` builder. The `uninstall` task removes targets created by the `InstallDirectory` builder but not by the `Directory` builder. +####> The Lex Builder + +```ruby +env.Lex(target, source) +# Example +env.Lex("^/lexer.c", "lexer.l") +``` + +The `Lex` builder will generate a source file from a lex (.l, .ll) +input file. + ####> The Library Builder ```ruby @@ -1178,6 +1179,17 @@ stores its output in the target file. The size executable can be specified with the `SIZE` construction variable, and flags can be specified with `SIZEFLAGS`. +####> The Yacc Builder + +```ruby +env.Yacc(target, source) +# Example +env.Yacc("^/parser.c", "parser.y") +``` + +The `Yacc` builder will generate a source file from a yacc (.y, .yy) +input file. + ###> Phony Targets Rscons supports phony build targets. @@ -1959,7 +1971,7 @@ end ```ruby env do |env| - env.CFile("^/parser.tab.cc", "parser.yy") + env.Yacc("^/parser.tab.cc", "parser.yy") end ``` diff --git a/lib/rscons.rb b/lib/rscons.rb index e896239..b0d38b4 100644 --- a/lib/rscons.rb +++ b/lib/rscons.rb @@ -23,13 +23,13 @@ module Rscons # Names of the default builders which will be added to all newly created # {Environment} objects. DEFAULT_BUILDERS = [ - :CFile, :Command, :Copy, :Directory, :Disassemble, :Install, :InstallDirectory, + :Lex, :Library, :Object, :Preprocess, @@ -37,6 +37,7 @@ module Rscons :SharedLibrary, :SharedObject, :Size, + :Yacc, ] # Class to represent a fatal error during an Rscons operation. @@ -135,11 +136,11 @@ require_relative "rscons/builders/mixins/object_deps" require_relative "rscons/builders/mixins/program" # default builders -require_relative "rscons/builders/cfile" require_relative "rscons/builders/command" require_relative "rscons/builders/copy" require_relative "rscons/builders/directory" require_relative "rscons/builders/disassemble" +require_relative "rscons/builders/lex" require_relative "rscons/builders/library" require_relative "rscons/builders/object" require_relative "rscons/builders/preprocess" @@ -148,6 +149,7 @@ require_relative "rscons/builders/shared_library" require_relative "rscons/builders/shared_object" require_relative "rscons/builders/simple_builder" require_relative "rscons/builders/size" +require_relative "rscons/builders/yacc" # language support require_relative "rscons/builders/lang/asm" diff --git a/lib/rscons/builders/cfile.rb b/lib/rscons/builders/cfile.rb deleted file mode 100644 index 0573e4a..0000000 --- a/lib/rscons/builders/cfile.rb +++ /dev/null @@ -1,35 +0,0 @@ -module Rscons - module Builders - # Build a C or C++ source file given a lex (.l, .ll) or yacc (.y, .yy) - # input file. - # - # Examples:: - # env.CFile("parser.tab.cc", "parser.yy") - # env.CFile("lex.yy.cc", "parser.ll") - class CFile < Builder - - # Run the builder to produce a build target. - def run(options) - if @command - finalize_command - else - @vars["_TARGET"] = @target - @vars["_SOURCES"] = @sources - case - when @sources.first.end_with?(*@env.expand_varref("${LEXSUFFIX}")) - cmd = "LEX" - message = "Generating lexer" - when @sources.first.end_with?(*@env.expand_varref("${YACCSUFFIX}")) - cmd = "YACC" - message = "Generating parser" - else - raise "Unknown source file #{@sources.first.inspect} for CFile builder" - end - command = @env.build_command("${#{cmd}_CMD}", @vars) - standard_command("#{message} from #{Util.short_format_paths(@sources)} => #{@target}", command) - end - end - - end - end -end diff --git a/lib/rscons/builders/lex.rb b/lib/rscons/builders/lex.rb new file mode 100644 index 0000000..5d15a4e --- /dev/null +++ b/lib/rscons/builders/lex.rb @@ -0,0 +1,24 @@ +module Rscons + module Builders + # Build a source file given a lex input file. + # + # Examples:: + # env.Lex("lex.c", "parser.l") + # env.Lex("lex.cc", "parser.ll") + class Lex < Builder + + # Run the builder to produce a build target. + def run(options) + if @command + finalize_command + else + @vars["_TARGET"] = @target + @vars["_SOURCES"] = @sources + command = @env.build_command("${LEX_CMD}", @vars) + standard_command("Generating lexer source from #{Util.short_format_paths(@sources)} => #{@target}", command) + end + end + + end + end +end diff --git a/lib/rscons/builders/yacc.rb b/lib/rscons/builders/yacc.rb new file mode 100644 index 0000000..23d9215 --- /dev/null +++ b/lib/rscons/builders/yacc.rb @@ -0,0 +1,24 @@ +module Rscons + module Builders + # Build a source file given a yacc input file. + # + # Examples:: + # env.Yacc("parser.c", "parser.y") + # env.Yacc("parser.cc", "parser.yy") + class Yacc < Builder + + # Run the builder to produce a build target. + def run(options) + if @command + finalize_command + else + @vars["_TARGET"] = @target + @vars["_SOURCES"] = @sources + command = @env.build_command("${YACC_CMD}", @vars) + standard_command("Generating parser source from #{Util.short_format_paths(@sources)} => #{@target}", command) + end + end + + end + end +end diff --git a/lib/rscons/default_construction_variables.rb b/lib/rscons/default_construction_variables.rb index cf0df52..5f25374 100644 --- a/lib/rscons/default_construction_variables.rb +++ b/lib/rscons/default_construction_variables.rb @@ -49,7 +49,6 @@ module Rscons "LDCMD" => %w[${LD} -o ${_TARGET} ${LDFLAGS} ${_SOURCES} ${LIBDIRPREFIX}${LIBPATH} ${LIBLINKPREFIX}${LIBS}], "LDFLAGS" => [], "LEX" => "flex", - "LEXSUFFIX" => %w[.l .ll], "LEX_CMD" => %w[${LEX} ${LEX_FLAGS} -o ${_TARGET} ${_SOURCES}], "LEX_FLAGS" => [], "LIBDIRPREFIX" => "-L", @@ -84,7 +83,6 @@ module Rscons "SIZECMD" => %w[${SIZE} ${SIZEFLAGS} ${_SOURCES}], "SIZEFLAGS" => [], "YACC" => "bison", - "YACCSUFFIX" => %w[.y .yy], "YACC_CMD" => %w[${YACC} ${YACC_FLAGS} -o ${_TARGET} ${_SOURCES}], "YACC_FLAGS" => %w[-d], } diff --git a/spec/build_tests_spec.rb b/spec/build_tests_spec.rb index 3896722..b321de3 100644 --- a/spec/build_tests_spec.rb +++ b/spec/build_tests_spec.rb @@ -1163,28 +1163,21 @@ EOF end end - context "CFile builder" do - it "builds a .c file using flex and bison" do - test_dir("cfile") + context "Lex and Yacc builders" do + it "builds C files using flex and bison" do + test_dir("lex_yacc") result = run_rscons expect(result.stderr).to eq "" verify_lines(lines(result.stdout), [ - %r{Generating lexer from lexer.l => lexer.c}, - %r{Generating parser from parser.y => parser.c}, + %r{Generating lexer source from lexer.l => lexer.c}, + %r{Generating parser source from parser.y => parser.c}, ]) result = run_rscons expect(result.stderr).to eq "" expect(result.stdout).to eq "" end - - it "raises an error when an unknown source file is specified" do - test_dir("cfile") - result = run_rscons(args: %w[-f error_unknown_extension.rb]) - expect(result.stderr).to match /Unknown source file .foo.bar. for CFile builder/ - expect(result.status).to_not eq 0 - end end context "Command builder" do