aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog13
-rw-r--r--src/Makefile.in9
-rw-r--r--src/Makefile.pamphlet9
-rw-r--r--src/algebra/Makefile.in12
-rw-r--r--src/algebra/Makefile.pamphlet14
-rw-r--r--src/etc/Makefile.in2
-rw-r--r--src/graph/Makefile.in4
-rw-r--r--src/input/Makefile.in4
-rw-r--r--src/input/Makefile.pamphlet4
-rw-r--r--src/interp/Makefile.in4
-rw-r--r--src/interp/Makefile.pamphlet4
-rw-r--r--src/utils/Makefile.in77
-rw-r--r--src/utils/hammer.cc414
-rw-r--r--src/utils/storage.H87
-rw-r--r--src/utils/storage.cc175
15 files changed, 800 insertions, 32 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index a291b326..85445ae7 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,16 @@
+2010-08-20 Gabriel Dos Reis <gdr@cs.tamu.edu>
+
+ * Makefile.pamphlet (all-interpsys): Require all-utils.
+ (all-asq): Likewise.
+ (all-utils): New tule.
+ * algebra/Makefile.pamphlet: Replace $(axiom_build_document) with
+ $(oa_hammer).
+ * etc/Makefile.in: Likewise.
+ * graph/Makefile.in: Likewise.
+ * input/Makefile.pamphlet: Likewise.
+ * interp/Makefile.pamphlet: Likewise.
+ * utils/: New component.
+
2010-08-17 Gabriel Dos Reis <gdr@cs.tamu.edu>
* ChangeLog.jap: Merge into here. Remove
diff --git a/src/Makefile.in b/src/Makefile.in
index 420b1c8f..d6efda33 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -5,7 +5,7 @@ subdir = src/
SUBDIRS = @axiom_src_subdirs@
-.PHONY: all all-ax all-src all-clef all-sman all-driver
+.PHONY: all all-ax all-src all-clef all-sman all-driver all-utils
all: all-ax
@@ -19,6 +19,9 @@ stamp: @axiom_src_all@ all-driver
all-driver: all-lib
@cd driver && $(MAKE) $@
+all-utils:
+ @cd utils && $(MAKE) $@
+
all-clef: all-lib
@$(mkdir_p) "$(axiom_target_bindir)"
cd clef && $(MAKE) $@
@@ -41,7 +44,7 @@ all-lisp: all-lib
cd lisp && $(MAKE) all-lisp
all-boot: all-lisp
@cd boot && $(MAKE) $@
-all-interpsys: all-boot all-hyper-pre
+all-interpsys: all-boot all-hyper-pre all-utils
cd interp && ${MAKE} all-interpsys
all-axiomsys: all-asq
@@ -54,7 +57,7 @@ all-hyper-pre: all-lib
cd hyper && $(MAKE) all-hyper-pre
all-input: all-axiomsys all-doc
cd input && ${MAKE}
-all-asq: all-hyper-post
+all-asq: all-hyper-post all-utils
cd etc && $(MAKE) $@
.PHONY: all-databases
diff --git a/src/Makefile.pamphlet b/src/Makefile.pamphlet
index 806d8375..07989893 100644
--- a/src/Makefile.pamphlet
+++ b/src/Makefile.pamphlet
@@ -124,7 +124,7 @@ all-boot: all-lisp
Once \Tool{bootsys} exists we need to build
\Tool{interpsys}.
<<interpdir>>=
-all-interpsys: all-boot all-hyper-pre
+all-interpsys: all-boot all-hyper-pre all-utils
cd interp && ${MAKE} all-interpsys
all-axiomsys: all-asq
@@ -211,7 +211,7 @@ The \Tool{asq} \cite{2} command, contained in this directory, is useful
for finding detailed information about domains, packages, and
categories from the shell without running Axiom.
<<etcdir>>=
-all-asq: all-hyper-post
+all-asq: all-hyper-post all-utils
cd etc && $(MAKE) $@
.PHONY: all-databases
@@ -252,7 +252,7 @@ subdir = src/
SUBDIRS = @axiom_src_subdirs@
-.PHONY: all all-ax all-src all-clef all-sman all-driver
+.PHONY: all all-ax all-src all-clef all-sman all-driver all-utils
all: all-ax
@@ -266,6 +266,9 @@ stamp: @axiom_src_all@ all-driver
all-driver: all-lib
@cd driver && $(MAKE) $@
+all-utils:
+ @cd utils && $(MAKE) $@
+
<<clefdir>>
<<smandir>>
<<hyperdir>>
diff --git a/src/algebra/Makefile.in b/src/algebra/Makefile.in
index e2293479..0b47e87a 100644
--- a/src/algebra/Makefile.in
+++ b/src/algebra/Makefile.in
@@ -1131,7 +1131,7 @@ strap/%.$(FASLEXT): $(srcdir)/strap/%.lsp
$(OUTSRC)/%.spad: mk-target-src-algabra-dir
${OUTSRC}/%.spad: $(srcdir)/%.spad.pamphlet
- $(axiom_build_document) --tangle --output=$@ $<
+ $(oa_hammer) --tangle --output=$@ $<
.PHONY: mk-target-src-algabra-dir
mk-target-src-algabra-dir:
@@ -1153,10 +1153,10 @@ $(builddir)/%.dvi: $(axiom_build_texdir)/diagrams.tex \
$(axiom_build_texdir)/axiom.sty
$(builddir)/%.dvi: $(builddir)/%.tex
- $(axiom_build_document) --latex $<
+ $(oa_hammer) --latex $<
$(builddir)/%.tex: $(srcdir)/%.pamphlet
- $(axiom_build_document) --weave --output=$@ $<
+ $(oa_hammer) --weave --output=$@ $<
$(axiom_build_texdir)/diagrams.tex: $(axiom_src_docdir)/diagrams.tex
@cp -p $< $@
@@ -1170,13 +1170,13 @@ PARSER.NRLIB/code.$(FASLEXT): script-parser.spad
${INPUT}/TESTFR.input: $(srcdir)/fr.spad.pamphlet
- $(axiom_build_document) --tangle='TEST FR' --output=$@ $<
+ $(oa_hammer) --tangle='TEST FR' --output=$@ $<
${INPUT}/INTHEORY.input: $(srcdir)/numtheor.spad.pamphlet
- $(axiom_build_document) --tangle='TEST INTHEORY' --output=$@ $<
+ $(oa_hammer) --tangle='TEST INTHEORY' --output=$@ $<
${INPUT}/VIEW2D.input: $(srcdir)/view2D.spad.pamphlet
- $(axiom_build_document) --tangle='TEST VIEW2D' --output=$@ $<
+ $(oa_hammer) --tangle='TEST VIEW2D' --output=$@ $<
${DOC}/diagrams.tex: $(axiom_src_docdir)/diagrams.tex
diff --git a/src/algebra/Makefile.pamphlet b/src/algebra/Makefile.pamphlet
index 24d15915..210b5165 100644
--- a/src/algebra/Makefile.pamphlet
+++ b/src/algebra/Makefile.pamphlet
@@ -1418,13 +1418,13 @@ TESTS=${INPUT}/INTHEORY.input ${INPUT}/VIEW2D.input ${INPUT}/TESTFR.input
<<testrules>>=
${INPUT}/TESTFR.input: $(srcdir)/fr.spad.pamphlet
- $(axiom_build_document) --tangle='TEST FR' --output=$@ $<
+ $(oa_hammer) --tangle='TEST FR' --output=$@ $<
${INPUT}/INTHEORY.input: $(srcdir)/numtheor.spad.pamphlet
- $(axiom_build_document) --tangle='TEST INTHEORY' --output=$@ $<
+ $(oa_hammer) --tangle='TEST INTHEORY' --output=$@ $<
${INPUT}/VIEW2D.input: $(srcdir)/view2D.spad.pamphlet
- $(axiom_build_document) --tangle='TEST VIEW2D' --output=$@ $<
+ $(oa_hammer) --tangle='TEST VIEW2D' --output=$@ $<
@
@@ -1580,7 +1580,7 @@ strap/%.$(FASLEXT): $(srcdir)/strap/%.lsp
$(OUTSRC)/%.spad: mk-target-src-algabra-dir
${OUTSRC}/%.spad: $(srcdir)/%.spad.pamphlet
- $(axiom_build_document) --tangle --output=$@ $<
+ $(oa_hammer) --tangle --output=$@ $<
.PHONY: mk-target-src-algabra-dir
mk-target-src-algabra-dir:
@@ -1604,10 +1604,10 @@ $(builddir)/%.dvi: $(axiom_build_texdir)/diagrams.tex \
$(axiom_build_texdir)/axiom.sty
$(builddir)/%.dvi: $(builddir)/%.tex
- $(axiom_build_document) --latex $<
+ $(oa_hammer) --latex $<
$(builddir)/%.tex: $(srcdir)/%.pamphlet
- $(axiom_build_document) --weave --output=$@ $<
+ $(oa_hammer) --weave --output=$@ $<
$(axiom_build_texdir)/diagrams.tex: $(axiom_src_docdir)/diagrams.tex
@cp -p $< $@
@@ -1723,7 +1723,7 @@ the case above this would resolve to [[\${MID}/LEXTRIPK.spad]].
For the line given above it outputs the following:
\begin{verbatim}
${MID}/LEXTRIPK.spad: $(srcdir)/zerodim.spad.pamphlet
- $(axiom_build_document) --tangle='package LEXTRIPK LexTriangularPackage' --output=$@ $<
+ $(oa_hammer) --tangle='package LEXTRIPK LexTriangularPackage' --output=$@ $<
\end{verbatim}
diff --git a/src/etc/Makefile.in b/src/etc/Makefile.in
index b642bda1..c06c0437 100644
--- a/src/etc/Makefile.in
+++ b/src/etc/Makefile.in
@@ -109,7 +109,7 @@ asq$(EXEEXT): $(asq_objects)
asq.c: $(srcdir)/asq.c.pamphlet
- $(axiom_build_document) --tangle --output=$@ $<
+ $(oa_hammer) --tangle --output=$@ $<
$(axiom_target_libdir)/summary: $(srcdir)/summary
cp -p $< $@
diff --git a/src/graph/Makefile.in b/src/graph/Makefile.in
index 6ffecf3c..4368c446 100644
--- a/src/graph/Makefile.in
+++ b/src/graph/Makefile.in
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2009, Gabriel Dos Reis.
+# Copyright (C) 2007-2010, Gabriel Dos Reis.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -78,7 +78,7 @@ all-viewAlone: all-Gdraws
parabola/data parabola/graph0: $(srcdir)/fileformats.pamphlet
- $(axiom_build_document) --tangle=`basename $@` --output=$@ $<
+ $(oa_hammer) --tangle=`basename $@` --output=$@ $<
mostlyclean-local:
diff --git a/src/input/Makefile.in b/src/input/Makefile.in
index acfdd10a..a845deab 100644
--- a/src/input/Makefile.in
+++ b/src/input/Makefile.in
@@ -514,13 +514,13 @@ ${OUT}/%.input: %.input
.PRECIOUS: %.input
%.input: ${IN}/%.input.pamphlet
- @$(axiom_build_document) --output=$@ --tangle $<
+ @$(oa_hammer) --output=$@ --tangle $<
${OUT}/%.as: %.as
@cp -p $< $@
%.as: ${IN}/%.as.pamphlet
- @ $(axiom_build_document) --output=$@ --tangle $<
+ @ $(oa_hammer) --output=$@ --tangle $<
pamphlets = \
Makefile.pamphlet \
diff --git a/src/input/Makefile.pamphlet b/src/input/Makefile.pamphlet
index 5a320d1c..d9747262 100644
--- a/src/input/Makefile.pamphlet
+++ b/src/input/Makefile.pamphlet
@@ -57,13 +57,13 @@ ${OUT}/%.input: %.input
.PRECIOUS: %.input
%.input: ${IN}/%.input.pamphlet
- @$(axiom_build_document) --output=$@ --tangle $<
+ @$(oa_hammer) --output=$@ --tangle $<
${OUT}/%.as: %.as
@cp -p $< $@
%.as: ${IN}/%.as.pamphlet
- @ $(axiom_build_document) --output=$@ --tangle $<
+ @ $(oa_hammer) --output=$@ --tangle $<
pamphlets = \
Makefile.pamphlet \
diff --git a/src/interp/Makefile.in b/src/interp/Makefile.in
index bf46316f..6fbfdf3c 100644
--- a/src/interp/Makefile.in
+++ b/src/interp/Makefile.in
@@ -219,11 +219,9 @@ ${AXIOMSYS}: database.date \
--load-directory=. $(OBJS) makeint.$(LNKEXT)
@ echo 6a $@ created
exposed.lsp: $(axiom_src_algdir)/exposed.lsp.pamphlet
- @ echo 615 making exposed.lsp from $(axiom_src_algdir)/exposed.lsp.pamphlet
- $(axiom_build_document) --tangle --output=$@ $<
+ $(oa_hammer) --tangle --output=$@ $<
$(axiom_targetdir)/algebra/exposed.$(FASLEXT) : exposed.lsp boot-pkg.$(LNKEXT)
- @ echo 616 making $@ from exposed.lsp
$(mkdir_p) $(axiom_targetdir)/algebra
$(BOOTSYS) --compile --output=$@ --load-directory=. $<
diff --git a/src/interp/Makefile.pamphlet b/src/interp/Makefile.pamphlet
index c3714e72..a1579c1c 100644
--- a/src/interp/Makefile.pamphlet
+++ b/src/interp/Makefile.pamphlet
@@ -410,11 +410,9 @@ $(axiom_build_texdir)/diagrams.tex: $(axiom_src_docdir)/diagrams.tex
\end{verbatim}
<<databases>>=
exposed.lsp: $(axiom_src_algdir)/exposed.lsp.pamphlet
- @ echo 615 making exposed.lsp from $(axiom_src_algdir)/exposed.lsp.pamphlet
- $(axiom_build_document) --tangle --output=$@ $<
+ $(oa_hammer) --tangle --output=$@ $<
$(axiom_targetdir)/algebra/exposed.$(FASLEXT) : exposed.lsp boot-pkg.$(LNKEXT)
- @ echo 616 making $@ from exposed.lsp
$(mkdir_p) $(axiom_targetdir)/algebra
$(BOOTSYS) --compile --output=$@ --load-directory=. $<
diff --git a/src/utils/Makefile.in b/src/utils/Makefile.in
new file mode 100644
index 00000000..024af5dc
--- /dev/null
+++ b/src/utils/Makefile.in
@@ -0,0 +1,77 @@
+# Copyright (C) 2010, Gabriel Dos Reis.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# - Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# - Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# - Neither the name of The Numerical Algorithms Group Ltd. nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+subdir = src/utils/
+
+bin_PROGRAMS = hammer$(EXEEXT)
+hammer_SOURCES = hammer.cc
+hammer_OBJECTS = $(hammer_SOURCES:.cc=.lo)
+hammer_LDADD = -L. -lOpenAxiom
+
+libOpenAxiom_HEADERS = storage.H
+libOpenAxiom_SOURCES = storage.cc
+libOpenAxiom_OBJECTS = $(libOpenAxiom_SOURCES:.cc=.lo)
+
+.PHONY: all all-ax all-utils
+.SUFFIXES:
+.SUFFIXES: .cc .H $(OBJEXT) $(LIBEXT)
+
+all: all-ax
+
+all-ax all-utils: stamp
+
+stamp: libOpenAxiom.$(LIBEXT) hammer$(EXEEXT)
+ -rm -f stamp
+ $(STAMP) stamp
+
+.SUFFIXES:
+.SUFFIXES: .c .h .lo .$(OBJEXT)
+.PRECIOUS: %.lo %.obj
+
+hammer$(EXEEXT): $(hammer_OBJECTS) libOpenAxiom.$(LIBEXT)
+ $(CXXLINK) -o $@ $(hammer_OBJECTS) $(hammer_LDADD) $(LDFLAGS)
+
+libOpenAxiom.$(LIBEXT): $(libOpenAxiom_OBJECTS)
+ $(CXXLINK) -o $@ $(libOpenAxiom_OBJECTS)
+
+%.lo: %.cc $(libOpenAxiom_HEADERS)
+ $(CXXCOMPILE) ${CXXFLAGS} -I. -I$(top_builddir)/config -o $@ $<
+
+
+mostlyclean-local:
+ @rm -rf .libs
+ @rm -f $(libOpenAxiom_OBJECTS)
+ @rm -f *~ core
+
+clean-local: mostlyclean-local
+
+distclean-local: clean-local
+
diff --git a/src/utils/hammer.cc b/src/utils/hammer.cc
new file mode 100644
index 00000000..17c5cc73
--- /dev/null
+++ b/src/utils/hammer.cc
@@ -0,0 +1,414 @@
+// Copyright (C) 2010, Gabriel Dos Reis.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// - Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in
+// the documentation and/or other materials provided with the
+// distribution.
+//
+// - Neither the name of The Numerical Algorithms Group Ltd. nor the
+// names of its contributors may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <string.h>
+#include <stdlib.h>
+#include <utility>
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <iterator>
+#include <list>
+#include <vector>
+#include <map>
+#include "storage.H"
+
+// -- This program implements basic functionalities for untangling
+// -- algebra source code from the pamphlets. The syntax is that
+// -- of `noweb'. A chunk definition starts with a pattern
+// -- <<name>>= on a line by itself, and ends with `@' by itself
+// -- on a line. A chunk can refer to another chunk through
+// -- a pattern of the form `<<name>>'.
+
+namespace OpenAxiom {
+ namespace Hammer {
+ // -------------
+ // -- Element --
+ // -------------
+ // Base class of document elements.
+ struct Element {
+ virtual ~Element() { }
+ };
+
+ // ---------------
+ // -- BasicText --
+ // ---------------
+ // Plain text, with no reference to any chunk.
+ struct BasicText : Element {
+ BasicText(const char* f, const char* l) : span(f, l) { }
+ // Pointer to the start of this basic text element
+ const char* begin() const { return span.first; }
+ // Oone-past-the-end of the this basic text element.
+ const char* end() const { return span.second; }
+ private:
+ std::pair<const char*, const char*> span;
+ };
+
+ // ---------------
+ // -- Reference --
+ // ---------------
+ // Reference to a a chunk by name.
+ struct Reference : Element {
+ explicit Reference(const std::string& s) : label(s) { }
+ // Naame of the chunk referenced.
+ const std::string& name() const { return label; }
+ private:
+ const std::string label;
+ };
+
+ // -------------------
+ // -- CompositeText --
+ // -------------------
+ // Sequence of basic elements and reference to chunks.
+ struct CompositeText: private std::vector<const Element*> {
+ typedef std::vector<const Element*> base;
+ using base::iterator;
+ using base::begin;
+ using base::end;
+ using base::size;
+ using base::operator[];
+
+ // Augment this chunk with a basic text in the open interval
+ // [f,l).
+ CompositeText& add_text(const char* f, const char* l) {
+ texts.push_back(BasicText(f, l));
+ push_back(&texts.back());
+ return *this;
+ }
+
+ // Augment this chunk with a reference to another chunk
+ // named `n'. Note that we don't attempt to check for
+ // possible circularities.
+ CompositeText reference_chunk(const char* f, const char* l) {
+ refs.push_back(Reference(std::string(f, l)));
+ push_back(&refs.back());
+ return *this;
+ }
+
+ private:
+ std::list<BasicText> texts;
+ std::list<Reference> refs;
+ };
+
+ // --------------
+ // -- Document --
+ // --------------
+ // A whole document; a sequence of chunks.
+ struct Document : std::list<CompositeText> {
+ Document(const Memory::FileMapping& file)
+ : active_chunk(&prose), text_start(file.begin()) {
+ parse(file);
+ }
+
+ // Return a pointer to a document chunk name `n'.
+ // Otherwise, return null.
+ CompositeText* lookup_chunk(const std::string& n) const {
+ ChunkTable::const_iterator i = defs.find(n);
+ return i == defs.end() ? 0 : i->second;
+ }
+
+ private:
+ typedef std::map<std::string, CompositeText*> ChunkTable;
+ CompositeText prose; // the prose around the chunks.
+ ChunkTable defs; // chunk definition table.
+ CompositeText* active_chunk; // chunk under construction.
+ const char* text_start; // begining of current basic text.
+
+ // Append basic text in the range `[text_start,last)'
+ // to the current chunk.
+ void finish_chunk(const char* last) {
+ if (text_start != last)
+ active_chunk->add_text(text_start, last);
+ active_chunk = &prose;
+ text_start = last;
+ }
+
+ // Start a new chunk or extend an existing chunk.
+ void begin_chunk(const std::string& name, const char* start) {
+ if (CompositeText* chunk = lookup_chunk(name))
+ active_chunk = chunk;
+ else {
+ push_back(CompositeText());
+ defs[name] = active_chunk = &back();
+ }
+ text_start = start;
+ }
+
+ // Parse a file mapping into this document.
+ void parse(const Memory::FileMapping&);
+ };
+
+ // Return true if the character `c' introduces a newline.
+ static inline bool
+ looking_at_newline(char c) {
+ return c == '\n' or c == '\r';
+ }
+
+ // Attempt to advance the cursor past newline marker.
+ // Return true on sucess.
+ static bool
+ saw_newline(const char*& cur, const char* end) {
+ if (*cur == '\n') {
+ ++cur;
+ return true;
+ }
+ else if (*cur == '\r') {
+ if (++cur < end and *cur == '\n')
+ ++cur;
+ return true;
+ }
+ return false;
+ }
+
+ // Move `cur' to end of line or `end', whichever comes first.
+ // Return true if the area swept consisted only of blank characters.
+ static inline bool
+ trailing_blank(const char*& cur, const char* end) {
+ bool result = true;
+ for (; cur < end and not saw_newline(cur, end); ++cur)
+ result = isspace(*cur);
+ return result;
+ }
+
+ // Attempt to advance `cur' past the double left angle brackets
+ // starting a chunk name. Returm true on success.
+ static bool
+ chunk_name_began(const char*& cur, const char* end) {
+ if (cur[0] == '<' and cur + 1 < end and cur[1] == '<') {
+ cur += 2;
+ return true;
+ }
+ return false;
+ }
+
+ // Attempt to move `cur' past the double right angle brackets
+ // terminating a chunk name. Returm true on success.
+ static bool
+ chunk_name_ended(const char*& cur, const char* end) {
+ if (cur[0] == '>' and cur + 1 < end and cur[1] == '>') {
+ cur += 2;
+ return true;
+ }
+ return false;
+ }
+
+ // We've just seen the start of a chunk reference; skip
+ // characters till we seen of the chunk's name.
+ static void
+ skip_to_end_of_chunk_name(const char*& cur, const char* end) {
+ while (cur < end) {
+ if (looking_at_newline(*cur)
+ or (cur + 1 < end and cur[0] == '>' and cur[1] == '>'))
+ return;
+ ++cur;
+ }
+ }
+
+ // Move the cursor until end of line.
+ static void
+ skip_to_end_of_line(const char*& cur, const char* end) {
+ while (cur < end) {
+ if (saw_newline(cur, end))
+ break;
+ ++cur;
+ }
+ }
+
+ void
+ Document::parse(const Memory::FileMapping& file) {
+ const char* cur = text_start;
+ const char* last = file.end();
+ // Process one line at a time.
+ while (cur < last) {
+ // 1. `@' ends previous chunk
+ if (*cur == '@') {
+ const char* p = cur;
+ if (trailing_blank(++cur, last))
+ finish_chunk(p);
+ }
+ // 2. `<<' introduces a chunk reference or a chunk definition.
+ else if (chunk_name_began(cur, last)) {
+ const char* label_start = cur;
+ skip_to_end_of_chunk_name(cur, last);
+ if (chunk_name_ended(cur, last)) {
+ const char* label_end = cur - 2;
+ if (cur < last and *cur == '=') {
+ if (trailing_blank(++cur, last)) {
+ // chunk definition or extension
+ finish_chunk(label_start - 2);
+ begin_chunk(std::string(label_start, label_end), cur);
+ }
+ }
+ else if (trailing_blank(cur, last)) {
+ // This is just a reference to a chunk.
+ active_chunk->add_text(text_start, label_start - 2);
+ active_chunk->reference_chunk(label_start, label_end);
+ text_start = cur;
+ }
+ else
+ skip_to_end_of_line(cur, last);
+ }
+ }
+ else
+ skip_to_end_of_line(cur, last);
+ }
+ finish_chunk(cur);
+ }
+
+ // Capture chunk resolution in a document.
+ struct resolve_chunk {
+ resolve_chunk(const std::string& s, const Document& f)
+ : name(s), doc(f) { }
+ const std::string name; // name of the chunk
+ const Document& doc; // document containing the chunk.
+ };
+
+ // Print the resolution of a chunk name onto an output stream.
+ std::ostream&
+ operator<<(std::ostream& os, const resolve_chunk& rc) {
+ // FIXME: no attempt at detecting circularities.
+ const CompositeText* doc = rc.doc.lookup_chunk(rc.name);
+ if (doc == 0) {
+ std::cerr << "chunk " << rc.name << " is undefined" << std::endl;
+ exit(1);
+ }
+ for (std::size_t i = 0; i < doc->size(); ++i) {
+ const Element* elt = (*doc)[i];
+ if (const BasicText* t = dynamic_cast<const BasicText*>(elt))
+ std::copy(t->begin(), t->end(),
+ std::ostream_iterator<char>(os));
+ else if (const Reference* r = dynamic_cast<const Reference*>(elt))
+ os << resolve_chunk(r->name(), rc.doc);
+ else {
+ std::cerr << "unknown document element" << std::endl;
+ exit(1);
+ }
+ }
+
+ return os;
+ }
+
+ // Return true if the `arg' is the option named`opt'.
+ static inline bool
+ is_option(const char* arg, const char* opt) {
+ return strcmp(arg, opt) == 0;
+ }
+
+ // `arg' is a argument on the command line. If `arg'
+ // does not match option name `opt', return null. Otherwise,
+ // return a pointer to the terminating NUL character if there
+ // is no specified value for that option, or a pointer to the
+ // start of the value.
+ static const char*
+ is_named_arg(const char* arg, const char* opt) {
+ const int n = strlen(opt);
+ int i = 0;
+ // Get out if argion name does not match.
+ // Note: Ideally, we could use strncmp(). However, that
+ // function is not available in C++98, so we cannot depend on it.
+ for (; i < n ; ++i)
+ if (arg[i] != opt[i])
+ return 0;
+
+ if (arg[i] == '\0')
+ return arg + i; // no value for the option.
+ return arg + n + 1; // being of the value.
+ }
+ }
+}
+
+
+int
+main(int argc, char* argv[]) {
+ using namespace OpenAxiom::Hammer;
+ int error_count = 0;
+ const char* chunk = 0; // chunck to tangle
+ const char* output_path = 0; // path to the output file
+ const char* input_path = 0; // path to the input file.
+ // 1. Process command line arguments.
+ for (int pos = 1; error_count == 0 and pos < argc; ++pos) {
+ if (const char* val = is_named_arg(argv[pos], "--tangle")) {
+ if (chunk != 0) {
+ std::cerr << "cannot tangle more than one chunk";
+ ++error_count;
+ }
+ else
+ chunk = *val == 0 ? "*" : val;
+ }
+ else if (const char* val = is_named_arg(argv[pos], "--output")) {
+ if (*val == 0) {
+ std::cerr << "missing output file name" << std::endl;
+ ++error_count;
+ }
+ else
+ output_path = val;
+ }
+ else if (argv[pos][0] == '-' and argv[pos][1] == '-') {
+ std::cerr << "unknown option " << argv[pos] << std::endl;
+ ++error_count;
+ }
+ else if (input_path != 0) {
+ std::cerr << "there must be exactly one input file" << std::endl;
+ ++error_count;
+ }
+ else
+ input_path = argv[pos];
+ }
+
+ // 2. Basic sanity check.
+ if (input_path == 0) {
+ std::cerr << "missing input file" << std::endl;
+ return 1;
+ }
+ if (output_path == 0) {
+ std::cerr << "missing output file" << std::endl;
+ return 1;
+ }
+ if (chunk == 0) {
+ std::cerr << "missing chunk name" << std::endl;
+ return 1;
+ }
+
+ if (error_count != 0)
+ return 1;
+
+ // 3. Attempt to extract the chunk.
+ try {
+ OpenAxiom::Memory::FileMapping file(input_path);
+ std::ofstream os(output_path);
+ os << resolve_chunk(chunk, Document(file));
+ }
+ catch(const OpenAxiom::SystemError& e) {
+ std::cerr << e.message() << std::endl;
+ exit(1);
+ }
+ return 0;
+}
diff --git a/src/utils/storage.H b/src/utils/storage.H
new file mode 100644
index 00000000..ba14ec97
--- /dev/null
+++ b/src/utils/storage.H
@@ -0,0 +1,87 @@
+// Copyright (C) 2010, Gabriel Dos Reis.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// - Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in
+// the documentation and/or other materials provided with the
+// distribution.
+//
+// - Neither the name of The Numerical Algorithms Group Ltd. nor the
+// names of its contributors may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stddef.h>
+#include <string>
+
+namespace OpenAxiom {
+ // -----------------
+ // -- SystemError --
+ // -----------------
+ // Objects of (type derived from) this type are used to report
+ // error orignating from the OpenAxiom core system.
+ struct SystemError {
+ explicit SystemError(std::string);
+ virtual ~SystemError();
+ // Return the text of the diagnostic message.
+ virtual const std::string& message() const;
+ protected:
+ const std::string text;
+ };
+
+ // Report a file system erro
+ void filesystem_error(std::string);
+
+ namespace Memory {
+ // Datatype for pointers to data.
+ typedef void* Pointer;
+
+ // Precision of the host OS storage page unit in byte count
+ size_t page_size();
+
+ // Acquire raw memory from the host OS in multiple
+ // of storage page nits.
+ Pointer os_acquire_raw_memory(size_t);
+
+ // Release raw storage to the hosting OS. The first operand must
+ // be a pointer value previous returned by `os_acquire_raw_memory'.
+ // Otherwise, the result is undefined.
+ void os_release_raw_memory(Pointer, size_t);
+
+ // -----------------
+ // -- FileMapping --
+ // -----------------
+ struct FileMapping {
+ explicit FileMapping(std::string);
+ ~FileMapping();
+ const char* begin() const { return static_cast<const char*>(start); }
+ const char* end() const { return begin() + extent; }
+ std::size_t size() const { return extent; }
+ protected:
+ Pointer start; // address at the mapped storage
+ size_t extent; // length (in bytes) of the storage
+ private:
+ FileMapping(const FileMapping&); // not implemented
+ FileMapping& operator=(const FileMapping&); // idem
+ };
+
+ }
+}
diff --git a/src/utils/storage.cc b/src/utils/storage.cc
new file mode 100644
index 00000000..4db7f302
--- /dev/null
+++ b/src/utils/storage.cc
@@ -0,0 +1,175 @@
+// Copyright (C) 2010, Gabriel Dos Reis.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// - Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in
+// the documentation and/or other materials provided with the
+// distribution.
+//
+// - Neither the name of The Numerical Algorithms Group Ltd. nor the
+// names of its contributors may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "openaxiom-c-macros.h"
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#include <sys/types.h>
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#ifdef HAVE_SYS_MMAN_H
+# include <sys/mman.h>
+#endif
+#ifdef OPENAXIOM_MS_WINDOWS_HOST
+# include <windows.h>
+#endif
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include "storage.H"
+
+namespace OpenAxiom {
+ // ----------------
+ // -- SystemError --
+ // ----------------
+ SystemError::SystemError(std::string s) : text(s) { }
+
+ SystemError::~SystemError() { }
+
+ const std::string&
+ SystemError::message() const {
+ return text;
+ }
+
+ void
+ filesystem_error(std::string s) {
+ throw SystemError(s);
+ }
+
+ namespace Memory {
+ // Return storage page allocation unit in byte count.
+ size_t page_size() {
+#if defined(OPENAXIOM_MS_WINDOWS_HOST)
+ SYSTEM_INFO si = { };
+ GetSystemInfo(&si);
+ return si.dwPageSize;
+#elif defined(HAVE_UNISTD_H)
+ return sysconf(_SC_PAGESIZE);
+#else
+ // Well, we have to return a number.
+ return 4096;
+#endif
+ }
+
+ // Subroutine of os_acquire_raw_memory. Attempt to acquire
+ // storage from the host OS. Return null on failure.
+ static inline Pointer
+ os_allocate_read_write_raw_memory(size_t nbytes) {
+#if defined(OPENAXIOM_MS_WINDOWS_HOST)
+ return VirtualAlloc(Pointer(), nbytes,
+ MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+#elif defined(HAVE_SYS_MMAN_H)
+ Pointer p = mmap(Pointer(), nbytes, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | OPENAXIOM_MM_ANONYMOUS_MAP_FLAG,
+ -1, 0);
+ return p == MAP_FAILED ? Pointer() : p;
+#else
+ return malloc(byte_count);
+#endif
+ }
+
+ Pointer
+ os_acquire_raw_memory(size_t nbytes) {
+ Pointer p = os_allocate_read_write_raw_memory(nbytes);
+ if (p == 0)
+ throw SystemError("cannot acquire more memory");
+ return memset(p, nbytes, 0);
+ }
+
+ void
+ os_release_raw_memory(Pointer p, size_t n) {
+#if defined(OPENAXIOM_MS_WINDOWS_HOST)
+ VirtualFree(p, 0, MEM_RELEASE);
+#elif defined(HAVE_SYS_MMAN_H)
+ munmap(p, n);
+#else
+ free(p);
+#endif
+ }
+
+ // -----------------
+ // -- FileMapping --
+ // -----------------
+ FileMapping::FileMapping(std::string path)
+ : start(), extent() {
+#if defined(OPENAXIOM_MS_WINDOWS_HOST)
+ HANDLE file = CreateFile(path.c_str(), GENERIC_READ, 0, 0,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, 0);
+ if (file == INVALID_HANDLE_VALUE)
+ filesystem_error("could not access file " + path);
+ HANDLE mapping = CreateFileMapping(file, 0, PAGE_READONLY, 0, 0, 0);
+ if (mapping == 0)
+ filesystem_error("could not map file " + path);
+ start = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
+ extent = GetFileSize(file, 0);
+ CloseHandle(mapping);
+ CloseHandle(file);
+#elif defined(HAVE_SYS_STAT_H) && defined(HAVE_SYS_MMAN_H) && defined(HAVE_FCNTL_H)
+ struct stat s;
+ errno = 0;
+ if (stat(path.c_str(), &s) < 0)
+ filesystem_error("could not access file " + path);
+ else if (!S_ISREG(s.st_mode))
+ filesystem_error(path + " is not a regular file");
+ int fd = open(path.c_str(), O_RDONLY);
+ if (fd < 0)
+ filesystem_error("could not open " + path);
+ start = mmap(Pointer(), s.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ close(fd);
+ if (start == MAP_FAILED)
+ filesystem_error("could not map file " + path);
+ extent = s.st_size;
+#else
+# error "Don't know how to map a file on this platform"
+#endif // OPENAXIOM_MS_WINDOWS_HOST
+ }
+
+ FileMapping::~FileMapping() {
+#if defined(OPENAXIOM_MS_WINDOWS_HOST)
+ UnmapViewOfFile(start);
+#elif defined(HAVE_SYS_MMAN_H)
+ munmap(start, extent);
+#else
+# error "Don't know how to unmap a file on this platform"
+#endif
+ }
+ }
+}