nitcc: introduce nitcc
authorJean Privat <jean@pryen.org>
Wed, 16 Oct 2013 04:44:59 +0000 (00:44 -0400)
committerJean Privat <jean@pryen.org>
Wed, 16 Oct 2013 04:56:54 +0000 (00:56 -0400)
Signed-off-by: Jean Privat <jean@pryen.org>

234 files changed:
contrib/nitcc/.gitignore [new file with mode: 0644]
contrib/nitcc/autom.nit [new file with mode: 0644]
contrib/nitcc/examples/calc.nit [new file with mode: 0644]
contrib/nitcc/examples/calc.sablecc [new file with mode: 0644]
contrib/nitcc/examples/json.sablecc [new file with mode: 0644]
contrib/nitcc/examples/minilang.minilang [new file with mode: 0644]
contrib/nitcc/examples/minilang.nit [new file with mode: 0644]
contrib/nitcc/examples/minilang.sablecc [new file with mode: 0644]
contrib/nitcc/examples/mkml.sh [new file with mode: 0755]
contrib/nitcc/grammar.nit [new file with mode: 0644]
contrib/nitcc/mk [new file with mode: 0755]
contrib/nitcc/nitcc.nit [new file with mode: 0644]
contrib/nitcc/nitcc.sablecc [new file with mode: 0644]
contrib/nitcc/nitcc_lexer0.nit [new file with mode: 0644]
contrib/nitcc/nitcc_parser_gen.nit [new file with mode: 0644]
contrib/nitcc/nitcc_runtime.nit [new file with mode: 0644]
contrib/nitcc/nitcc_semantic.nit [new file with mode: 0644]
contrib/nitcc/re2nfa.nit [new file with mode: 0644]
contrib/nitcc/t/alterner.pl [new file with mode: 0755]
contrib/nitcc/t/empty.input [new file with mode: 0644]
contrib/nitcc/t/empty.input2 [new file with mode: 0644]
contrib/nitcc/t/empty.sablecc [new file with mode: 0644]
contrib/nitcc/t/if.sablecc [new file with mode: 0644]
contrib/nitcc/t/inf5000-04-lexer-automate.input [new file with mode: 0644]
contrib/nitcc/t/inf5000-04-lexer-automate.sablecc [new file with mode: 0644]
contrib/nitcc/t/inf5000-04-lexer-demo.input [new file with mode: 0644]
contrib/nitcc/t/inf5000-04-lexer-demo.input2 [new file with mode: 0644]
contrib/nitcc/t/inf5000-04-lexer-demo.sablecc [new file with mode: 0644]
contrib/nitcc/t/inf5000-04-lexer-pire_cout.input [new file with mode: 0644]
contrib/nitcc/t/inf5000-04-lexer-pire_cout.input2 [new file with mode: 0644]
contrib/nitcc/t/inf5000-04-lexer-pire_cout.sablecc [new file with mode: 0644]
contrib/nitcc/t/inf5000-04-lexer-priorite_d_inclusion.input [new file with mode: 0644]
contrib/nitcc/t/inf5000-04-lexer-priorite_d_inclusion.sablecc [new file with mode: 0644]
contrib/nitcc/t/inf5000-04-lexer-priorite_declaree.input [new file with mode: 0644]
contrib/nitcc/t/inf5000-04-lexer-priorite_declaree.sablecc [new file with mode: 0644]
contrib/nitcc/t/inf5000-05-grammaire-arithmetique.input [new file with mode: 0644]
contrib/nitcc/t/inf5000-05-grammaire-arithmetique.sablecc [new file with mode: 0644]
contrib/nitcc/t/inf5000-05-grammaire-arithmetique2.input [new file with mode: 0644]
contrib/nitcc/t/inf5000-05-grammaire-arithmetique2.sablecc [new file with mode: 0644]
contrib/nitcc/t/inf5000-05-grammaire-formes.input [new file with mode: 0644]
contrib/nitcc/t/inf5000-05-grammaire-formes.sablecc [new file with mode: 0644]
contrib/nitcc/t/inf5000-05-grammaire-lisp.input [new file with mode: 0644]
contrib/nitcc/t/inf5000-05-grammaire-lisp.sablecc [new file with mode: 0644]
contrib/nitcc/t/inf5000-05-grammaire-listes.input [new file with mode: 0644]
contrib/nitcc/t/inf5000-05-grammaire-listes.sablecc [new file with mode: 0644]
contrib/nitcc/t/inf5000-05-grammaire-parentheses.input [new file with mode: 0644]
contrib/nitcc/t/inf5000-05-grammaire-parentheses.sablecc [new file with mode: 0644]
contrib/nitcc/t/inf5000-06-grammaire2-calculatrice.input [new file with mode: 0644]
contrib/nitcc/t/inf5000-06-grammaire2-calculatrice.sablecc [new file with mode: 0644]
contrib/nitcc/t/inf5000-06-grammaire2-grammaire.input [new file with mode: 0644]
contrib/nitcc/t/inf5000-06-grammaire2-grammaire.sablecc [new file with mode: 0644]
contrib/nitcc/t/inf5000-06-grammaire2-grammaire2.input [new file with mode: 0644]
contrib/nitcc/t/inf5000-06-grammaire2-grammaire2.sablecc [new file with mode: 0644]
contrib/nitcc/t/inf5000-06-grammaire2-instructions.input [new file with mode: 0644]
contrib/nitcc/t/inf5000-06-grammaire2-instructions.sablecc [new file with mode: 0644]
contrib/nitcc/t/inf5000-06-grammaire2-polygone.input [new file with mode: 0644]
contrib/nitcc/t/inf5000-06-grammaire2-polygone.sablecc [new file with mode: 0644]
contrib/nitcc/t/lalr.sablecc [new file with mode: 0644]
contrib/nitcc/t/lexer-c-comment.sablecc [new file with mode: 0644]
contrib/nitcc/t/lexer-errors.sablecc [new file with mode: 0644]
contrib/nitcc/t/lexer-implicit-longest-and-priority.input [new file with mode: 0644]
contrib/nitcc/t/lexer-implicit-longest-and-priority.sablecc [new file with mode: 0644]
contrib/nitcc/t/lexer-implicit-longest.input [new file with mode: 0644]
contrib/nitcc/t/lexer-implicit-longest.sablecc [new file with mode: 0644]
contrib/nitcc/t/lexer-markers.input [new file with mode: 0644]
contrib/nitcc/t/lexer-markers.sablecc [new file with mode: 0644]
contrib/nitcc/t/lexer-precedences.input [new file with mode: 0644]
contrib/nitcc/t/lexer-precedences.sablecc [new file with mode: 0644]
contrib/nitcc/t/lexer-shortest-longest.input [new file with mode: 0644]
contrib/nitcc/t/lexer-shortest-longest.sablecc [new file with mode: 0644]
contrib/nitcc/t/lexer-shortest-longest2.input [new file with mode: 0644]
contrib/nitcc/t/lexer-shortest-longest2.sablecc [new file with mode: 0644]
contrib/nitcc/t/lexer_conflict_token.sablecc [new file with mode: 0644]
contrib/nitcc/t/lexer_empty_token.sablecc [new file with mode: 0644]
contrib/nitcc/t/lexer_features.input [new file with mode: 0644]
contrib/nitcc/t/lexer_features.input2 [new file with mode: 0644]
contrib/nitcc/t/lr1.sablecc [new file with mode: 0644]
contrib/nitcc/t/modif.input1 [new file with mode: 0644]
contrib/nitcc/t/modif.input2 [new file with mode: 0644]
contrib/nitcc/t/modif.input3 [new file with mode: 0644]
contrib/nitcc/t/modif.input4 [new file with mode: 0644]
contrib/nitcc/t/modif.sablecc [new file with mode: 0644]
contrib/nitcc/t/nit_expr.sablecc [new file with mode: 0644]
contrib/nitcc/t/not_lalr.sablecc [new file with mode: 0644]
contrib/nitcc/t/not_slr.sablecc [new file with mode: 0644]
contrib/nitcc/t/pri.sablecc [new file with mode: 0644]
contrib/nitcc/t/priority.sablecc [new file with mode: 0644]
contrib/nitcc/t/qualified.sablecc [new file with mode: 0644]
contrib/nitcc/t/run [new file with mode: 0755]
contrib/nitcc/t/sav/calc.res [new file with mode: 0644]
contrib/nitcc/t/sav/empty.alt1.res [new file with mode: 0644]
contrib/nitcc/t/sav/empty.alt2.res [new file with mode: 0644]
contrib/nitcc/t/sav/empty.alt3.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/empty.alt3.input2.res [new file with mode: 0644]
contrib/nitcc/t/sav/empty.alt3.res [new file with mode: 0644]
contrib/nitcc/t/sav/empty.alt4.res [new file with mode: 0644]
contrib/nitcc/t/sav/empty.alt5.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/empty.alt5.input2.res [new file with mode: 0644]
contrib/nitcc/t/sav/empty.alt5.res [new file with mode: 0644]
contrib/nitcc/t/sav/empty.alt6.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/empty.alt6.input2.res [new file with mode: 0644]
contrib/nitcc/t/sav/empty.alt6.res [new file with mode: 0644]
contrib/nitcc/t/sav/empty.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/empty.input2.res [new file with mode: 0644]
contrib/nitcc/t/sav/empty.res [new file with mode: 0644]
contrib/nitcc/t/sav/expression.res [new file with mode: 0644]
contrib/nitcc/t/sav/if.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-04-lexer-automate.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-04-lexer-automate.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-04-lexer-demo.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-04-lexer-demo.input2.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-04-lexer-demo.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-04-lexer-pire_cout.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-04-lexer-pire_cout.input2.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-04-lexer-pire_cout.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-04-lexer-priorite_d_inclusion.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-04-lexer-priorite_d_inclusion.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-04-lexer-priorite_declaree.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-04-lexer-priorite_declaree.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-05-grammaire-arithmetique.alt1.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-05-grammaire-arithmetique.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-05-grammaire-arithmetique.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-05-grammaire-arithmetique2.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-05-grammaire-arithmetique2.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-05-grammaire-formes.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-05-grammaire-formes.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-05-grammaire-lisp.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-05-grammaire-lisp.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-05-grammaire-listes.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-05-grammaire-listes.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-05-grammaire-parentheses.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-05-grammaire-parentheses.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-06-grammaire2-calculatrice.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-06-grammaire2-calculatrice.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-06-grammaire2-grammaire.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-06-grammaire2-grammaire.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-06-grammaire2-grammaire2.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-06-grammaire2-grammaire2.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-06-grammaire2-instructions.alt1.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-06-grammaire2-instructions.alt1.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-06-grammaire2-instructions.alt2.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-06-grammaire2-instructions.alt2.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-06-grammaire2-instructions.alt3.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-06-grammaire2-instructions.alt3.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-06-grammaire2-instructions.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-06-grammaire2-instructions.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-06-grammaire2-polygone.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/inf5000-06-grammaire2-polygone.res [new file with mode: 0644]
contrib/nitcc/t/sav/json.res [new file with mode: 0644]
contrib/nitcc/t/sav/lalr.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-c-comment.alt1.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-c-comment.alt2.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-c-comment.alt3.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-c-comment.alt4.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-c-comment.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-errors.alt1.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-errors.alt2.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-errors.alt3.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-errors.alt4.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-errors.alt5.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-errors.alt6.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-errors.alt7.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-errors.alt8.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-errors.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-implicit-longest-and-priority.alt1.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-implicit-longest-and-priority.alt1.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-implicit-longest-and-priority.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-implicit-longest.alt1.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-implicit-longest.alt1.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-implicit-longest.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-markers.alt1.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-markers.alt1.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-markers.alt2.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-markers.alt2.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-markers.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-markers.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-precedences.alt1.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-precedences.alt1.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-precedences.alt10.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-precedences.alt10.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-precedences.alt2.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-precedences.alt2.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-precedences.alt3.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-precedences.alt3.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-precedences.alt4.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-precedences.alt4.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-precedences.alt5.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-precedences.alt5.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-precedences.alt6.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-precedences.alt6.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-precedences.alt7.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-precedences.alt7.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-precedences.alt8.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-precedences.alt9.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-precedences.alt9.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-precedences.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-shortest-longest.alt1.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-shortest-longest.alt2.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-shortest-longest.alt3.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-shortest-longest.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-shortest-longest.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-shortest-longest2.alt1.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-shortest-longest2.alt1.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-shortest-longest2.alt2.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-shortest-longest2.alt3.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-shortest-longest2.alt3.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-shortest-longest2.alt4.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer-shortest-longest2.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer_conflict_token.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer_empty_token.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer_features.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer_features.input2.res [new file with mode: 0644]
contrib/nitcc/t/sav/lexer_features.res [new file with mode: 0644]
contrib/nitcc/t/sav/lr1.res [new file with mode: 0644]
contrib/nitcc/t/sav/minilang.res [new file with mode: 0644]
contrib/nitcc/t/sav/mixed_list.res [new file with mode: 0644]
contrib/nitcc/t/sav/modif.input1.res [new file with mode: 0644]
contrib/nitcc/t/sav/modif.input2.res [new file with mode: 0644]
contrib/nitcc/t/sav/modif.input3.res [new file with mode: 0644]
contrib/nitcc/t/sav/modif.input4.res [new file with mode: 0644]
contrib/nitcc/t/sav/modif.res [new file with mode: 0644]
contrib/nitcc/t/sav/nit_expr.res [new file with mode: 0644]
contrib/nitcc/t/sav/not_lalr.res [new file with mode: 0644]
contrib/nitcc/t/sav/not_slr.res [new file with mode: 0644]
contrib/nitcc/t/sav/pri.res [new file with mode: 0644]
contrib/nitcc/t/sav/priority.res [new file with mode: 0644]
contrib/nitcc/t/sav/qualified.res [new file with mode: 0644]
contrib/nitcc/t/sav/trans.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/trans.res [new file with mode: 0644]
contrib/nitcc/t/sav/trans_inline.input.res [new file with mode: 0644]
contrib/nitcc/t/sav/trans_inline.res [new file with mode: 0644]
contrib/nitcc/t/t [new file with mode: 0755]
contrib/nitcc/t/trans.sablecc [new file with mode: 0644]
contrib/nitcc/t/trans_inline.sablecc [new file with mode: 0644]

diff --git a/contrib/nitcc/.gitignore b/contrib/nitcc/.gitignore
new file mode 100644 (file)
index 0000000..6e56095
--- /dev/null
@@ -0,0 +1,16 @@
+*.dot
+*_parser.nit
+*_lexer.nit
+*_test_parser
+*.concrete_grammar.txt
+*.lr.txt
+t/alt
+t/out
+t/tap.output
+
+nitcc_parser_gen
+nitcc0
+nitcc1
+nitcc
+examples/calc
+examples/minilang
diff --git a/contrib/nitcc/autom.nit b/contrib/nitcc/autom.nit
new file mode 100644 (file)
index 0000000..2d1ca78
--- /dev/null
@@ -0,0 +1,541 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Finite automaton (NFA & DFA)
+module autom
+
+# For the class Token
+import grammar
+
+# A finite automaton
+class Automaton
+       # The start state
+       var start: State
+
+       # State that are accect states
+       var accept = new Array[State]
+
+       # All states
+       var states = new Array[State]
+
+       # Tokens associated on accept states
+       # use `add_tag` to update
+       var tags = new HashMap[State, Set[Token]]
+
+       # Accept states associated on tokens
+       # use `add_tag` to update
+       var retrotags = new HashMap[Token, Set[State]]
+
+       # Add a token to a state
+       fun add_tag(s: State, t: Token)
+       do
+               if not tags.has_key(s) then
+                       var set = new ArraySet[Token]
+                       tags[s] = set
+                       set.add t
+               else
+                       tags[s].add t
+               end
+
+               if not retrotags.has_key(t) then
+                       var set = new ArraySet[State]
+                       retrotags[t] = set
+                       set.add s
+               else
+                       retrotags[t].add s
+               end
+       end
+
+       # Remove tokens from conflicting state according the the inclusion of language
+       # REQUIRE: self isa DFA automaton
+       fun solve_token_inclusion
+       do
+               for s, ts in tags do
+                       if ts.length <= 1 then continue
+                       var losers = new Array[Token]
+                       for t1 in ts do
+                               for t2 in ts do
+                                       if t1 == t2 then continue
+                                       if retrotags[t1].length > retrotags[t2].length and retrotags[t1].has_all(retrotags[t2]) then
+                                               losers.add(t1)
+                                               break
+                                       end
+                               end
+                       end
+                       for t in losers do
+                               ts.remove(t)
+                               retrotags[t].remove s
+                       end
+               end
+       end
+
+       # Initialize a new automaton for the empty language
+       # one state, no accept, no transition
+       init empty
+       do
+               var state = new State
+               start = state
+               states.add state
+       end
+
+       # Initialize a new automaton for the empty-string language
+       # one state, is accept, no transition
+       init epsilon
+       do
+               var state = new State
+               start = state
+               accept.add state
+               states.add state
+       end
+
+       # Initialize a new automation for the language that accepts only a single symbol
+       # Two state, the second is accept, one transition on `symbol`
+       init atom(symbol: Int)
+       do
+               var s = new State
+               var a = new State
+               s.add_trans(a, symbol)
+               start = s
+               accept.add a
+               states.add s
+               states.add a
+       end
+
+       # Initialize a new automation for the language that accepts only a range of symbols
+       # Two state, the second is accept, one transition for `from` to `to`
+       init cla(from, to: Int)
+       do
+               var s = new State
+               var a = new State
+               for symbol in [from..to] do
+                       s.add_trans(a, symbol)
+               end
+               start = s
+               accept.add a
+               states.add s
+               states.add a
+       end
+
+       # Contatenate `other` to `self`
+       # other is modified and invalidated.
+       fun concat(other: Automaton)
+       do
+               var s2 = other.start
+               for a1 in accept do
+                       a1.add_trans(s2, null)
+               end
+               accept = other.accept
+               states.add_all other.states
+       end
+
+       # `self` become the alternation of `self` and `other`
+       # `other` is modified and invalidated.
+       fun alternate(other: Automaton)
+       do
+               var s = new State
+               var a = new State
+               s.add_trans(start, null)
+               for a1 in accept do
+                       a1.add_trans(a, null)
+               end
+               s.add_trans(other.start, null)
+               for a2 in other.accept do
+                       a2.add_trans(a, null)
+                       accept.add(a2)
+               end
+
+               start = s
+               accept = [a]
+
+               states.add s
+               states.add a
+               states.add_all other.states
+       end
+
+       # Do the Kleene closure (*) on self
+       fun close
+       do
+               for a1 in accept do
+                       a1.add_trans(start, null)
+                       start.add_trans(a1, null)
+               end
+       end
+
+       # Do the + on self
+       fun plus
+       do
+               for a1 in accept do
+                       a1.add_trans(start, null)
+               end
+       end
+
+       # Do the ? on self
+       fun optionnal
+       do
+               alternate(new Automaton.epsilon)
+       end
+
+       # Remove all transitions on a given symbol
+       fun minus_sym(symbol: Int)
+       do
+               for s in states do
+                       for t in s.outs.to_a do
+                               if t.symbol == symbol then t.delete
+                       end
+               end
+       end
+
+       # Fully duplicate an automaton
+       fun dup: Automaton
+       do
+               var res = new Automaton.empty
+               var map = new HashMap[State, State]
+               map[start] = res.start
+               for s in states do
+                       if s == start then continue
+                       var s2 = new State
+                       map[s] = s2
+                       res.states.add(s2)
+               end
+               for s in accept do
+                       res.accept.add map[s]
+               end
+               for s, ts in tags do for t in ts do
+                       res.add_tag(map[s], t)
+               end
+               for s in states do
+                       for t in s.outs do
+                               map[s].add_trans(map[t.to], t.symbol)
+                       end
+               end
+               return res
+       end
+
+       # Produce a graphvis file for the automaton
+       fun to_dot(filepath: String)
+       do
+               var f = new OFStream.open(filepath) 
+                f.write("digraph g \{\n")
+
+               for s in states do
+                       f.write("s{s.object_id}[")
+                       #f.write("label=\"\",")
+                       if accept.has(s) then
+                               f.write("color=blue")
+                               if tags.has_key(s) then
+                                       f.write(",label=\"")
+                                       for token in tags[s] do
+                                               f.write("{token.name.escape_to_c}\\n")
+                                       end
+                                       f.write("\"")
+                               end
+                       end
+                       f.write("];\n")
+                       var outs = new HashMap[State, Array[nullable Int]]
+                       for t in s.outs do
+                               var a
+                               var s2 = t.to
+                               var c = t.symbol
+                               if outs.has_key(s2) then
+                                       a = outs[s2]
+                               else
+                                       a = new Array[nullable Int]
+                                       outs[s2] = a
+                               end
+                               a.add(c)
+                       end
+                       for s2, a in outs do
+                               var labe = ""
+                               var lastc: nullable Int = null
+                               var elip = 0
+                               a.add(-1)
+                               for c in a do
+                                       if c == null then
+                                               if not labe.is_empty then labe += "\n"
+                                               labe += "''"
+                                       else if lastc == c - 1 then
+                                               elip += 1
+                                               lastc = c
+                                       else
+                                               if elip == 1 then
+                                                       assert lastc != null
+                                                       labe += "\n{sym_to_s(lastc)}"
+                                               else if elip > 1 then
+                                                       assert lastc != null
+                                                       labe += " .. {sym_to_s(lastc)}"
+                                               end
+                                               if c == -1 then break
+                                               if not labe.is_empty then labe += "\n"
+                                               labe += sym_to_s(c)
+                                               lastc = c
+                                       end
+                               end
+                               f.write("s{s.object_id}->s{s2.object_id} [label=\"{labe.escape_to_c}\"];\n")
+                       end
+               end
+               f.write("empty->s{start.object_id}; empty[label=\"\",shape=none];\n")
+
+                f.write("\}\n")
+               f.close
+       end
+
+       # Transform a symbol to a string
+       # Used by `to_dot`
+       private fun sym_to_s(symbol: nullable Int): String
+       do
+               if symbol == null then
+                       return "''"
+               else if symbol <= 32 then
+                       return "#{symbol}"
+               else
+                       return symbol.ascii.to_s
+               end
+       end
+
+       # Transform a NFA to a DFA
+       # note: the DFA is not miminized
+       fun to_dfa: Automaton
+       do
+               var dfa = new Automaton.empty
+               var n2d = new ArrayMap[Set[State], State]
+               var seen = new ArraySet[Set[State]] 
+               var ts = new HashSet[Int]
+               var st = eclosure([start])
+               var todo = [st]
+               n2d[st] = dfa.start
+               seen.add(st)
+               while not todo.is_empty do
+                       var nfa_states = todo.pop
+                       #print "* work on {nfa_states.inspect}={nfa_states} (remains {todo.length}/{seen.length})"
+                       var dfa_state = n2d[nfa_states]
+                       ts.clear
+                       for s in nfa_states do
+                               if accept.has(s) then
+                                       if tags.has_key(s) then
+                                               for t in tags[s] do
+                                                       dfa.add_tag(dfa_state, t)
+                                               end
+                                       end
+                                       dfa.accept.add(dfa_state)
+                               end
+                               for t in s.outs do
+                                       var sym = t.symbol
+                                       if sym == null or ts.has(sym) then continue
+                                       ts.add(sym)
+                                       var nfa_dest = eclosure(trans(nfa_states, sym))
+                                       #print "{nfa_states} -> {sym} -> {nfa_dest}"
+                                       var dfa_dest
+                                       if seen.has(nfa_dest) then
+                                               #print "* reuse {nfa_dest.inspect}={nfa_dest}"
+                                               dfa_dest = n2d[nfa_dest]
+                                       else
+                                               #print "* new {nfa_dest.inspect}={nfa_dest}"
+                                               dfa_dest = new State
+                                               dfa.states.add(dfa_dest)
+                                               n2d[nfa_dest] = dfa_dest
+                                               todo.add(nfa_dest)
+                                               seen.add(nfa_dest)
+                                       end
+                                       dfa_state.add_trans(dfa_dest, sym)
+                               end
+                       end
+               end
+               return dfa
+       end
+
+       # epsilon-closure on a state of states
+       # used by `to_dfa`
+       private fun eclosure(states: Collection[State]): Set[State]
+       do
+               var res = new ArraySet[State]
+               res.add_all(states)
+               var todo = states.to_a
+               while not todo.is_empty do
+                       var s = todo.pop
+                       for t in s.outs do
+                               if t.symbol != null then continue
+                               var to = t.to
+                               if res.has(to) then continue 
+                               res.add(to)
+                               todo.add(to)
+                       end
+               end
+               return res
+       end
+
+       # trans on a set of states
+       # Used by `to_dfa`
+       fun trans(states: Collection[State], symbol: Int): Set[State]
+       do
+               var res = new ArraySet[State]
+               for s in states do
+                       for t in s.outs do
+                               if t.symbol != symbol then continue
+                               var to = t.to
+                               if res.has(to) then continue 
+                               res.add(to)
+                       end
+               end
+               return res
+       end
+
+       # Generate the Nit source code of the lexer
+       # `filepath` is the name of the ouptit file
+       # `parser` is the name of the parser module (used to import the token classes)
+       fun gen_to_nit(filepath: String, parser: nullable String)
+       do
+               var gen = new DFAGenerator(filepath, self, parser)
+               gen.gen_to_nit
+       end
+end
+
+# Generate the Nit source code of the lexer
+private class DFAGenerator
+       var filepath: String
+       var automaton: Automaton
+       var parser: nullable String
+
+       var out: OStream
+       init(filepath: String, automaton: Automaton, parser: nullable String) do
+               self.filepath = filepath
+               self.automaton = automaton
+               self.parser = parser
+               self.out = new OFStream.open(filepath)
+       end
+
+       fun add(s: String) do out.write(s)
+
+       fun gen_to_nit
+       do
+               var names = new HashMap[State, String]
+               var i = 0
+               for s in automaton.states do
+                       names[s] = i.to_s
+                       i += 1
+               end
+
+               add "# Lexer generated by nitcc"
+               add("import nitcc_runtime\n")
+
+               var p = parser
+               if p != null then add("import {p}\n")
+
+               add("class MyLexer\n")
+               add("\tsuper Lexer\n")
+               add("\tredef fun start_state do return dfastate_{names[automaton.start]}\n")
+               add("end\n")
+
+               add("redef class Object\n")
+               for s in automaton.states do
+                       var n = names[s]
+                       add("\tprivate fun dfastate_{n}: DFAState{n} do return once new DFAState{n}\n")
+               end
+               add("end\n")
+
+               add("class MyNToken\n")
+               add("\tsuper NToken\n")
+               add("end\n")
+
+               for s in automaton.states do
+                       var  n = names[s]
+                       add("class DFAState{n}\n")
+                       add("\tsuper DFAState\n")
+                       if automaton.accept.has(s) then
+                               var token
+                               if automaton.tags.has_key(s) then
+                                       token = automaton.tags[s].first
+                               else
+                                       token = null
+                               end
+                               add("\tredef fun is_accept do return true\n")
+                               add("\tredef fun make_token(position, text) do\n")
+                               if token != null and token.name == "Ignored" then
+                                       add("\t\treturn null\n")
+                               else
+                                       if token == null then
+                                               add("\t\tvar t = new MyNToken\n")
+                                       else
+                                               add("\t\tvar t = new {token.cname}\n")
+                                       end
+                                       add("\t\tt.position = position\n")
+                                       add("\t\tt.text = text\n")
+                                       add("\t\treturn t\n")
+                               end
+                               add("\tend\n")
+                       end
+                       var trans = new ArrayMap[Int, State]
+                       for t in s.outs do
+                               var sym = t.symbol
+                               assert sym != null
+                               trans[sym] = t.to
+                       end
+                       if trans.is_empty then
+                               # Do nothing, inherit the trans
+                       else if trans.length == 1 then
+                               var sym = trans.keys.first
+                               var next = trans.values.first
+                               add("\tredef fun trans(c) do\n")
+                               add("\t\tif c.ascii == {sym} then return dfastate_{names[next]}\n")
+                               add("\t\treturn null\n")
+                               add("\tend\n")
+                       else
+                               add("\tredef fun trans(c) do\n")
+                               for sym, next in trans do
+                                       add("\t\tif c.ascii == {sym} then return dfastate_{names[next]}\n")
+                               end
+                               add("\t\treturn null\n")
+                               add("\tend\n")
+                       end
+                       add("end\n")
+               end
+
+               self.out.close
+       end
+end
+
+# A state in a finite automaton
+class State
+       # Outgoing transitions
+
+       var outs = new Array[Transition]
+       # Ingoing tyransitions
+       var ins = new Array[Transition]
+
+       # Add a transitions to `to` on `symbol` (null means epsilon)
+       fun add_trans(to: State, symbol: nullable Int): Transition
+       do
+               var t = new Transition(self, to, symbol)
+               outs.add(t)
+               to.ins.add(t)
+               return t
+       end
+end
+
+# A transition in a finite automaton
+class Transition
+       # The source state
+       var from: State
+       # The destination state
+       var to: State
+       # The symbol on the transition (null means epsilon)
+       var symbol: nullable Int
+
+       # Remove the transition from the automaton
+       # Detash from `from` and `to`
+       fun delete
+       do
+               from.outs.remove(self)
+               to.ins.remove(self)
+       end
+end
diff --git a/contrib/nitcc/examples/calc.nit b/contrib/nitcc/examples/calc.nit
new file mode 100644 (file)
index 0000000..1ee7bc3
--- /dev/null
@@ -0,0 +1,82 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Example of a calculation used nitcc
+# see `calc.sablecc` for the grammar
+module calc
+
+# Reuse the test program to simplify the code
+import calc_test_parser
+
+# The main evaluator, as a visitiopn that stack values
+class Calulator
+       super Visitor
+
+       # The stack of values
+       var stack = new Array[Int]
+
+       redef fun visit(n) do n.accept_calculator(self)
+end
+
+redef class Node
+       # Default caculation is to visit the childrens
+       fun accept_calculator(v: Calulator) do visit_children(v)
+end
+
+redef class Nint
+       redef fun accept_calculator(v) do v.stack.push(text.to_i)
+end
+
+redef class Ne_add
+       redef fun accept_calculator(v) do
+               super
+               v.stack.push(v.stack.pop+v.stack.pop)
+       end
+end
+
+redef class Ne_sub
+       redef fun accept_calculator(v) do
+               super
+               var n1 = v.stack.pop
+               v.stack.push(v.stack.pop-n1)
+       end
+end
+
+redef class Ne_neg
+       redef fun accept_calculator(v) do
+               super
+               v.stack.push(-v.stack.pop)
+       end
+end
+
+redef class Ne_mul
+       redef fun accept_calculator(v) do
+               super
+               v.stack.push(v.stack.pop*v.stack.pop)
+       end
+end
+
+redef class Ne_div
+       redef fun accept_calculator(v) do
+               super
+               var n1 = v.stack.pop
+               v.stack.push(v.stack.pop/n1)
+       end
+end
+
+var t = new MyTest
+var n = t.main
+var v = new Calulator
+v.enter_visit(n)
+print v.stack.pop
diff --git a/contrib/nitcc/examples/calc.sablecc b/contrib/nitcc/examples/calc.sablecc
new file mode 100644 (file)
index 0000000..077aad5
--- /dev/null
@@ -0,0 +1,22 @@
+/* A simple calculator, see calc.nit */
+Grammar calc;
+
+Lexer
+d = '0'..'9';
+int = d+;
+blank = (' '|'\n')+;
+
+Parser
+Ignored blank;
+e =
+       {add:} e '+' f |
+       {sub:} e '-' f |
+       f {->f};
+f {->e} =
+       {mul:} f '*' a |
+       {div:} f '/' a |
+       a {->a};
+a {->e} =
+       {int:} int |
+       {par:} '(' e ')' |
+       {neg:} '-' a ;
diff --git a/contrib/nitcc/examples/json.sablecc b/contrib/nitcc/examples/json.sablecc
new file mode 100644 (file)
index 0000000..4ec4c55
--- /dev/null
@@ -0,0 +1,31 @@
+Grammar json;
+
+Lexer
+
+number = int frac? exp;
+int = '-'? d+;
+d = '0'..'9';
+frac = '.' d+;
+exp = e d+;
+e = ('e'|'E') ('+'|'-')?;
+
+string = '"' (ch-'\\'-'"' | '\\'ch)+ '"';
+ch = ' '..'~';
+
+blank = (' '|'\n'|'\t')+;
+
+Parser
+Ignored blank;
+
+value =
+       {object:} '{' members? '}' |
+       {array:} '[' elements? ']' |
+       number |
+       string |
+       'true' |
+       'false' |
+       'null' ;
+
+members = members ',' pair | pair ;
+pair = string ':' value ;
+elements = elements ',' value | value ;
diff --git a/contrib/nitcc/examples/minilang.minilang b/contrib/nitcc/examples/minilang.minilang
new file mode 100644 (file)
index 0000000..7347ea9
--- /dev/null
@@ -0,0 +1,28 @@
+a=1+2;
+a=a*3;
+print(a-4);
+println();
+
+f = 1;
+fn = 0;
+while (f < 500) {
+        t = f;
+        f = f + fn;
+        fn = t;
+}
+print("le plus petit nombre de Fibbonacci > 500 est ");
+print(f);
+println();
+
+print("Plus ou moins ? (hint la reponse est 42)");
+println();
+goal = 42;
+lu = -1;
+while (lu != goal) {
+        print("Votre choix: ");
+        lu = read();
+        if (lu > goal) { print("c'est plus petit."); println(); }
+        if (lu < goal) { print("c'est plus grand."); println(); }
+}
+print("C'est bon.");
+println();
diff --git a/contrib/nitcc/examples/minilang.nit b/contrib/nitcc/examples/minilang.nit
new file mode 100644 (file)
index 0000000..c639f14
--- /dev/null
@@ -0,0 +1,182 @@
+import minilang_test_parser
+
+class Interpretor
+       super Visitor
+       var stack = new Array[Int]
+       var bstack = new Array[Bool]
+       var vars = new HashMap[String, Int]
+
+       redef fun visit(n) do n.accept_calculator(self)
+end
+
+redef class Node
+       fun accept_calculator(v: Interpretor) do visit_children(v)
+end
+
+redef class Nint
+       redef fun accept_calculator(v) do v.stack.push(text.to_i)
+end
+
+redef class Ns_assign
+       redef fun accept_calculator(v) do
+               super
+               v.vars[n_id.text] = v.stack.pop
+       end
+end
+
+redef class Ns_print
+       redef fun accept_calculator(v) do
+               super
+               printn v.stack.pop
+       end
+end
+redef class Ns_print_str
+       redef fun accept_calculator(v) do
+               var text = n_str.text
+               text = text.substring(1, text.length-2)
+               printn text
+       end
+end
+redef class Ns_println
+       redef fun accept_calculator(v) do
+               print ""
+       end
+end
+redef class Ns_if
+       redef fun accept_calculator(v) do
+               v.enter_visit(n_c)
+               if v.bstack.pop then
+                       v.enter_visit(n_then)
+               else
+                       var nelse = n_else
+                       if nelse != null then v.enter_visit(nelse)
+               end
+       end
+end
+redef class Ns_while
+       redef fun accept_calculator(v) do
+               loop
+                       v.enter_visit(n_c)
+                       if not v.bstack.pop then break
+                       v.enter_visit(n_stmts)
+               end
+       end
+end
+
+
+redef class Nc_and
+       redef fun accept_calculator(v) do
+               super
+               var b1 = v.bstack.pop
+               var b2 = v.bstack.pop
+               v.bstack.push(b1 and b2)
+       end
+end
+
+redef class Nc_or
+       redef fun accept_calculator(v) do
+               super
+               var b1 = v.bstack.pop
+               var b2 = v.bstack.pop
+               v.bstack.push(b1 or b2)
+       end
+end
+
+redef class Nc_not
+       redef fun accept_calculator(v) do
+               super
+               v.bstack.push(not v.bstack.pop)
+       end
+end
+
+redef class Nc_eq
+       redef fun accept_calculator(v) do
+               super
+               v.bstack.push(v.stack.pop == v.stack.pop)
+       end
+end
+
+redef class Nc_ne
+       redef fun accept_calculator(v) do
+               super
+               v.bstack.push(v.stack.pop != v.stack.pop)
+       end
+end
+
+redef class Nc_lt
+       redef fun accept_calculator(v) do
+               super
+               v.bstack.push(v.stack.pop > v.stack.pop)
+       end
+end
+
+redef class Nc_le
+       redef fun accept_calculator(v) do
+               super
+               v.bstack.push(v.stack.pop >= v.stack.pop)
+       end
+end
+
+redef class Nc_gt
+       redef fun accept_calculator(v) do
+               super
+               v.bstack.push(v.stack.pop < v.stack.pop)
+       end
+end
+
+redef class Nc_ge
+       redef fun accept_calculator(v) do
+               super
+               v.bstack.push(v.stack.pop <= v.stack.pop)
+       end
+end
+
+redef class Ne_add
+       redef fun accept_calculator(v) do
+               super
+               v.stack.push(v.stack.pop+v.stack.pop)
+       end
+end
+redef class Ne_sub
+       redef fun accept_calculator(v) do
+               super
+               var n1 = v.stack.pop
+               v.stack.push(v.stack.pop-n1)
+       end
+end
+redef class Ne_neg
+       redef fun accept_calculator(v) do
+               super
+               v.stack.push(-v.stack.pop)
+       end
+end
+redef class Ne_mul
+       redef fun accept_calculator(v) do
+               super
+               v.stack.push(v.stack.pop*v.stack.pop)
+       end
+end
+redef class Ne_div
+       redef fun accept_calculator(v) do
+               super
+               var n1 = v.stack.pop
+               v.stack.push(v.stack.pop/n1)
+       end
+end
+redef class Ne_var
+       redef fun accept_calculator(v) do
+               v.stack.push v.vars[n_id.text]
+       end
+end
+redef class Ne_read
+       redef fun accept_calculator(v) do
+               var t = gets
+               v.stack.push(t.to_i)
+       end
+end
+
+var t = new MyTest
+var n = t.main
+
+var v = new Interpretor 
+v.enter_visit(n)
diff --git a/contrib/nitcc/examples/minilang.sablecc b/contrib/nitcc/examples/minilang.sablecc
new file mode 100644 (file)
index 0000000..7c951c0
--- /dev/null
@@ -0,0 +1,57 @@
+/* Grammar of a mini procedural programming language */
+Grammar minilang;
+
+Lexer
+l = 'a'..'z'|'A'..'Z'|'_';
+d = '0'..'9';
+id = l (l|d)*;
+int = d+;
+str = '"' (' '..'~' - '"')* '"';
+blank = ' ' | '\n' | '\t';
+
+Parser
+Ignored blank;
+
+prog = s*;
+
+s =
+       {assign:} id '=' e ';' |
+       {print:} 'print' '(' e ')' ';' |
+       {print_str:} 'print' '(' str ')' ';' |
+       {println:} 'println' '(' ')' ';' |
+       {while:} 'while' '(' c ')' stmts |
+       {if:} 'if' '(' c ')' [then:]stmts else? ;
+
+stmts = '{' s* '}' ;
+
+else = 'else' stmts;
+
+e = 
+       {add:} [left:]e '+' [right:]e2 |
+       {sub:} [left:]e '-' [right:]e2 |
+       e2 {->e2};
+e2 {->e} =
+       {mul:} [left:]e2 '*' [right:]e3 |
+       {div:} [left:]e2 '/' [right:]e3 |
+       e3 {->e3};
+e3 {->e} =
+       {neg:} '-' e3 |
+       {lit:} int |
+       {par:} '(' e ')' |
+       {var:} id |
+       {read:} 'read' '(' ')' ;
+
+c =
+       {or:} [left:]c '||' [right:]c2 |
+       c2 {->c2};
+c2 {->c} =
+       {and:} [left:]c2 '&&' [right:]c3 |
+       c3 {->c3};
+c3 {->c} =
+       {not:} 'not' [c:]c3 |
+       {eq:} [left:]e '=' [right:]e |
+       {ne:} [left:]e '!=' [right:]e |
+       {lt:} [left:]e '<' [right:]e |
+       {le:} [left:]e '<=' [right:]e |
+       {gt:} [left:]e '>' [right:]e |
+       {ge:} [left:]e '>=' [right:]e ;
diff --git a/contrib/nitcc/examples/mkml.sh b/contrib/nitcc/examples/mkml.sh
new file mode 100755 (executable)
index 0000000..1b49c51
--- /dev/null
@@ -0,0 +1,5 @@
+set -e
+set -x
+../nitcc minilang.sablecc
+../../../bin/nitc minilang.nit -v -I ..
+./minilang minilang.minilang
diff --git a/contrib/nitcc/grammar.nit b/contrib/nitcc/grammar.nit
new file mode 100644 (file)
index 0000000..6cb7956
--- /dev/null
@@ -0,0 +1,1054 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# A gramar describing a language
+class Gram
+       # The productions (non-terminal) of the conctete grammar
+       var prods = new Array[Production]
+
+       # The additionnal abstract productions of the grammar
+       # TODO clean AST
+       var ast_prods = new Array[Production]
+
+       # The tokens (terminals) of the grammar
+       var tokens = new Array[Token]
+
+       # Dump of the concrete grammar and the transformations
+       fun pretty: String
+       do
+               var res = new Buffer
+               for p in prods do
+                       if p.spe != null then
+                               res.append("{p.name} \{-> {p.spe.name}\}=\n")
+                       else
+                               res.append("{p.name} =\n")
+                       end
+                       var last = p.alts.last
+                       for a in p.alts do
+                               res.append("\t\{{a.name}:\} {a.elems.join(" ")}")
+                               if a.codes == null then a.make_codes
+                               res.append("\n\t\t\{-> {a.codes.join(", ")}\}")
+                               if a == last then res.append(" ;\n") else res.append(" |\n")
+                       end
+                       if p.is_nullable then res.append "\t// is nullable\n"
+                       if not p.firsts.is_empty then res.append "\t// firsts: {p.firsts.join(" ")}\n"
+                       if not p.afters.is_empty then res.append "\t// afters: {p.afters.join(" ")}\n"
+               end
+               return res.to_s
+       end
+
+       # Inline (ie. remove from the conctete grammar) some production
+       # REQUIRE: no circular production in `prods`
+       fun inline(prods: Collection[Production])
+       do
+               for p in self.prods do
+                       for a in p.alts.to_a do
+                               var to_inline = false
+                               for e in a.elems do
+                                       if e isa Production and prods.has(e) then to_inline = true
+                               end
+                               if not to_inline then continue
+
+                               if a.codes == null then a.make_codes
+
+                               var a0 = new Alternative(p, a.name, new Array[Element])
+                               a0.trans = true
+                               a0.codes = new Array[Code]
+                               var pool = [a0]
+                               var pool2 = new Array[Alternative]
+                               for e in a.elems do
+                                       if not e isa Production or not prods.has(e) then
+                                               for x in pool do
+                                                       x.elems.add(e)
+                                                       x.codes.add(new CodePop)
+                                               end
+                                               continue
+                                       end
+                                       if p == e then
+                                               print "Circular inlining on {p} :: {a}"
+                                               abort
+                                       end
+                                       pool2.clear
+                                       for a2 in e.alts do
+                                               if a2.codes == null then a2.make_codes
+                                               for x in pool do
+                                                       var name = a.name + "_" + pool2.length.to_s
+                                                       var na = new Alternative(p, name, new Array[Element])
+                                                       na.trans = true
+                                                       pool2.add(na)
+                                                       na.elems.add_all(x.elems)
+                                                       na.elems.add_all(a2.elems)
+                                                       na.codes = new Array[Code]
+                                                       na.codes.add_all(x.codes.as(not null))
+                                                       na.codes.add_all(a2.codes.as(not null))
+                                               end
+                                       end
+                                       var tmp = pool
+                                       pool = pool2
+                                       pool2 = tmp
+                               end
+                               for x in pool do
+                                       x.codes.add(a.codes.last)
+                               end
+                               p.ast_alts.add(a)
+                               p.alts.remove(a)
+                               p.alts.add_all(pool)
+                       end
+               end
+               for p in prods do
+                       self.prods.remove(p)
+                       self.ast_prods.add(p)
+               end
+       end
+
+       # Compute a LR automaton
+       fun lr0: LRAutomaton
+       do
+               analyse
+
+               var start = new Production("_start")
+               start.accept = true
+               var eof = new Token("Eof")
+               tokens.add(eof)
+               start.new_alt("Start", self.prods.first, eof)
+               prods.add(start)
+               var first = new LRState("Start")
+               first.number = 0
+               for i in start.start_state do first.add(i)
+
+               var automaton = new LRAutomaton(self)
+
+               var todo = new List[LRState]
+               todo.add first
+               var seen = new HashSet[LRState]
+               seen.add first
+
+               while not todo.is_empty do
+                       var state = todo.shift
+
+                       #print state
+                       automaton.states.add(state)
+                       state.analysis
+
+                       var nexts = new HashMap[Element, LRState]
+                       for i in state.items do
+                               var e = i.next
+                               if e == null then continue
+                               if nexts.has_key(e) then
+                                       nexts[e].add(i.avance)
+                               else
+                                       var name
+                                       if state == automaton.states.first then
+                                               name = e.to_s
+                                       else
+                                               name = "{state.name} {e}"
+                                       end
+                                       var next = new LRState(name)
+                                       nexts[e] = next
+                                       next.add(i.avance)
+                               end
+                       end
+
+                       for e, next in nexts do
+
+                               #print "#states: {seen.length}"
+
+                               var new_state = true
+                               for n in seen do
+                                       if n == next then
+                                               for i in next.items do
+                                                       if n.add(i) then n.extends(i)
+                                               end
+                                               next = n
+                                               new_state = false
+                                               break
+                                       end
+                               end
+
+                               if new_state then
+                                       next.number = seen.length
+                                       assert not seen.has(next)
+                                       seen.add(next)
+                                       todo.add(next)
+                               end
+
+                               var t = new LRTransition(state, next, e)
+                               state.outs.add t
+                               next.ins.add t
+                       end
+               end
+               return automaton
+       end
+
+       # Compute `nullables`, `firsts` and `afters` of productions
+       fun analyse
+       do
+               loop
+                       var changed = false
+                       for p in prods do
+                               if p.is_nullable then continue
+                               for a in p.alts do
+                                       var nullabl = true
+                                       for e in a.elems do
+                                               if e isa Token then
+                                                       nullabl = false
+                                                       break
+                                               else if e isa Production then
+                                                       if not e.is_nullable then nullabl = false
+                                                       break
+                                               else
+                                                       abort
+                                               end
+                                       end
+                                       if nullabl then
+                                               p.is_nullable = true
+                                               changed = true
+                                       end
+                               end
+                       end
+                       if not changed then break
+               end
+
+               loop
+                       var changed = false
+                       for p in prods do
+                               var fs = p.firsts
+                               for a in p.alts do
+                                       for e in a.elems do
+                                               if e isa Token then
+                                                       if try_add(fs, e) then changed = true
+                                                       break
+                                               else if e isa Production then
+                                                       for t in e.firsts do
+                                                               if try_add(fs, t) then changed = true
+                                                       end
+                                                       if not e.is_nullable then break
+                                               else
+                                                       abort
+                                               end
+                                       end
+                               end
+                       end
+                       if not changed then break
+               end
+
+               loop
+                       var changed = false
+                       for p1 in prods do
+                               for a in p1.alts do
+                                       var p0: nullable Production = null
+                                       for e in a.elems do
+                                               var p = p0
+                                               if e isa Production then p0 = e else p0 = null
+                                               if p == null then continue
+
+                                               var afs = p.afters
+
+                                               if e isa Token then
+                                                       if try_add(afs, e) then changed = true
+                                               else if e isa Production then
+                                                       for t in e.firsts do
+                                                               if try_add(afs, t) then changed = true
+                                                       end
+                                                       if e.is_nullable then
+                                                               for t in e.afters do
+                                                                       if try_add(afs, t) then changed = true
+                                                               end
+                                                       end
+                                               else
+                                                       abort
+                                               end
+                                       end
+                                       if p0 != null then
+                                               var afs = p0.afters
+                                               for t in p1.afters do
+                                                       if try_add(afs, t) then changed = true
+                                               end
+                                       end
+                               end
+                       end
+                       if not changed then break
+               end
+       end
+
+       # used by `analyse`
+       private fun try_add(set: Set[Token], t: Token): Bool
+       do
+               var res = not set.has(t)
+               if res then set.add(t)
+               return res
+       end
+
+end
+
+# A production of a grammar
+class Production
+       super Element
+       # The alternative of the production
+       var alts = new Array[Alternative]
+
+       # Additionnal alternatives in the AST
+       var ast_alts = new Array[Alternative]
+
+       # Is self the accept production
+       var accept = false
+
+       # Is self transformed to a other production for the AST
+       # FIXME: cleaup AST
+       var spe: nullable Production writable = null
+
+       # Is self contains only a single alternative (then no need for a abstract production class in the AST)
+       # FIXME cleanup AST
+       var altone writable = false
+
+       # The cname of the class in the AST
+       # FIXME: cleanup AST
+       redef fun acname do
+               if spe != null then return spe.acname
+               return super
+       end
+
+       # Is the production nullable
+       var is_nullable = false
+       # The first tokens of the production
+       var firsts = new HashSet[Token]
+       # The tokens that may follows the production (as in SLR)
+       var afters = new HashSet[Token]
+
+
+       # Crate a new empty alternative
+       fun new_alt0(name: String): Alternative
+       do
+               var a = new Alternative(self, name, new Array[Element])
+               alts.add a
+               return a
+       end
+
+       # Crate a new alternative with some elements
+       fun new_alt(name: String, elems: Element...): Alternative
+       do
+               var a = new Alternative(self, name, elems)
+               alts.add a
+               return a
+       end
+
+       # Crate a new alternative with some elements
+       fun new_alt2(name: String, elems: Array[Element]): Alternative
+       do
+               var a = new Alternative(self, name, elems)
+               alts.add a
+               return a
+       end
+
+       # Return a set of items for the production
+       fun start_state: Array[Item]
+       do
+               var res = new Array[Item]
+               for a in alts do
+                       res.add new Item(a, 0)
+               end
+               return res
+       end
+
+       # States in the LR automaton that has a outgoing transition on self
+       var gotos = new ArraySet[LRState]
+end
+
+# An alternative of a production
+class Alternative
+       # The production
+       var prod: Production
+
+       # The name of the alternative
+       var name: String writable
+
+       # The elements of the alternative
+       var elems: Array[Element]
+
+       # The name of the elements
+       var elems_names = new Array[nullable String]
+
+       # Return a name for a given element (or a number if unamed)
+       fun elemname(i: Int): String
+       do
+               if i >= elems_names.length then return "{i}"
+               var n = elems_names[i]
+               if n == null then return "{i}"
+               return n
+       end
+
+       redef fun to_s do return "{prod.name}::{name}={elems.join(" ")}"
+       
+       # A mangled name
+       fun cname: String do
+               return "N{name.to_cmangle}"
+       end
+
+       # The code for the reduction
+       var codes: nullable Array[Code] writable = null
+
+       # Is the alternative transformed (ie not in the AST)
+       var trans writable = false
+
+       # Imitialize codes with the elements
+       fun make_codes
+       do
+               if codes != null then return
+               var codes = new Array[Code]
+               self.codes = codes
+               for e in elems do
+                       codes.add(new CodePop)
+               end
+               codes.add(new CodeNew(self))
+       end
+end
+
+# A step in the construction of the AST. used to modelize transformations
+interface Code
+end
+# Get a element from the stack
+class CodePop
+       super Code
+       redef fun to_s do return "pop"
+end
+# Allocate a new AST node for an alternative using the correct number of poped elements
+class CodeNew
+       super Code
+       var alt: Alternative
+       redef fun to_s do return "New {alt.name}/{alt.elems.length}"
+end
+# Get null
+class CodeNull
+       super Code
+       redef fun to_s do return "null"
+end
+
+# Elements of an alternative.
+# Either a `Production` or a `Token`
+abstract class Element
+       # The name of the element
+       var name: String
+       redef fun to_s do return name
+
+       private var acname_cache: nullable String = null
+
+       # The mangled name of the element
+       fun cname: String do return "N{name.to_cmangle}"
+
+       # the name of the class in the AST
+       fun acname: String do
+               var res = acname_cache
+               if res == null then
+                       res = "N{to_s.to_cmangle}"
+                       acname_cache = res
+               end
+               return res
+       end
+       fun acname=(s: String) do acname_cache = s
+end
+
+# A terminal element
+class Token
+       super Element
+       # States of the LR automatio that shift on self
+       var shifts = new ArraySet[LRState]
+       # States of the LR automatio that reduce on self in the lookahead(1)
+       var reduces = new ArraySet[LRState]
+end
+
+#
+
+# A LR automaton
+class LRAutomaton
+       # The grammar of the automaton
+       var grammar: Gram
+
+       # The set of states
+       var states = new Array[LRState]
+
+       # Dump of the automaton
+       fun pretty: String
+       do
+               var res = new Array[String]
+               res.add "* LRAutomaton: {states.length} states\n"
+               for s in states do
+                       res.add "s{s.number} {s.name}\n"
+                       res.add "\tCORE\n"
+                       for i in s.core do
+                               res.add "\t\t{i}\n"
+                       end
+                       res.add "\tOTHER ITEMS\n"
+                       for i in s.items do
+                               if s.core.has(i) then continue
+                               res.add "\t\t{i}\n"
+                       end
+                       res.add "\tTRANSITIONS {s.outs.length}\n"
+                       for t in s.outs do
+                               res.add "\t\t{t.elem} |-> s{t.to.number}\n"
+                       end
+                       res.add "\tACTIONS\n"
+                       if s.is_lr0 then
+                               res.add "\t\tSTATE LR0\n"
+                       else
+                               res.add "\t\tSTATE LALR\n"
+                               for t, a in s.guarded_reduce do
+                                       if a.length > 1 then
+                                               res.add "\t\t/!\\ REDUCE/REDUCE CONFLICT\n"
+                                               break
+                                       else if s.shifts.has(t) then
+                                               res.add "\t\t/!\\ SHIFT/REDUCE CONFLICT\n"
+                                               break
+                                       end
+                               end
+                       end
+                       if not s.shifts.is_empty then
+                               res.add "\t\tSHIFT {s.shifts.join(" ")}\n"
+                       end
+                       for r in s.reduces do
+                               res.add "\t\tREDUCE {r}\n"
+                       end
+               end
+               return res.to_s
+       end
+
+       # Generate a graphviz file of the automaton
+       fun to_dot(path: String)
+       do
+               var f = new OFStream.open(path)
+               f.write("digraph g \{\n")
+               f.write("rankdir=LR;\n")
+               f.write("node[shape=Mrecord,height=0];\n")
+
+               for s in states do
+                       f.write "s{s.number} [label=\"{s.number} {s.name.escape_to_dot}|"
+                       for i in s.core do
+                               f.write "{i.to_s.escape_to_dot}\\l"
+                       end
+                       f.write("|")
+                       for i in s.items do
+                               if s.core.has(i) then continue
+                               f.write "{i.to_s.escape_to_dot}\\l"
+                       end
+                       f.write "\""
+                       if not s.is_lr0 then
+                               var conflict = false
+                               for t, a in s.guarded_reduce do
+                                       if a.length > 1 then
+                                               f.write ",color=red"
+                                               conflict = true
+                                               break
+                                       else if s.shifts.has(t) then
+                                               f.write ",color=orange"
+                                               conflict = true
+                                               break
+                                       end
+                               end
+                               if not conflict then
+                                       f.write ",color=blue"
+                               end
+                       end
+                       f.write "];\n"
+                       for t in s.outs do
+                               f.write "s{s.number} -> s{t.to.number} [label=\"{t.elem.to_s.escape_to_dot}\"];\n"
+                       end
+               end
+               f.write("\}\n")
+               f.close
+       end
+
+       # Generate the parser of the automaton
+       fun gen_to_nit(filepath: String)
+       do
+               var gen = new Generator
+               gen.gen_to_nit(self)
+               var f = new OFStream.open(filepath)
+               for s in gen.out do
+                       f.write(s)
+                       f.write("\n")
+               end
+               f.close
+       end
+end
+
+redef class String
+       # escape string used in labels for graphviz
+       fun escape_to_dot: String
+       do
+               return escape_more_to_c("|\{\}")
+       end
+end
+
+private class Generator
+       var out = new Array[String]
+       fun add(s: String) do out.add(s)
+       fun gen_to_nit(autom: LRAutomaton)
+       do
+               var states = autom.states
+               var gram = autom.grammar
+
+               add "# Parser generated by nitcc"
+               add "import nitcc_runtime"
+
+               add "class MyParser"
+               add "\tsuper Parser"
+               add "\tredef fun start_state do return state_{states.first.cname}"
+               add "end"
+               
+               add "redef class Object"
+               for s in states do
+                       add "\tprivate fun state_{s.cname}: LRState{s.cname} do return once new LRState{s.cname}"
+               end
+               for p in gram.prods do
+                       add "\tprivate fun goto_{p.cname}: Goto_{p.cname} do return once new Goto_{p.cname}"
+               end
+               add "end"
+
+               add "redef class NToken"
+               for s in states do
+                       if not s.need_guard then continue
+                       add "\t# guarded action for state {s.name}"
+                       add "\t# {s.shifts.length} shift(s) and {s.reduces.length} reduce(s)"
+                       add "\tprivate fun action_s{s.cname}(parser: Parser) do"
+                       if s.reduces.length != 1 then
+                               add "\t\tparser.parse_error"
+                       else
+                               gen_reduce_to_nit(s.reduces.first)
+                       end
+                       add "\tend"
+               end
+               add "end"
+
+               for t in gram.tokens do
+                       if t.name == "Eof" then
+                               add "redef class {t.cname}"
+                       else
+                               add "class {t.cname}"
+                       end
+                       add "\tsuper NToken"
+                       for s in t.shifts do
+                               if not s.need_guard then continue
+                               add "\tredef fun action_s{s.cname}(parser) do"
+                               gen_shift_to_nit(s, t)
+                               add "\tend"
+                       end
+                       for s in t.reduces do
+                               if not s.need_guard then continue
+                               if s.reduces.length <= 1 then continue
+                               add "\tredef fun action_s{s.cname}(parser) do"
+                               gen_reduce_to_nit(s.guarded_reduce[t].first.alt)
+                               add "\tend"
+                       end
+                       add "\tredef fun node_name do return \"{t.name.escape_to_nit}\""
+                       add "end"
+               end
+
+               add "redef class LRGoto"
+               for s in states do
+                       if s.gotos.length <= 1 then continue
+                       add "\tprivate fun goto_s{s.cname}(parser: Parser) do abort"
+               end
+               add "end"
+
+               for p in gram.prods do
+                       add "class Goto_{p.cname}"
+                       add "\tsuper LRGoto"
+                       for s in p.gotos do
+                               if s.gotos.length <= 1 then continue
+                               add "\tredef fun goto_s{s.cname}(parser) do"
+                               gen_goto_to_nit(s, p)
+                               add "\tend"
+                       end
+                       add "end"
+               end
+
+               var ps = gram.prods.to_a
+               ps.add_all(gram.ast_prods)
+               for p in ps do
+                       if p.spe == null and not p.altone then
+                               if p.name.has_suffix("?") or p.name.has_suffix("+") then continue
+                               add "class {p.acname}"
+                               add "\tsuper NProd"
+                               add "\tredef fun node_name do return \"{p.name.escape_to_nit}\""
+                               add "end"
+                       end
+
+                       var als = p.alts.to_a
+                       als.add_all(p.ast_alts)
+                       for a in als do
+                               if a.trans then continue
+                               add "class {a.cname}"
+                               if p.altone then
+                                       add "\tsuper NProd"
+                               else
+                                       add "\tsuper {p.acname}"
+                               end
+                               add "\tredef fun node_name do return \"{a.name.escape_to_nit}\""
+                               var initarg = new Array[String]
+                               for i in [0..a.elems.length[ do
+                                       add "\tvar n_{a.elemname(i)}: {a.elems[i].acname}"
+                                       initarg.add("n_{a.elemname(i)}: {a.elems[i].acname}")
+                               end
+                               if initarg.is_empty then
+                                       add "\tinit do end"
+                               else
+                                       add "\tinit({initarg.join(", ")}) do"
+                                       for i in [0..a.elems.length[ do
+                                               add "\t\tself.n_{a.elemname(i)} = n_{a.elemname(i)}"
+                                       end
+                                       add "\tend"
+                               end
+                               add "\tredef fun number_of_children do return {a.elems.length}"
+                               add "\tredef fun child(i) do"
+                               for i in [0..a.elems.length[ do
+                                       add "\t\tif i == {i} then return n_{a.elemname(i)}"
+                               end
+                               add "\t\tabort"
+                               add "\tend"
+                               add "end"
+                       end
+               end
+
+               for s in states do
+                       add "# State {s.name}"
+                       add "private class LRState{s.cname}"
+                       add "\tsuper LRState"
+
+                       add "\tredef fun to_s do return \"{s.name.escape_to_nit}\""
+                       
+                       var err = new Array[String]
+                       for t in s.outs do
+                               var e = t.elem
+                               if e isa Production then err.add e.name
+                       end
+                       if err.is_empty then for t in s.outs do
+                               var e = t.elem
+                               if e isa Token then err.add e.name
+                       end
+
+                       add "\tredef fun error_msg do return \"{err.join(", ").escape_to_nit}\""
+
+                       add "\tredef fun action(parser) do"
+                       if s.need_guard then
+                               add "\t\tparser.peek_token.action_s{s.cname}(parser)"
+                       else if s.reduces.length == 1 then
+                               gen_reduce_to_nit(s.reduces.first)
+                       else
+                               abort
+                       end
+                       add "\tend"
+                       
+                       if not s.gotos.is_empty then
+                               add "\tredef fun goto(parser, goto) do"
+                               if s.gotos.length > 1 then
+                                       add "\t\tgoto.goto_s{s.cname}(parser)"
+                               else
+                                       gen_goto_to_nit(s, s.gotos.first)
+                               end
+                               add "\tend"
+                       end
+
+                       add "end"
+               end
+
+
+       end
+
+       fun gen_shift_to_nit(s: LRState, t: Token)
+       do
+               var dest = s.trans(t)
+               add "\t\tparser.shift(state_{dest.cname})"
+
+       end
+
+       fun gen_goto_to_nit(s: LRState, p: Production)
+       do
+               var dest = s.trans(p)
+               add "\t\tparser.push(state_{dest.cname})"
+       end
+
+       fun gen_reduce_to_nit(alt: Alternative)
+       do
+               add "\t\t# REDUCE {alt}"
+               var i = alt.elems.length - 1
+               for e in alt.elems.to_a.reversed do
+                       add "\t\tvar n{i} = parser.pop.as({e.acname})"
+                       i -= 1
+               end
+
+               if alt.name.has_suffix("+_more") then
+                       add "\t\tvar prod = n0"
+                       add "\t\tn0.items.add(n1)"
+               else if alt.name.has_suffix("+_one") then
+                       add "\t\tvar prod = new {alt.prod.acname}"
+                       add "\t\tprod.items.add(n0)"
+               else
+                       alt.make_codes
+                       var cpt = 0
+                       i = 0
+                       var st = new Array[String]
+                       for c in alt.codes.as(not null) do
+                               if c isa CodePop then
+                                       st.add "n{i}"
+                                       i += 1
+                               else if c isa CodeNull then
+                                       st.add "null"
+                               else if c isa CodeNew then
+                                       var calt = c.alt
+                                       cpt += 1
+                                       var from = st.length - calt.elems.length
+                                       var args = new List[String]
+                                       for j in [from..st.length[ do
+                                               args.unshift(st.pop)
+                                       end
+
+                                       if args.is_empty then
+                                               add "\t\tvar p{cpt} = new {calt.cname}"
+                                       else
+                                               add "\t\tvar p{cpt} = new {calt.cname}({args.join(", ")})"
+                                       end
+                                       #var x = 0
+                                       #for j in [from..st.length[ do
+                                               #if st[j] == "null" then continue
+                                               #add "\t\tp{cpt}.n_{calt.elemname(x)} = {st[j]}"
+                                               #x += 1
+                                       #end
+                                       st.add("p{cpt}")
+                               end
+                       end
+                       assert st.length == 1
+                       add "\t\tvar prod = {st.first}"
+               end
+
+               add "\t\tparser.node_stack.push prod"
+               if alt.prod.accept then
+                       add "\t\tparser.stop = true"
+               else
+                       add "\t\tparser.goto(goto_{alt.prod.cname})"
+               end
+       end
+end
+
+# A state in a LR automaton
+class LRState
+       # name of the automaton (short part from the start)
+       var name: String
+
+       # malglen name
+       fun cname: String do return name.to_cmangle
+
+       # number
+       var number: Int = -1
+
+       # Set of all items
+       var items = new HashSet[Item]
+
+       # Set of items only in the core
+       var core = new HashSet[Item]
+
+       # Outgoing transitions
+       var ins = new Array[LRTransition]
+
+       # Ingoing transitions
+       var outs = new Array[LRTransition]
+
+       # trans function
+       fun trans(e: Element): nullable LRState
+       do
+               for t in outs do if t.elem == e then return t.to
+               return null
+       end
+
+       redef fun ==(o) do return o isa LRState and core == o.core
+       redef fun hash do return items.length
+
+       redef fun to_s do return items.join(" ; ")
+
+       # Add and item in the core
+       fun add(i: Item): Bool
+       do
+               #if items.has(i) then return
+
+               #print "add {i} in {inspect}={self}"
+               var found = false
+               for i2 in items do
+                       if i.alt == i2.alt and i.pos == i2.pos then
+                               if i2.future.has_all(i.future) then return false
+                               i2.future.add_all(i.future)
+                               found = true
+
+                               break
+                       end
+               end
+               if not found then
+                       items.add(i)
+                       if i.pos > 0 or i.alt.prod.accept then core.add(i)
+               end
+               return true
+       end
+
+       # Recusively extends item outside the core
+       fun extends(i: Item)
+       do
+               var e = i.next
+               if e == null then return
+               if not e isa Production then return
+               var la = i.lookahead
+               for i2 in e.start_state do
+                       i2.future.add_all(la)
+                       if add(i2) then extends(i2)
+               end
+       end
+
+       # Set of all reductions
+       var reduces = new ArraySet[Alternative]
+       # Set of all shifts
+       var shifts = new ArraySet[Token]
+       # Set of all goto
+       var gotos = new ArraySet[Production]
+       # Reduction guarded by tokens
+       var guarded_reduce = new HashMap[Token, Array[Item]]
+       # Shitfs guarded by tokens
+       var guarded_shift = new HashMap[Token, Array[Item]]
+
+       # Does the state need a guard to perform an action?
+       fun need_guard: Bool do return not shifts.is_empty or reduces.length > 1
+
+       # Is the state LR0
+       fun is_lr0: Bool do return reduces.length <= 1 and shifts.is_empty or reduces.is_empty
+
+       # compute guards and conflicts
+       fun analysis
+       do
+               for i in items.to_a do
+                       extends(i)
+               end
+
+               for i in items do
+                       var n = i.next
+                       if n == null then
+                               reduces.add(i.alt)
+                               #for t in i.alt.prod.afters do
+                               for t in i.future do
+                                       t.reduces.add(self)
+                                       if guarded_reduce.has_key(t) then
+                                               guarded_reduce[t].add(i)
+                                       else
+                                               guarded_reduce[t] = [i]
+                                       end
+                               end
+                       else if n isa Token then
+                               shifts.add(n)
+                               n.shifts.add(self)
+                               if guarded_shift.has_key(n) then
+                                       guarded_shift[n].add(i)
+                               else
+                                       guarded_shift[n] = [i]
+                               end
+                       else if n isa Production then
+                               gotos.add(n)
+                               n.gotos.add(self)
+                       else
+                               abort
+                       end
+               end
+               for t, a in guarded_reduce do
+                       if a.length > 1 then
+                               print "REDUCE/REDUCE Conflict on state {self.number} {self.name} for token {t}:"
+                               for i in a do print "\t{i}"
+                       else if guarded_shift.has_key(t) then
+                               print "SHIFT/REDUCE Conflict on state {self.number} {self.name} for token {t}:"
+                               for i in a do print "\t{i}"
+                               for i in guarded_shift[t] do print "\t{i}"
+                       end
+               end
+       end
+end
+
+# A transition in a LR automaton
+class LRTransition
+       # The origin state
+       var from: LRState
+       # The testination state
+       var to: LRState
+       # The element labeling the transition
+       var elem: Element
+end
+
+# A alternative with a cursor (dot) and possibly a future
+class Item
+       # The alternative
+       var alt: Alternative
+       # The dot index (0 means before the first element)
+       var pos: Int
+       # The possible future
+       var future = new ArraySet[Token]
+
+       redef fun ==(o) do return o isa Item and alt == o.alt and pos == o.pos
+       redef fun hash do return alt.hash + pos
+
+       redef fun to_s
+       do
+               var b = new Buffer
+               b.append("{alt.prod.name}::{alt.name}=")
+               for i in [0..alt.elems.length[
+               do
+                       if pos == i then b.append(".") else b.append(" ")
+                       b.append(alt.elems[i].to_s)
+               end
+               if pos == alt.elems.length then b.append(".")
+               if not future.is_empty then
+                       b.append("/\{")
+                       b.append(future.join(" "))
+                       b.append("\}")
+               end
+               return b.to_s
+       end
+
+       # The element thatr follow the dot, null if the fdot is at the end
+       fun next: nullable Element
+       do
+               if pos >= alt.elems.length then return null
+               return alt.elems[pos]
+       end
+
+       # SLR loohahead
+       fun lookahead: Set[Token]
+       do
+               var res = new HashSet[Token]
+               var p = pos + 1
+               while p < alt.elems.length do
+                       var e = alt.elems[p]
+                       if e isa Token then
+                               res.add(e)
+                               break
+                       else if e isa Production then
+                               res.add_all(e.firsts)
+                               if not e.is_nullable then break
+                       end
+                       p += 1
+               end
+               if p >= alt.elems.length then
+                       res.add_all(future)
+               end
+               return res
+       end
+
+       # The item that advanced once
+       fun avance: Item
+       do
+               var res = new Item(alt, pos+1)
+               res.future.add_all(future)
+               return res
+       end
+end
diff --git a/contrib/nitcc/mk b/contrib/nitcc/mk
new file mode 100755 (executable)
index 0000000..5c7a0cf
--- /dev/null
@@ -0,0 +1,33 @@
+set -e
+set -x
+
+NITC=../../bin/nitg
+
+echo "**************************"
+
+$NITC nitcc_parser_gen.nit -v
+./nitcc_parser_gen
+
+echo "**************************"
+
+$NITC nitcc.nit -v
+cp nitcc nitcc0
+
+echo "**************************"
+
+./nitcc nitcc.sablecc
+$NITC nitcc.nit
+cp nitcc nitcc1
+
+echo "**************************"
+
+./nitcc nitcc.sablecc
+$NITC nitcc.nit
+
+echo "**************************"
+
+cd examples
+../nitcc calc.sablecc
+../$NITC calc.nit -v -I ..
+./calc -e "1+2*3-40/5+9------1"
+
diff --git a/contrib/nitcc/nitcc.nit b/contrib/nitcc/nitcc.nit
new file mode 100644 (file)
index 0000000..3d172ef
--- /dev/null
@@ -0,0 +1,147 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# nitcc, a parser and lexer generator for Nit
+module nitcc
+
+import nitcc_semantic
+
+# Load the grammar file
+
+if args.is_empty then
+       print "usage: nitcc <file> | -"
+       exit 1
+end
+var fi = args.first
+
+var text
+if fi != "-" then
+       var f = new IFStream.open(fi)
+       text = f.read_all
+       f.close
+else
+       text = stdin.read_all
+end
+
+# Parse the grammar file
+
+var l = new MyLexer(text)
+var ts = l.lex
+
+var p = new MyParser
+p.tokens.add_all ts
+
+var node = p.parse
+
+if not node isa NProd then
+       print node
+       exit 1
+       abort
+end
+
+var name = node.children.first.as(Ngrammar).children[1].as(Nid).text
+
+print "Grammar {name} (see {name}.gram.dot))"
+node.to_dot("{name}.gram.dot")
+
+# Semantic analysis
+
+var v2 = new CollectNameVisitor
+v2.start(node)
+var gram = v2.gram
+
+if gram.prods.is_empty then
+       print "Error: grammar with no production"
+       exit(1)
+end
+
+# Generate the LR automaton
+
+var lr = gram.lr0
+
+var conflitcs = new ArraySet[Production]
+for s in lr.states do for t, a in s.guarded_reduce do if a.length > 1 or s.guarded_shift.has_key(t) then
+       for i in a do conflitcs.add(i.alt.prod)
+end
+
+if not conflitcs.is_empty then
+       print "Error: there is conflicts"
+end
+
+if false then loop
+if conflitcs.is_empty then break
+print "Inline {conflitcs.join(" ")}"
+gram.inline(conflitcs)
+lr=gram.lr0
+end
+
+# Output concrete grammar and LR automaton
+
+var nbalts = 0
+for prod in gram.prods do nbalts += prod.alts.length
+print "Concrete grammar: {gram.prods.length} productions, {nbalts} alternatives (see {name}.concrete_grammar.txt)"
+
+var pretty = gram.pretty
+var f = new OFStream.open("{name}.concrete_grammar.txt")
+f.write "// Concrete grammar of {name}\n"
+f.write pretty
+f.close
+
+print "LR automaton: {lr.states.length} states (see {name}.lr.dot and {name}.lr.txt)"
+lr.to_dot("{name}.lr.dot")
+pretty = lr.pretty
+f = new OFStream.open("{name}.lr.txt")
+f.write "// LR automaton of {name}\n"
+f.write pretty
+f.close
+
+# NFA and DFA
+
+var nfa = v2.nfa
+print "NFA automaton: {nfa.states.length} states (see {name}.nfa.dot)"
+nfa.to_dot("{name}.nfa.dot")
+
+var dfa = nfa.to_dfa
+if dfa.tags.has_key(dfa.start) then
+       print "ERROR: Empty tokens {dfa.tags[dfa.start].join(" ")}"
+end
+dfa.solve_token_inclusion
+for s, tks in dfa.tags do
+       if tks.length <= 1 then continue
+       print "ERROR: Conflicting tokens: {tks.join(" ")}"
+end
+print "DFA automaton: {dfa.states.length} states (see {name}.dfa.dot)"
+dfa.to_dot("{name}.dfa.dot")
+
+# Generate Nit code
+
+print "Generate {name}_lexer.nit {name}_parser.nit {name}_test_parser.nit"
+dfa.gen_to_nit("{name}_lexer.nit", "{name}_parser")
+lr.gen_to_nit("{name}_parser.nit")
+
+f = new OFStream.open("{name}_test_parser.nit")
+f.write """# Generated by nitcc for the language {{{name}}}
+import nitcc_runtime
+import {{{name}}}_lexer
+import {{{name}}}_parser
+class MyTest
+       super TestParser
+       redef fun name do return \"{{{name}}}\"
+       redef fun new_lexer(text) do return new MyLexer(text)
+       redef fun new_parser do return new MyParser
+end
+var t = new MyTest
+t.main
+"""
+f.close
diff --git a/contrib/nitcc/nitcc.sablecc b/contrib/nitcc/nitcc.sablecc
new file mode 100644 (file)
index 0000000..9dc5579
--- /dev/null
@@ -0,0 +1,95 @@
+// The grammar of nitcc (subset of sablecc4)
+Grammar nitcc;
+
+Lexer
+
+// Identifier, used for production, expressions, alternatives, etc.
+id = ('a'..'z')('a'..'z'|'0'..'9'|'_')*;
+
+// A printable character (inside strings)
+ch = ' ' .. '~';
+
+// Literal strings
+str = '\'' (ch-'\\'-'\''|'\\'ch)* '\'';
+
+// A char by decimal ascii
+ch_dec = '#' ('0'..'9')+ ;
+
+// A single-line comment
+comment = '//' ch* '\n'?;
+
+any = '\t'..'~';
+not_star = any - '*';
+not_star_not_slash = not_star - '/';
+
+ccomment = '/*' not_star* ('*' (not_star_not_slash not_star*)?)* '*/';
+
+unknown_keyword = 'A..Z'('A'..'Z'|'a'..'z'|'0'..'9'|'_')*;
+
+// Igndored stufs
+blank = '\n' | '\t' | ' ' | comment | ccomment;
+
+Parser
+
+Ignored blank;
+
+grammar = 'Grammar' id ';' lexer_part? parser_part? reject?;
+
+reject = 'XXX' unknown_keyword ';';
+
+lexer_part = 'Lexer' expr*;
+
+expr = id '=' re ';';
+
+// No priority (yet) so just decompose
+re =
+       {alter:} re '|' re1 |
+       re1 ;
+
+re1 {-> re} =
+       {minus:} re1 '-' re2 |
+       re2 ;
+
+re2 {-> re} =
+       {conc:} re2 re3 |
+       re3 ;
+
+re3 {-> re} =
+       {ques:} re3 '?' |
+       {star:} re3 '*' |
+       {plus:} re3 '+' |
+       {id:} id |
+       {str:} str |
+       {par:} '(' re ')' |
+       {class:} str '.' '.' str |
+       {any:} 'Any' |
+       {ch_dec:} ch_dec ;
+
+
+parser_part = 'Parser' ign? prod*;
+
+ign = 'Ignored' id ';' ;
+
+prod = id ptrans? '=' alts ';';
+
+ptrans = '{' '->' id '}';
+atrans = '{' '->' id '}';
+
+alts =
+       {more:} alts '|' alt |
+       {one:} alt ;
+
+alt = altid? nelem* atrans?;
+
+altid = '{' id ':' '}' | '{' id '}';
+
+nelem = elem | elemid elem;
+
+elemid = '[' id ':' ']' | '[' id ']' ':';
+
+elem =
+       {id:} id |
+       {str:} str |
+       {star:} elem '*' |
+       {ques:} elem '?' |
+       {plus:} elem '+' ;
diff --git a/contrib/nitcc/nitcc_lexer0.nit b/contrib/nitcc/nitcc_lexer0.nit
new file mode 100644 (file)
index 0000000..50d590e
--- /dev/null
@@ -0,0 +1,163 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Ad-hoc hand-writen lexer for nitcc
+# This avoid to commit (and relyon ) a generated lexer
+#
+module nitcc_lexer0
+
+# Required for the tokens definitions
+import nitcc_parser
+
+# Hand-writen lexer of nitcc
+# Used only for the boostrap of the tool.
+class MyLexer
+       var text: String
+
+       var iter: Iterator[Char] = "".iterator
+       var pos = 0
+
+       var tokens = new Array[NToken]
+
+       fun lex: Array[NToken]
+       do
+               iter = text.iterator
+               while iter.is_ok do
+                       trim
+                       if not iter.is_ok then break
+                       var c = iter.item
+                       iter.next
+                       pos += 1
+                       if c == '*' then
+                               tokens.add new Nstar
+                       else if c == '?' then
+                               tokens.add new Nques
+                       else if c == '+' then
+                               tokens.add new Nplus
+                       else if c == '-' then
+                               if iter.item == '>' then
+                                       iter.next
+                                       tokens.add new Narrow
+                               else
+                                       tokens.add new Nminus
+                               end
+                       else if c == '(' then
+                               tokens.add new Nopar
+                       else if c == ')' then
+                               tokens.add new Ncpar
+                       else if c == '{' then
+                               tokens.add new Nocur
+                       else if c == '}' then
+                               tokens.add new Nccur
+                       else if c == '|' then
+                               tokens.add new Npipe
+                       else if c == ':' then
+                               tokens.add new Ncolo
+                       else if c == ';' then
+                               tokens.add new Nsemi
+                       else if c == '.' then
+                               tokens.add new Ndot
+                       else if c == '=' then
+                               tokens.add new Neq
+                       else if c == '\'' then
+                               str
+                       else if c >= 'a' and c <= 'z' then
+                               id(c)
+                       else if c >= 'A' and c <= 'Z' then
+                               kw(c)
+                       else if c == '/' and iter.is_ok and iter.item == '/' then
+                               while iter.is_ok and iter.item != '\n' do iter.next
+                       else
+                               error(c)
+                       end
+               end
+               tokens.add new NEof
+               return tokens
+       end
+
+       fun error(c: Char)
+       do
+               print "pos {pos}: Lexer error on '{c}'."
+               abort
+       end
+
+       fun str
+       do
+               var b = new Buffer
+               b.add('\'')
+               while iter.is_ok do
+                       var c = iter.item
+                       iter.next
+                       if c == '\\' then
+                               if not iter.is_ok then
+                                       error(c)
+                               end
+                               b.add(c)
+                               c = iter.item
+                               iter.next
+                       else if c == '\'' then
+                               b.add(c)
+                               var token = new Nstr
+                               token.text = b.to_s
+                               tokens.add token
+                               return
+                       end
+                       b.add c
+               end
+               error('\n')
+               abort
+       end
+
+       fun id(c: Char)
+       do
+               var b = new Buffer
+               b.add c
+               while iter.is_ok do
+                       c = iter.item
+                       if c != '_' and (c<'a' or c >'z') and (c<'0' or c>'9') then
+                               break
+                       end
+                       b.add c
+                       iter.next
+               end
+               var token = new Nid
+               token.text = b.to_s
+               tokens.add token
+       end
+
+       fun kw(c: Char)
+       do
+               var b = new Buffer
+               b.add c
+               while iter.is_ok do
+                       c = iter.item
+                       if c != '_' and (c<'a' or c >'z') and (c<'0' or c>'9') then
+                               break
+                       end
+                       b.add c
+                       iter.next
+               end
+               var token = new Nkw
+               token.text = b.to_s
+               tokens.add token
+       end
+
+       fun trim
+       do
+               while iter.is_ok and iter.item <= ' ' do
+                       iter.next
+                       pos += 1
+               end
+       end
+end
diff --git a/contrib/nitcc/nitcc_parser_gen.nit b/contrib/nitcc/nitcc_parser_gen.nit
new file mode 100644 (file)
index 0000000..0118a4c
--- /dev/null
@@ -0,0 +1,150 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Bootstraping the nitcc parser
+#
+# Instead of commiting a generated parser on each version,
+# this program just generate the nitcc_parser using the API of `grammar`
+#
+# Pros:
+#
+#  - no generated file commited
+#  - easier to modify and bootstrap
+#
+# Cons:
+#
+#  - somewhat dublicate the ful grammar of nitcc
+#  - need an ad-hoc lexer (nitcc_lexer0.nit)
+#
+module nitcc_parser_gen
+
+import grammar
+
+var g = new Gram
+var p_gr = new Production("grammar")
+var p_lex = new Production("lexer")
+var p_exprs = new Production("exprs")
+var p_expr = new Production("expression")
+var p_re = new Production("re")
+var p_re1 = new Production("re1")
+var p_re2 = new Production("re2")
+var p_re3 = new Production("re3")
+var p_par = new Production("parser")
+var p_ign = new Production("ignored")
+var p_prods = new Production("prods")
+var p_prod = new Production("production")
+var p_ptrans_o = new Production("ptrans_o")
+var p_alts = new Production("alts")
+var p_alt = new Production("alternative")
+var p_altid_o = new Production("altid_o")
+var p_altid = new Production("altident")
+var p_elems = new Production("elems")
+var p_elem = new Production("elem")
+g.prods.add_all([p_gr, p_re, p_re1, p_re2, p_re3, p_lex, p_exprs, p_expr, p_par, p_ign, p_prods, p_prod, p_ptrans_o, p_alts, p_alt, p_altid_o, p_altid, p_elems, p_elem])
+g.prods.add(new Production("atrans"))
+g.prods.add(new Production("elemid"))
+g.prods.add(new Production("nelem"))
+
+var t_opar = new Token("opar")
+var t_cpar = new Token("cpar")
+var t_ocur = new Token("ocur")
+var t_ccur = new Token("ccur")
+var t_pipe = new Token("pipe")
+var t_star = new Token("star")
+var t_ques = new Token("ques")
+var t_plus = new Token("plus")
+var t_minus = new Token("minus")
+var t_colo = new Token("colo")
+var t_semi = new Token("semi")
+var t_dot = new Token("dot")
+var t_eq = new Token("eq")
+var t_arrow = new Token("arrow")
+var t_str = new Token("str")
+var t_id = new Token("id")
+var t_kw = new Token("kw")
+var t_any = new Token("any")
+var t_ch_dec = new Token("ch_dec")
+g.tokens.add_all([t_opar, t_cpar, t_ocur, t_ccur, t_pipe, t_star, t_ques, t_plus, t_minus, t_colo, t_semi, t_dot, t_eq, t_arrow, t_str, t_id, t_kw, t_any, t_ch_dec])
+
+p_gr.new_alt("gr", t_kw, t_id, t_semi, p_lex, p_par)
+
+p_lex.new_alt("lex", t_kw, p_exprs)
+
+p_exprs.new_alt("exprs_many", p_exprs, p_expr)
+p_exprs.new_alt0("exprs_none")
+
+p_expr.new_alt("expr", t_id, t_eq, p_re, t_semi)
+
+p_re.new_alt("re_alter", p_re, t_pipe, p_re1)
+p_re.new_alt("re_re2", p_re1)
+
+p_re1.new_alt("re_minus", p_re1, t_minus, p_re2)
+p_re1.new_alt("re_re1", p_re2)
+
+p_re2.new_alt("re_conc", p_re2, p_re3)
+p_re2.new_alt("re_re3", p_re3)
+
+p_re3.new_alt("re_star", p_re3, t_star)
+p_re3.new_alt("re_ques", p_re3, t_ques)
+p_re3.new_alt("re_plus", p_re3, t_plus)
+p_re3.new_alt("re_par", t_opar, p_re, t_cpar)
+p_re3.new_alt("re_str", t_str)
+p_re3.new_alt("re_ch_dec", t_ch_dec)
+p_re3.new_alt("re_class", t_str, t_dot, t_dot, t_str)
+p_re3.new_alt("re_any", t_any)
+p_re3.new_alt("re_id", t_id)
+
+p_par.new_alt("par", t_kw, p_ign, p_prods)
+
+p_ign.new_alt0("ign_none")
+p_ign.new_alt("ign", t_kw, t_id, t_semi)
+
+p_prods.new_alt("prods_many", p_prods, p_prod)
+p_prods.new_alt0("prods_none")
+
+p_prod.new_alt("prod", t_id, p_ptrans_o, t_eq, p_alts, t_semi)
+
+p_ptrans_o.new_alt("ptrans", t_ocur, t_arrow, t_id, t_ccur)
+p_ptrans_o.new_alt0("ptrans_none")
+
+p_alts.new_alt("alts_many", p_alts, t_pipe, p_alt)
+p_alts.new_alt("alts_one", p_alt)
+
+p_alt.new_alt("alt", p_altid_o, p_elems)
+
+p_altid_o.new_alt0("altid_o_none")
+p_altid_o.new_alt("altid_o_one", p_altid)
+
+p_altid.new_alt("altid", t_ocur, t_id, t_colo, t_ccur)
+
+p_elems.new_alt("elems_many", p_elems, p_elem)
+p_elems.new_alt0("elems_none")
+
+p_elem.new_alt("elem_id", t_id)
+p_elem.new_alt("elem_str", t_str)
+p_elem.new_alt("elem_par", t_opar, p_alts, t_cpar)
+p_elem.new_alt("elem_star", p_elem, t_star)
+p_elem.new_alt("elem_ques", p_elem, t_ques)
+p_elem.new_alt("elem_plus", p_elem, t_plus)
+
+var a = g.lr0
+
+print "LR automaton: {a.states.length} states (see nitcc0.lr.dot)"
+a.to_dot("nitcc0.lr.dot")
+
+a.gen_to_nit("nitcc_parser.nit")
+
+var f = new OFStream.open("nitcc_lexer.nit")
+f.write("import nitcc_lexer0\n")
+f.close
diff --git a/contrib/nitcc/nitcc_runtime.nit b/contrib/nitcc/nitcc_runtime.nit
new file mode 100644 (file)
index 0000000..5778641
--- /dev/null
@@ -0,0 +1,543 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Runtime library required by parsers and lexers generated by nitcc
+module nitcc_runtime
+
+# A abstract parser engine generated by nitcc
+abstract class Parser
+       # The list of tokens
+       # FIXME: provide something better, like a lexer?
+       var tokens = new List[NToken]
+
+       # Look at the next token
+       # Used by generated parsers
+       fun peek_token: NToken do return tokens.first
+
+       # Consume the next token
+       # Used by generated parsers
+       fun get_token: NToken do return tokens.shift
+
+       # Consume the next token and shift to the state `dest`.
+       # Used by generated parsers
+       fun shift(dest: LRState)
+       do
+               var t = get_token
+               #print "shift {t} -> {dest}"
+               node_stack.push t
+               state_stack.push state
+               state = dest
+       end
+
+       # After a reduction on `goto` go to the next state
+       # Used by generated parsers
+       fun goto(goto: LRGoto)
+       do
+               #print "reduce from {state} -> {prod}"
+               state.goto(self, goto)
+       end
+
+       # push a new state on the stack of states (
+       # Used by generated parsers
+       fun push(dest: LRState)
+       do
+               #print "push prod {prod} -> {dest}"
+               state_stack.push state
+               state = dest
+       end
+
+       # Pop and return the last node
+       # Also pop (and discard) the associated state
+       # Used by generated parsers
+       fun pop: Node
+       do
+               var res = node_stack.pop
+               state = state_stack.pop
+               return res
+       end
+
+       # Produce a parse error and stop the parsing
+       # Used by generated parsers
+       fun parse_error
+       do
+               var token = peek_token
+               print "* parse error in state {state} on token {token}"
+               print "  expected: {state.error_msg}"
+               print "  node_stack={node_stack.join(", ")}"
+               print "  state_stack={state_stack.join(", ")}"
+               var error: Node
+               if token isa NLexerError then
+                       error = token
+                       token.error_tree.items.add_all(node_stack)
+               else
+                       error = new NParserError
+                       error.position = token.position
+                       error.text = token.text
+                       error.token = token
+                       error.error_tree.items.add_all(node_stack)
+               end
+               node_stack.clear
+               node_stack.add error
+               stop = true
+       end
+
+       # The stating state for parsing
+       # Used by generated parsers
+       protected fun start_state: LRState is abstract
+
+       # The current state
+       # Used by generated parsers
+       var state: LRState
+
+       init
+       do
+               state = start_state
+       end
+
+       # The stack of nodes
+       # Used by generated parsers
+       var node_stack = new Array[Node]
+
+       # The stack of states
+       # Used by generated parsers
+       var state_stack = new Array[LRState]
+
+       # Should the parser stop
+       # Used by generated parsers
+       var stop writable = true
+
+       # Parse a full sequence of tokens and return a complete syntactic tree
+       fun parse: Node
+       do
+               state = start_state
+               state_stack.clear
+               node_stack.clear
+               stop = false
+               while not stop do
+                       #print "* current state {state}"
+                       #print "  tokens={tokens.join(" ")}"
+                       #print "  node_stack={node_stack.join(" ")}"
+                       #print "  state_stack={state_stack.join(" ")}"
+                       state.action(self)
+               end
+               #print "* over"
+               return node_stack.first
+       end
+end
+
+# A state in a parser LR automaton generated by nitcc
+# Used by generated parsers
+abstract class LRState
+       fun action(parser: Parser) is abstract
+       fun goto(parser: Parser, goto: LRGoto) is abstract
+       fun error_msg: String do return "FIXME"
+end
+
+# A concrete production in a parser LR automation generated by nitcc
+# Used by generated parsers
+abstract class LRGoto
+end
+
+###
+
+# A abstract lexer engine generated by nitcc
+abstract class Lexer
+       # The input stream of characters
+       var stream: String
+
+       # The stating state for lexing
+       # Used by generated parsers
+       protected fun start_state: DFAState is abstract
+
+       # Lexize a stream of characters and return a sequence of tokens
+       fun lex: List[NToken]
+       do
+               var res = new List[NToken]
+               var state = start_state
+               var pos = 0
+               var pos_start = 0
+               var pos_end = 0
+               var line = 1
+               var line_start = 1
+               var line_end = 0
+               var col = 1
+               var col_start = 1
+               var col_end = 0
+               var last_state: nullable DFAState = null
+               var text = stream
+               var length = text.length
+               loop
+                       if state.is_accept then
+                               pos_end = pos - 1
+                               line_end = line
+                               col_end = col
+                               last_state = state
+                       end
+                       var c
+                       if pos >= length then
+                               c = '\0'
+                       else
+                               c = text[pos]
+                       end
+                       var next = state.trans(c)
+                       if next == null then
+                               if last_state == null then
+                                       var token = new NLexerError
+                                       var position = new Position(pos_start, pos, line_start, line, col_start, col)
+                                       token.position = position
+                                       token.text = text.substring(pos_start, pos-pos_start+1)
+                                       res.add token
+                                       break
+                               end
+                               var position = new Position(pos_start, pos_end, line_start, line_end, col_start, col_end)
+                               var token = last_state.make_token(position, text.substring(pos_start, pos_end-pos_start+1))
+                               if token != null then res.add(token)
+                               if pos >= length then
+                                       token = new NEof
+                                       position = new Position(pos, pos, line, line, col, col)
+                                       token.position = position
+                                       token.text = ""
+                                       res.add token
+                                       break
+                               end
+                               state = start_state
+                               pos_start = pos_end + 1
+                               pos = pos_start
+                               line_start = line_end
+                               line = line_start
+                               col_start = col_end
+                               col = col_start
+
+                               last_state = null
+                               continue
+                       end
+                       state = next
+                       pos += 1
+                       col += 1
+                       if c == '\n' then
+                               line += 1
+                               col = 1
+                       end
+               end
+               return res
+       end
+end
+
+# A state in a lexer automaton generated by nitcc
+# Used by generated lexers
+interface DFAState
+       fun is_accept: Bool do return false
+       fun trans(c: Char): nullable DFAState do return null
+       fun make_token(position: Position, text: String): nullable NToken is abstract
+end
+
+###
+
+# A abstract visitor on syntactic trees generated by nitcc
+abstract class Visitor
+       # The main entry point to visit a node `n`
+       # Should not be redefined
+       fun enter_visit(n: Node)
+       do
+               visit(n)
+       end
+
+       # The specific implementation of a visit
+       #
+       # Should be redefined by concrete visitors
+       #
+       # Should not be called directly (use `enter_visit` instead)
+       #
+       # By default, the visitor just rescursively visit the children of `n`
+       protected fun visit(n: Node)
+       do
+               n.visit_children(self)
+       end
+end
+
+# Print a node (using to_s) on a line and recustively each children indented (with two spaces)
+class TreePrinterVisitor
+       super Visitor
+       var writer: OStream
+       private var indent = 0
+       init(writer: OStream) do self.writer = writer
+       redef fun visit(n)
+       do
+               for i in [0..indent[ do writer.write("  ")
+               writer.write(n.to_s)
+               writer.write("\n")
+               indent += 1
+               super
+               indent -= 1
+       end
+end
+
+# A position into a input stream
+# Used to give position to tokens
+class Position
+       var pos_start: Int
+       var pos_end: Int
+       var line_start: Int
+       var line_end: Int
+       var col_start: Int
+       var col_end: Int
+       redef fun to_s do return "{line_start}:{col_start}-{line_end}:{col_end}"
+end
+
+# A node of a syntactic tree
+abstract class Node
+       # The name of the node (as used in the grammar file)
+       fun node_name: String do return class_name
+
+       # A point of view on the direct childrens of the node
+       fun children: SequenceRead[nullable Node] is abstract
+
+       # Visit all the children of the node with the visitor `v`
+       protected fun visit_children(v: Visitor)
+       do
+               for c in children do if c != null then v.enter_visit(c)
+       end
+
+       # The position of the node in the input stream
+       var position: nullable Position writable = null
+
+       # Produce a graphiz file for the syntaxtic tree rooted at `self`.
+       fun to_dot(filepath: String)
+       do
+               var f = new OFStream.open(filepath)
+               f.write("digraph g \{\n")
+               f.write("rankdir=BT;\n")
+
+               var a = new Array[NToken]
+               to_dot_visitor(f, a)
+
+               f.write("\{ rank=same\n")
+               var first = true
+               for n in a do
+                       if first then
+                               first = false
+                       else
+                               f.write("->")
+                       end
+                       f.write("n{n.object_id}")
+               end
+               f.write("[style=invis];\n")
+               f.write("\}\n")
+
+               f.write("\}\n")
+               f.close
+       end
+
+       private fun to_dot_visitor(f: OStream, a: Array[NToken])
+       do
+               f.write("n{object_id} [label=\"{node_name}\"];\n")
+               for x in children do
+                       if x == null then continue
+                       f.write("n{x.object_id} -> n{object_id};\n")
+                       x.to_dot_visitor(f,a )
+               end
+       end
+
+       redef fun to_s do
+               var pos = position
+               if pos == null then
+                       return "{node_name}"
+               else
+                       return "{node_name}@({pos})"
+               end
+       end
+end
+
+# A token produced by the lexer and used in a syntactic tree
+abstract class NToken
+       super Node
+
+       redef fun children do return once new Array[Node]
+
+       redef fun to_dot_visitor(f, a)
+       do
+               var labe = "{node_name}"
+               var pos = position
+               if pos != null then labe += "\\n{pos}"
+               var text = self.text
+               if node_name != "'{text}'" then
+                       labe += "\\n'{text.escape_to_c}'"
+               end
+               f.write("n{object_id} [label=\"{labe}\",shape=box];\n")
+               a.add(self)
+       end
+
+       # The text associated with the token
+       var text: String writable = ""
+
+       redef fun to_s do
+               var res = super
+               var text = self.text
+               if node_name != "'{text}'" then
+                       res += "='{text.escape_to_c}'"
+               end
+               return res
+       end
+end
+
+# The special token for the end of stream
+class NEof
+       super NToken
+end
+
+# A special token used to represent a parser or lexer error
+abstract class NError
+       super NToken
+
+       # All the partially built tree during parsing (aka the node_stack)
+       var error_tree = new Nodes[Node]
+end
+
+# A lexer error as a token for the unexpected characted
+class NLexerError
+       super NError
+end
+
+# A parser error linked to a unexpected token
+class NParserError
+       super NError
+       # The unexpected token
+       var token: nullable NToken
+end
+
+# A hogeneous sequence of node, used to represent unbounded lists (and + modifier)
+class Nodes[T: Node]
+       super Node
+       redef fun children do return items
+       var items = new Array[T]
+end
+
+# A production with a specific, named and statically typed childrens
+class NProd
+       super Node
+       redef var children: SequenceRead[nullable Node] = new NProdChildren(self)
+
+       # The exact number of direct children
+       # Used to implement `children` by generated parsers
+       fun number_of_children: Int is abstract
+
+       # The specific children got by its index
+       # Used to implement `children` by generated parsers
+       fun child(x: Int): nullable Node is abstract
+end
+
+
+private class NProdChildren
+       super SequenceRead[nullable Node]
+       var prod: NProd
+       redef fun iterator do return new NProdIterator(prod)
+       redef fun length do return prod.number_of_children
+       redef fun is_empty do return prod.number_of_children == 0
+       redef fun [](i) do return prod.child(i)
+end
+
+private class NProdIterator
+       super IndexedIterator[nullable Node]
+       var prod: NProd
+       redef var index = 0
+       redef fun is_ok do return index < prod.number_of_children
+       redef fun next do index += 1
+       redef fun item do return prod.child(index)
+end
+
+# All-in-one abstract class to test generated parsers on a given
+abstract class TestParser
+       # How to get a new lexer on a given stream of character
+       fun new_lexer(text: String): Lexer is abstract
+
+       # How to get a new parser
+       fun new_parser: Parser is abstract
+
+       # The name of the language (used for generated files)
+       fun name: String is abstract
+
+       # Use the class as the main enrty point of the program
+       # - parse arguments and options of the command
+       # - test the parser (see `work`)
+       fun main: Node
+       do
+               if args.is_empty then
+                       print "usage {name}_test <filepath> | - | -e <text>"
+                       exit 0
+               end
+
+               var filepath = args.shift
+               var text
+               if filepath == "-" then
+                       text = stdin.read_all
+               else if filepath == "-e" then
+                       if args.is_empty then
+                               print "Error: -e need a text"
+                               exit 1
+                       end
+                       text = args.shift
+               else
+                       var f = new IFStream.open(filepath)
+                       text = f.read_all
+                       f.close
+               end
+
+               if not args.is_empty then
+                       print "Error: superfluous arguments."
+                       exit 1
+               end
+
+               return work(text)
+       end
+
+       # Produce a full syntactic tree for a given stream of character
+       # Produce also statistics and output files
+       fun work(text: String): Node
+       do
+               print "INPUT: {text.length} chars"
+               var l = new_lexer(text)
+               var tokens = l.lex
+
+               var tokout = "{name}.tokens.out"
+               print "TOKEN: {tokens.length} tokens (see {tokout})"
+
+               var f = new OFStream.open(tokout)
+               for t in tokens do
+                       f.write "{t.to_s}\n"
+               end
+               f.close
+
+               var p = new_parser
+               p.tokens.add_all(tokens)
+
+               var n = p.parse
+
+               var astout = "{name}.ast.out"
+               f = new OFStream.open(astout)
+               var tpv = new TreePrinterVisitor(f)
+               var astdotout = "{name}.ast.dot"
+               if n isa NError then
+                       print "ERROR: {n} (see {astout} and {astdotout})"
+                       tpv.enter_visit(n)
+                       n = n.error_tree
+               else
+                       print "ROOT: {n} (see {astout} and {astdotout})"
+               end
+               tpv.enter_visit(n)
+               n.to_dot(astdotout)
+               f.close
+
+               return n
+       end
+end
diff --git a/contrib/nitcc/nitcc_semantic.nit b/contrib/nitcc/nitcc_semantic.nit
new file mode 100644 (file)
index 0000000..8713da0
--- /dev/null
@@ -0,0 +1,487 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Semantic analysis of a sablecc grammar file
+# User to validate the file and generate the grammar and the nfa
+#
+# TODO: split in submodules
+module nitcc_semantic
+
+import nitcc_parser
+import grammar
+import re2nfa
+
+# Main visitor for the semantic analysis
+#
+# TODO clean-up the visitors
+class CollectNameVisitor
+       super Visitor
+
+       var nprods = new Array[Nprod]
+
+       # Symbol table to associate things (prods and exprs) with their name
+       var names = new HashMap[String, Node]
+
+       # The associated grammar object
+       # Read the result of the visit here
+       var gram = new Gram
+
+       # The associated NFA object
+       # Read the result of the visit here
+       var nfa = new Automaton.empty
+
+       # Run the semantic analysis of the grammar
+       fun start(n: Node)
+       do
+               # First visit to collect names
+               enter_visit(n)
+
+               # Second visit to use collectec names and build rhings
+               var v2 = new CheckNameVisitor(self)
+               v2.enter_visit(n)
+
+               # Inline all the ?
+               gram.inline(v2.quesizes.values)
+               # Inlile all the prods sufixed by '_imline' #TODO use a real keyword
+               for p in gram.prods do
+                       if not p.name.has_suffix("_inline") then continue
+                       print "inline {p}"
+                       gram.inline([p])
+               end
+
+               # Build the NFA automaton
+               for t in gram.tokens do
+                       var nexpr = t.nexpr
+                       var nfa2
+                       if nexpr == null then
+                               nfa2 = new Automaton.epsilon
+                               for c in t.text.as(not null) do
+                                       nfa2.concat(new Automaton.atom(c.ascii))
+                               end
+                       else
+                               nfa2 = nexpr.build_nfa
+                       end
+                       nfa.states.add_all nfa2.states
+                       nfa.start.add_trans(nfa2.start, null)
+                       for s in nfa2.accept do nfa.add_tag(s, t)
+                       nfa.accept.add_all nfa2.accept
+               end
+       end
+
+       redef fun visit(n) do n.accept_collect_prod(self)
+end
+
+private class CheckNameVisitor
+       super Visitor
+
+       # The collected altname, for the alternative
+       var altname: nullable String = null
+
+       # The collected elements, for the alternative
+       var elems = new Array[Element]
+
+       # The collected element names, for the alternative
+       var elems_names = new Array[nullable String]
+
+       # The collected elementname, for the nelem
+       var elemname: nullable String = null
+
+       # Is the alternative transformed, for the alternative
+       var trans = false
+
+       # Pool of elements that are modified with + (reuse them!)
+       private var plusizes = new HashMap[Element, Production]
+
+       # Create a + version of an element
+       fun plusize(e: Element): Production
+       do
+               if plusizes.has_key(e) then return plusizes[e]
+               var name = "{e}+"
+               var prod = new Production(name)
+               prod.acname = "Nodes[{e.acname}]"
+               v1.gram.prods.add(prod)
+               prod.new_alt("{name}_one", e)
+               prod.new_alt("{name}_more", prod, e)
+               plusizes[e] = prod
+               return prod
+       end
+
+       # Pool of elements that are modified with ? (reuse them!)
+       private var quesizes = new HashMap[Element, Production]
+
+       # Create a ? version of an element
+       fun quesize(e: Element): Production
+       do
+               if quesizes.has_key(e) then return quesizes[e]
+               var name = "{e}?"
+               var prod = new Production(name)
+               prod.acname = "nullable {e.acname}"
+               v1.gram.prods.add(prod)
+               var a1 = prod.new_alt("{name}_one", e)
+               a1.codes = [new CodePop]
+               var a0 = prod.new_alt0("{name}_none")
+               a0.codes = [new CodeNull]
+               quesizes[e] = prod
+               return prod
+       end
+
+       # The current nexpr, used to track dependency on named expressions (see `Nexpr::precs`)
+       var nexpr: nullable Nexpr
+
+       # The current production, used to initialize alternatives
+       var prod: nullable Production
+
+       # The main visitor, used to access the grammar of the symbol table
+       var v1: CollectNameVisitor
+       init(v1: CollectNameVisitor) do self.v1 = v1
+
+       redef fun visit(n) do n.accept_check_name_visitor(self)
+end
+
+redef class Node
+       private fun accept_collect_prod(v: CollectNameVisitor) do visit_children(v)
+       private fun accept_check_name_visitor(v: CheckNameVisitor) do visit_children(v)
+end
+
+redef class Nexpr
+       # The associated token
+       var token: nullable Token
+
+       # The associated name
+       var name: nullable String
+
+       # The required expression (Nexpr that are used inside)
+       var precs = new ArraySet[Nexpr]
+
+       redef fun accept_collect_prod(v) do
+               var id = children.first.as(Nid)
+               var name = id.text
+               v.names[name] = self
+               self.name = name
+       end
+       redef fun accept_check_name_visitor(v) do
+               v.nexpr = self
+               super
+               v.nexpr = null
+       end
+
+       # Flag to track circular regular expression
+       var is_building = false
+
+       # The associated NFA (cached, see `build_nfa`)
+       private var nfa: nullable Automaton
+
+       # Build the NFA, possibily building the NFA of required expressions
+       # Print an error if there is a circular dependency
+       # The result is cached
+       fun build_nfa: Automaton do
+               var res = nfa
+               if res != null then return res
+               if is_building then
+                       print "Error: circular regular expression {name.to_s}."
+                       exit(1)
+                       abort
+               end
+               is_building = true
+               for p in precs do
+                       p.build_nfa
+               end
+               is_building = false
+               var nre = self.children[2]
+               res = nre.make_rfa
+               nfa = res
+               return res
+       end
+end
+
+redef class Nre_id
+       # The named expression
+       var nexpr: nullable Nexpr
+       
+       redef fun accept_check_name_visitor(v) do
+               var id = children.first.as(Nid)
+               var name = id.text
+               if not v.v1.names.has_key(name) then
+                       print "Error: unknown name {name}"
+                       exit(1)
+                       abort
+               end
+               var node = v.v1.names[name]
+               if node isa Nprod then
+                       print "Error: cannot use production {name} in a regular expression"
+                       exit(1)
+                       abort
+               else if not node isa Nexpr then
+                       abort
+               end
+               nexpr = node
+               v.nexpr.precs.add(node)
+       end
+
+       redef fun make_rfa
+       do
+               return nexpr.nfa.dup
+       end
+end
+
+redef class Nign
+       # The named element
+       var elem: nullable Element
+
+       redef fun accept_check_name_visitor(v) do
+               var id = children[1].as(Nid)
+               var name = id.text
+               if not v.v1.names.has_key(name) then
+                       print "Error: unknown name {name}"
+                       exit(1)
+                       abort
+               end
+               var node = v.v1.names[name]
+               var elem: nullable Element
+               if node isa Nprod then
+                       print "Error cannot ignore a production"
+                       exit(1)
+                       abort
+               else if node isa Nexpr then
+                       elem = node.token
+                       if elem == null then
+                               elem = new Token("Ignored")
+                               elem.nexpr = node
+                               v.v1.gram.tokens.add(elem)
+                               node.token = elem
+                       end
+               else
+                       abort
+               end
+               self.elem = elem
+       end
+end
+
+redef class Nprod
+       # The associated production
+       var prod: nullable Production
+
+       redef fun accept_collect_prod(v) do
+               var id = children.first.as(Nid)
+               var name = id.text
+               v.names[name] = self
+               v.nprods.add(self)
+               prod = new Production(name)
+               v.gram.prods.add(prod.as(not null))
+       end
+       redef fun accept_check_name_visitor(v) do
+               v.prod = prod
+               super
+               v.prod = null
+       end
+end
+
+redef class Nptrans
+       redef fun accept_check_name_visitor(v) do
+               var id = children[2].as(Nid)
+               var name = id.text
+
+               var node = v.v1.names[name]
+               if node isa Nprod then
+                       v.prod.spe = node.prod.as(not null)
+                       if v.prod.spe.spe != null then
+                               print "Cannot transform into {name}, {name} is already transformed."
+                               exit(1)
+                               abort
+                       end
+               else if node isa Nexpr then
+                       print "Cannot transform into {name}, {name} is a token."
+               else
+                       abort
+               end
+       end
+end
+
+redef class Natrans
+       redef fun accept_check_name_visitor(v) do
+               var id = children[2].as(Nid)
+               var name = id.text
+
+               v.trans = true
+       end
+end
+
+redef class Nalt
+       # The associated alternative
+       var alt: nullable Alternative
+
+       redef fun accept_check_name_visitor(v)
+       do
+               v.altname = null
+               v.trans = false
+               v.elems = new Array[Element]
+               v.elems_names = new Array[nullable String]
+               super
+               var prod = v.prod.as(not null)
+               var prodabs = prod.spe
+               if prodabs == null then prodabs = prod
+               var name = v.altname
+               if name == null then
+                       if v.trans then
+                               name = prod.name + "_" + prod.alts.length.to_s
+                       else if prod.spe == null and prod.alts.is_empty then
+                               name = prod.name
+                               prod.altone = true
+                       else
+                               if prodabs.altone then
+                                       prodabs.altone = false
+                                       prodabs.alts.first.name = prodabs.name + "_0"
+                               end
+                               name = prod.name + "_" + prod.alts.length.to_s
+                       end
+               else
+                       if prodabs.altone then
+                               prodabs.altone = false
+                               prodabs.alts.first.name = prodabs.name + "_0"
+                       end
+                       name = prodabs.name + "_" + name
+               end
+               var alt = prod.new_alt2(name, v.elems)
+               alt.elems_names.add_all(v.elems_names)
+               self.alt = alt
+               if v.trans then
+                       alt.trans = true
+                       alt.codes = [new CodePop]
+               end
+       end
+end
+
+redef class Naltid
+       redef fun accept_check_name_visitor(v)
+       do
+               var id = children[1].as(Nid)
+               var name = id.text
+               v.altname = name
+       end
+end
+
+redef class Nelem
+       # The associated element
+       var elem: nullable Element
+end
+
+redef class Token
+       # The associated expression (if any, ie defined in the lexer part)
+       var nexpr: nullable Nexpr
+       # The associated text (if any, ie defined in the parser part)
+       var text: nullable String
+end
+
+redef class Nnelem
+       redef fun accept_check_name_visitor(v)
+       do
+               v.elemname = null
+               super
+               var elemname = v.elemname
+               if elemname != null and v.elems_names.has(elemname) then
+                       var i = 2
+                       while v.elems_names.has(elemname+i.to_s) do i += 1
+                       elemname = elemname+i.to_s
+               end
+               v.elems_names.add elemname
+       end
+end
+
+redef class Nelemid
+       redef fun accept_check_name_visitor(v)
+       do
+               var id = children[1].as(Nid)
+               var name = id.text
+               v.elemname = name
+       end
+end
+
+redef class Nelem_id
+       redef fun accept_check_name_visitor(v) do
+               var id = children.first.as(Nid)
+               var name = id.text
+               if not v.v1.names.has_key(name) then
+                       print "Error: unknown name {name}"
+                       exit(1)
+                       abort
+               end
+               var node = v.v1.names[name]
+               var elem: nullable Element
+               if node isa Nprod then
+                       elem = node.prod
+               else if node isa Nexpr then
+                       elem = node.token
+                       if elem == null then
+                               elem = new Token(name)
+                               elem.nexpr = node
+                               v.v1.gram.tokens.add(elem)
+                               node.token = elem
+                       end
+               else
+                       abort
+               end
+               assert elem != null
+               self.elem = elem
+               v.elems.add(elem)
+               if v.elemname == null then v.elemname = name
+       end
+end
+
+redef class Nelem_str
+       redef fun accept_check_name_visitor(v) do
+               var str = children.first.as(Nstr)
+               var text = str.value
+               var name = str.text
+               var elem: nullable Element
+               if v.v1.names.has_key(name) then
+                       elem = v.v1.names[name].as(Nelem_str).elem
+                       assert elem != null
+               else
+                       elem = new Token(name)
+                       elem.text = text
+                       v.v1.gram.tokens.add(elem)
+                       v.v1.names[name] = self
+               end
+               self.elem = elem
+               v.elems.add(elem)
+       end
+end
+
+redef class Nelem_star
+       redef fun accept_check_name_visitor(v) do
+               super
+               var elem = v.elems.pop
+               elem = v.plusize(elem)
+               elem = v.quesize(elem)
+               v.elems.add elem
+       end
+end
+
+redef class Nelem_ques
+       redef fun accept_check_name_visitor(v) do
+               super
+               var elem = v.elems.pop
+               elem = v.quesize(elem)
+               v.elems.add elem
+       end
+end
+
+redef class Nelem_plus
+       redef fun accept_check_name_visitor(v) do
+               super
+               var elem = v.elems.pop
+               elem = v.plusize(elem)
+               v.elems.add elem
+       end
+end
diff --git a/contrib/nitcc/re2nfa.nit b/contrib/nitcc/re2nfa.nit
new file mode 100644 (file)
index 0000000..9a4008d
--- /dev/null
@@ -0,0 +1,153 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Transformation of regular expression to NFA
+module re2nfa
+
+import nitcc_lexer
+import autom
+
+redef class Node
+       # Build the NFA of the regular expression
+       fun make_rfa: Automaton do
+               print inspect
+               abort
+       end
+end
+
+redef class Nstr
+       # The real value of the string
+       fun value: String do return text.substring(1, text.length-2).unescape_nit
+       redef fun make_rfa: Automaton
+       do
+               var a = new Automaton.epsilon
+               var val
+               for c in self.value do
+                       var b = new Automaton.atom(c.ascii)
+                       a.concat(b)
+               end
+               return a
+       end
+end
+
+redef class Nch_dec
+       # The real value of the char
+       fun value: String do return text.substring_from(1).to_i.ascii.to_s
+       redef fun make_rfa: Automaton
+       do
+               var a = new Automaton.atom(self.value.first.ascii)
+               return a
+       end
+end
+
+redef class NProd
+       redef fun make_rfa: Automaton
+       do
+               assert children.length == 1 else print "no make_rfa for {self}"
+               return children.first.make_rfa
+       end
+end
+
+redef class Nre_alter
+       redef fun make_rfa
+       do
+               var a = children[0].make_rfa
+               var b = children[2].make_rfa
+               a.alternate(b)
+               return a
+       end
+end
+
+redef class Nre_minus
+       redef fun make_rfa
+       do
+               var a = children[0].make_rfa
+               var b = children[2].make_rfa.to_dfa
+               for t in b.start.outs do
+                       if not t.to.outs.is_empty then
+                               print "Not Yet Implemented Error: '-' only works on single char"
+                               exit(1)
+                       end
+                       a.minus_sym(t.symbol.as(not null))
+               end
+               return a
+       end
+end
+
+redef class Nre_conc
+       redef fun make_rfa
+       do
+               var a = children[0].make_rfa
+               var b = children[1].make_rfa
+               a.concat(b)
+               return a
+       end
+end
+
+redef class Nre_star
+       redef fun make_rfa
+       do
+               var a = children[0].make_rfa
+               a.close
+               return a
+       end
+end
+
+redef class Nre_ques
+       redef fun make_rfa
+       do
+               var a = children[0].make_rfa
+               a.optionnal
+               return a
+       end
+end
+
+redef class Nre_plus
+       redef fun make_rfa
+       do
+               var a = children[0].make_rfa
+               a.plus
+               return a
+       end
+end
+
+redef class Nre_par
+       redef fun make_rfa
+       do
+               return children[1].make_rfa
+       end
+end
+
+redef class Nre_class
+       redef fun make_rfa: Automaton
+       do
+               var c1 = children[0].as(Nstr).value
+               var c2 = children[3].as(Nstr).value
+               if c1.length != 1 or c2.length != 1 then
+                       print "Classes only works on single char"
+                       exit(1)
+                       abort
+               end
+               var a = new Automaton.cla(c1.first.ascii, c2.first.ascii)
+               return a
+       end
+end
+
+redef class Nre_any
+       redef fun make_rfa: Automaton
+       do
+               var a = new Automaton.cla(0, 127)
+               return a
+       end
+end
diff --git a/contrib/nitcc/t/alterner.pl b/contrib/nitcc/t/alterner.pl
new file mode 100755 (executable)
index 0000000..af66c96
--- /dev/null
@@ -0,0 +1,186 @@
+#!/usr/bin/perl
+
+# Alterner.pl
+#
+# Copyright 2011 Jean Privat <jean@pryen.org>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+use strict;
+use File::Basename;
+
+# Default values for options
+my $directory = "alt"; # The directory where alternatives will be generated.
+my $start = "//"; # The marker at the begin of a directive (usually the start of a comment).
+my $end = ""; # The marker at the end of the line (usually the end of a comment)
+my $altsep = "."; # The separator used in generated file between the basename and the altmark.
+
+sub usage(;$) {
+       my $msg = shift;
+       my $usage = "Usage: alterner.pl [-d dir] [--start pat] [--end pat] file...";
+       if (defined $msg) {
+               print STDERR $msg . "\n" . $usage . "\n";
+               exit 1;
+       } else {
+               print $usage . "\n";
+               exit 0;
+       }
+}
+
+# Process arguments.
+my $stop = 0;
+while (@ARGV && !$stop) {
+       my $arg = $ARGV[0];
+       my $val = $ARGV[1];
+       if ($arg eq "-d") {
+               $directory = $val or usage "$arg requires a directory.";
+               shift @ARGV;
+               shift @ARGV;
+       } elsif ($arg eq "--start") {
+               $start = $val or usage "$arg requires a pattern.";
+               shift @ARGV;
+               shift @ARGV;
+       } elsif ($arg eq "--end") {
+               $end = $val or usage "$arg requires a pattern.";
+               shift @ARGV;
+               shift @ARGV;
+       } elsif ($arg eq "--altsep") {
+               $altsep = $val or usage "$arg requires a pattern.";
+               shift @ARGV;
+               shift @ARGV;
+       } elsif ($arg eq "-h" || $arg eq "--help") { 
+               shift @ARGV;
+               usage
+       } elsif ($arg eq "--") { 
+               shift @ARGV;
+               $stop = 1;
+       } elsif ($arg =~ /^-/) {
+               usage "Unknown argument $arg.";
+       } else {
+               $stop = 1;
+       }
+}
+
+if ($#ARGV == -1) {
+       usage("No input file.");
+}
+
+# Is $_[0] triggers the alternative directive $[1]?
+sub triggers_alt($$) {
+       my $number = shift;
+       my $directive = shift;
+       foreach my $a (split ",", $directive) {
+               if ($a =~ /^(\d+)-(\d+)$/) {
+                       if ($1 <= $number && $number <= $2) {
+                               return 1;
+                       }
+               } else {
+                       if ($number == $a) {
+                               return 1;
+                       }
+               }
+       }
+       return 0;
+}
+
+# Generate alternatives from the specified input-file using a specific altmark
+sub process_alts($$) {
+       my $file = shift;
+       my $altmark = shift;
+       # Read the file
+       open my $in, "<", $file or die "$file: $!";
+       my @lines = <$in>;
+       close($file);
+
+       my $prefix = $start . $altmark;
+
+       # Collect alternatives
+       my %alt;
+       foreach my $l (@lines) {
+               while ($l =~ /\Q$prefix\E([\d,-]+)(\Q$start\E|\b)/g) {
+                       for my $a (split /[,-]/, $1) {
+                               $alt{$a} = 1;
+                       }
+               }
+       }
+       my @alt = sort(keys(%alt));
+
+       my @files;
+       # Process each alternatives
+       foreach my $alt (@alt) {
+               # Exctact the basename and the suffix
+               my ($name, $path, $suffix) = fileparse($file, qr/\.[^\.]*/);
+
+               # Compute filename of the alternative
+               my $outfile = $name . $altsep . $altmark . $alt . $suffix;
+               if (defined $directory && $directory ne ".") {
+                       $outfile = $directory . "/" . $outfile;
+                       if (! -d $directory) {
+                               mkdir $directory or die "$directory: $!";
+                       }
+               }
+               push @files, $outfile;
+
+               # Write the alternative
+               open my $out, ">", $outfile or die "$outfile: $!";
+               print "$outfile\n";
+               foreach my $l (@lines) {
+                       my $l2 = $l;
+                       my $selected;
+                       while ($l =~ /(\Q$prefix\E([\d,-]+)(\Q$start\E|\b))/g) {
+                               if (triggers_alt $alt, $2) {
+                                       $selected = $1;
+                               }
+                       }
+                       if ($selected && $l =~ /^(\s*)(.*)(\s*)(\Q$selected\E)([ \t]*)(.*)([ \t]*\Q$end\E\s*)$/) {
+                               $l2 = "$1$6$3$4$5$2$7";
+                       }
+                       print $out $l2 or die "$outfile: $!";
+               }
+               close $out;
+       }
+       return @files;
+}
+
+# Generate combination of alternatives from the specified input-file
+sub process_xalts($) {
+       my $file = shift;
+       # Read the file
+       open my $in, "<", $file or die "$file: $!";
+       my @lines = <$in>;
+       close($file);
+
+       # Collect combination of alternatives
+       my %alt;
+       foreach my $l (@lines) {
+               while ($l =~ /\Q$start\E(\d*alt)\d+(\Q$start\E|\b)/g) {
+                       $alt{$1} = $1;
+               }
+       }
+       my @alt = sort(keys(%alt));
+
+       my @files = $file;
+       # Process each combination of alternatives
+       foreach my $alt (@alt) {
+               my @newfiles;
+               foreach my $f (@files) {
+                       push @newfiles, process_alts($f, $alt);
+               }
+               push @files, @newfiles;
+       }
+}
+
+# Do the job
+foreach my $file (@ARGV) {
+       process_xalts($file);
+}
diff --git a/contrib/nitcc/t/empty.input b/contrib/nitcc/t/empty.input
new file mode 100644 (file)
index 0000000..2e65efe
--- /dev/null
@@ -0,0 +1 @@
+a
\ No newline at end of file
diff --git a/contrib/nitcc/t/empty.input2 b/contrib/nitcc/t/empty.input2
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/empty.sablecc b/contrib/nitcc/t/empty.sablecc
new file mode 100644 (file)
index 0000000..bab61e3
--- /dev/null
@@ -0,0 +1,15 @@
+//alt1 /*
+Grammar x;
+//alt2 /*
+Lexer
+//alt3 /*
+a = 'a';
+//alt4 /*
+Parser
+//alt5 /*
+Ignored a;
+//alt6 /*
+p = a;
+
+/* //alt1 //alt2 //alt3 //alt4 //alt5 //alt6
+*/
diff --git a/contrib/nitcc/t/if.sablecc b/contrib/nitcc/t/if.sablecc
new file mode 100644 (file)
index 0000000..374f2dd
--- /dev/null
@@ -0,0 +1,15 @@
+Grammar if;
+Lexer
+Parser
+
+p = 'e' e | 'f' f;
+
+e =
+       'if' e 'then' e else? |
+       'e' ;
+else = 'else' e;
+
+f =
+       'if' f 'then' f |
+       'if' f 'then' f 'else' f |
+       'f' ;
diff --git a/contrib/nitcc/t/inf5000-04-lexer-automate.input b/contrib/nitcc/t/inf5000-04-lexer-automate.input
new file mode 100644 (file)
index 0000000..6c2d35a
--- /dev/null
@@ -0,0 +1,9 @@
+if iff iff i f
+if50i
+if 50 i
+50
+50.50
+50.
+.50
+50.f
+f.50
diff --git a/contrib/nitcc/t/inf5000-04-lexer-automate.sablecc b/contrib/nitcc/t/inf5000-04-lexer-automate.sablecc
new file mode 100644 (file)
index 0000000..a06bd38
--- /dev/null
@@ -0,0 +1,14 @@
+Grammar automate;
+Lexer
+  letter = 'a'..'z';
+  digit = '0'..'9';
+  id = letter(letter|digit)*;
+  if = 'if';
+  int = (digit)+;
+  float = (digit)+ '.' (digit)+;
+  dot = '.';
+  blank = #10|#13|#32;
+Parser
+  Ignored blank;
+  p = t*;
+  t = id | if | int | float | dot;
diff --git a/contrib/nitcc/t/inf5000-04-lexer-demo.input b/contrib/nitcc/t/inf5000-04-lexer-demo.input
new file mode 100644 (file)
index 0000000..a6d7966
--- /dev/null
@@ -0,0 +1,3 @@
+if iff iff i f
+if50i
+if,i
diff --git a/contrib/nitcc/t/inf5000-04-lexer-demo.input2 b/contrib/nitcc/t/inf5000-04-lexer-demo.input2
new file mode 100644 (file)
index 0000000..e373ee6
--- /dev/null
@@ -0,0 +1 @@
+50
diff --git a/contrib/nitcc/t/inf5000-04-lexer-demo.sablecc b/contrib/nitcc/t/inf5000-04-lexer-demo.sablecc
new file mode 100644 (file)
index 0000000..42a7671
--- /dev/null
@@ -0,0 +1,14 @@
+Grammar demo;
+Lexer
+  letter = 'a'..'z';
+  digit = '0'..'9';
+  identifier = letter (letter | digit)*;
+  comma = ',';
+  blank = (' ' | #9 | #10 | #13)+;
+  if = 'if';
+  else = 'else';
+Parser
+  Ignored
+    blank;
+  p = t*;
+  t = identifier | comma | if | else;
diff --git a/contrib/nitcc/t/inf5000-04-lexer-pire_cout.input b/contrib/nitcc/t/inf5000-04-lexer-pire_cout.input
new file mode 100644 (file)
index 0000000..0601475
--- /dev/null
@@ -0,0 +1 @@
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab
diff --git a/contrib/nitcc/t/inf5000-04-lexer-pire_cout.input2 b/contrib/nitcc/t/inf5000-04-lexer-pire_cout.input2
new file mode 100644 (file)
index 0000000..2abac58
--- /dev/null
@@ -0,0 +1 @@
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
diff --git a/contrib/nitcc/t/inf5000-04-lexer-pire_cout.sablecc b/contrib/nitcc/t/inf5000-04-lexer-pire_cout.sablecc
new file mode 100644 (file)
index 0000000..841d90a
--- /dev/null
@@ -0,0 +1,9 @@
+Grammar pire_cout;
+Lexer
+  a = 'a';
+  b = 'a'* 'b';
+blank = ' ' | #9 | #10 | #13;
+Parser
+  Ignored blank;
+  p = t*;
+  t = a | b;
diff --git a/contrib/nitcc/t/inf5000-04-lexer-priorite_d_inclusion.input b/contrib/nitcc/t/inf5000-04-lexer-priorite_d_inclusion.input
new file mode 100644 (file)
index 0000000..41a8a53
--- /dev/null
@@ -0,0 +1,3 @@
+i f
+if
+ify
diff --git a/contrib/nitcc/t/inf5000-04-lexer-priorite_d_inclusion.sablecc b/contrib/nitcc/t/inf5000-04-lexer-priorite_d_inclusion.sablecc
new file mode 100644 (file)
index 0000000..7b50dfc
--- /dev/null
@@ -0,0 +1,9 @@
+Grammar priorite_d_inclusion;
+Lexer
+  identifier = ('a'..'z')+;
+  if = 'if';
+  blank = ' ' | #9 | #10 | #13;
+Parser
+  Ignored blank;
+  p = t*;
+  t = identifier | if;
diff --git a/contrib/nitcc/t/inf5000-04-lexer-priorite_declaree.input b/contrib/nitcc/t/inf5000-04-lexer-priorite_declaree.input
new file mode 100644 (file)
index 0000000..067f188
--- /dev/null
@@ -0,0 +1,4 @@
+z10
+00ff1
+fff
+00fg1
diff --git a/contrib/nitcc/t/inf5000-04-lexer-priorite_declaree.sablecc b/contrib/nitcc/t/inf5000-04-lexer-priorite_declaree.sablecc
new file mode 100644 (file)
index 0000000..01a8619
--- /dev/null
@@ -0,0 +1,11 @@
+Grammar priorite_declaree;
+Lexer
+  letter = 'a'..'z';
+  digit = '0'..'9';
+  identifier = letter(letter|digit)*;
+  hexinteger = (digit|'a'..'f')+ Except identifier;
+  blank = ' ' | #9 | #10 | #13;
+Parser
+  Ignored blank;
+  p = t*;
+  t = identifier | hexinteger;
diff --git a/contrib/nitcc/t/inf5000-05-grammaire-arithmetique.input b/contrib/nitcc/t/inf5000-05-grammaire-arithmetique.input
new file mode 100644 (file)
index 0000000..2ab63cf
--- /dev/null
@@ -0,0 +1,5 @@
+5 + 4 * 2
+5 - 4 - 2
+5 + 4 + 2
+(5 + 4) * 2
+5 + (4 * 2)
diff --git a/contrib/nitcc/t/inf5000-05-grammaire-arithmetique.sablecc b/contrib/nitcc/t/inf5000-05-grammaire-arithmetique.sablecc
new file mode 100644 (file)
index 0000000..cf76bd7
--- /dev/null
@@ -0,0 +1,18 @@
+Grammar arithmetique;
+Lexer
+int = ('0'..'9')+;
+blank = ' ' | #9 | #10 | #13;
+
+Parser
+Ignored blank;
+
+exps = exp*;
+
+exp = {add:} exp '+' exp |
+      {min:} exp '-' exp |
+      {mul:} exp '*' exp |
+      {int:} int |
+      {par:} '(' exp ')' ;
+//alt1   Precedence
+//alt1      Left mul;
+//alt1      Left add, min;
diff --git a/contrib/nitcc/t/inf5000-05-grammaire-arithmetique2.input b/contrib/nitcc/t/inf5000-05-grammaire-arithmetique2.input
new file mode 100644 (file)
index 0000000..2ab63cf
--- /dev/null
@@ -0,0 +1,5 @@
+5 + 4 * 2
+5 - 4 - 2
+5 + 4 + 2
+(5 + 4) * 2
+5 + (4 * 2)
diff --git a/contrib/nitcc/t/inf5000-05-grammaire-arithmetique2.sablecc b/contrib/nitcc/t/inf5000-05-grammaire-arithmetique2.sablecc
new file mode 100644 (file)
index 0000000..3adf419
--- /dev/null
@@ -0,0 +1,17 @@
+Grammar arithmetique;
+Lexer
+int = ('0'..'9')+;
+blank = ' ' | #9 | #10 | #13;
+
+Parser
+Ignored blank;
+
+exps = exp*;
+
+exp = {add:} exp '+' factor |
+      {min:} exp '-' factor |
+      {factor:} factor ;
+factor = {mul:} factor '*' term |
+         {term:} term ;
+term = {int:} int |
+       {par:} '(' exp ')' ;
diff --git a/contrib/nitcc/t/inf5000-05-grammaire-formes.input b/contrib/nitcc/t/inf5000-05-grammaire-formes.input
new file mode 100644 (file)
index 0000000..6b8c1c1
--- /dev/null
@@ -0,0 +1 @@
+centre (5pt, 1cm) rayon 10 px
diff --git a/contrib/nitcc/t/inf5000-05-grammaire-formes.sablecc b/contrib/nitcc/t/inf5000-05-grammaire-formes.sablecc
new file mode 100644 (file)
index 0000000..822634f
--- /dev/null
@@ -0,0 +1,12 @@
+Grammar formes;
+Lexer
+  nombre = ('0'..'9')+;
+  blank = ' ' | #9 | #10 | #13;
+
+Parser
+  Ignored blank;
+  forme = {cercle:} 'centre' point 'rayon' long |
+          {segment:} point '--' point ;
+  point = '(' long ',' long ')' ;
+  long = nombre unite ;
+  unite = 'cm' | 'mm' | 'pt' | 'px' ;
diff --git a/contrib/nitcc/t/inf5000-05-grammaire-lisp.input b/contrib/nitcc/t/inf5000-05-grammaire-lisp.input
new file mode 100644 (file)
index 0000000..5ac2401
--- /dev/null
@@ -0,0 +1 @@
+(ida(idb idc)(idd ide(idf))())
diff --git a/contrib/nitcc/t/inf5000-05-grammaire-lisp.sablecc b/contrib/nitcc/t/inf5000-05-grammaire-lisp.sablecc
new file mode 100644 (file)
index 0000000..d752dc9
--- /dev/null
@@ -0,0 +1,13 @@
+Grammar lisp;
+Lexer
+id = ('a'..'z')+;
+blank = ' ' | #9 | #10 | #13;
+
+Parser
+Ignored blank;
+
+item = {par:} '(' list ')' |
+       {nil:} '(' ')' |
+       {id:} id ;
+list = {many:} item list |
+       {one:} item ;
diff --git a/contrib/nitcc/t/inf5000-05-grammaire-listes.input b/contrib/nitcc/t/inf5000-05-grammaire-listes.input
new file mode 100644 (file)
index 0000000..188022f
--- /dev/null
@@ -0,0 +1 @@
+ida idb idc
diff --git a/contrib/nitcc/t/inf5000-05-grammaire-listes.sablecc b/contrib/nitcc/t/inf5000-05-grammaire-listes.sablecc
new file mode 100644 (file)
index 0000000..e8591c7
--- /dev/null
@@ -0,0 +1,10 @@
+Grammar listes;
+Lexer
+id = ('a'..'z')+;
+blank = ' ' | #9 | #10 | #13;
+
+Parser
+Ignored blank;
+
+list = {many:} id list |
+       {one:} id ;
diff --git a/contrib/nitcc/t/inf5000-05-grammaire-parentheses.input b/contrib/nitcc/t/inf5000-05-grammaire-parentheses.input
new file mode 100644 (file)
index 0000000..c9f3fcd
--- /dev/null
@@ -0,0 +1 @@
+((()))
diff --git a/contrib/nitcc/t/inf5000-05-grammaire-parentheses.sablecc b/contrib/nitcc/t/inf5000-05-grammaire-parentheses.sablecc
new file mode 100644 (file)
index 0000000..02b32a6
--- /dev/null
@@ -0,0 +1,9 @@
+Grammar parentheses;
+Lexer
+blank = ' ' | #9 | #10 | #13;
+
+Parser
+Ignored blank;
+
+par = {item:} '(' par ')' |
+      {empty:} '(' ')' ;
diff --git a/contrib/nitcc/t/inf5000-06-grammaire2-calculatrice.input b/contrib/nitcc/t/inf5000-06-grammaire2-calculatrice.input
new file mode 100644 (file)
index 0000000..bce0d8f
--- /dev/null
@@ -0,0 +1 @@
+1+2*(3+4)+5
diff --git a/contrib/nitcc/t/inf5000-06-grammaire2-calculatrice.sablecc b/contrib/nitcc/t/inf5000-06-grammaire2-calculatrice.sablecc
new file mode 100644 (file)
index 0000000..4b3d570
--- /dev/null
@@ -0,0 +1,15 @@
+Grammar calc;
+Lexer
+   int = ('0'..'9')+;
+   blank = ' ' | #9 | #10 | #13;
+
+Parser
+   Ignored blank;
+   exprs = expr*;
+   expr =
+      {add:} [left:]expr '+' [right:]expr |
+      {sub:} [left:]expr '-' [right:]expr |
+      {mul:} [left:]expr '*' [right:]expr |
+      {int:} int |
+      {par:} '(' expr ')' ;
+      Precedence Left mul; Left add, sub;
diff --git a/contrib/nitcc/t/inf5000-06-grammaire2-grammaire.input b/contrib/nitcc/t/inf5000-06-grammaire2-grammaire.input
new file mode 100644 (file)
index 0000000..9507760
--- /dev/null
@@ -0,0 +1,6 @@
+prods = {many:} prods prod  | {one:} prod ;
+prod = id '=' alts ';' ;
+alts = {many:} alts '|' alt | {one:} alt ;
+alt = altid atoms | atoms ;
+atoms = {many:} atoms atom | {none:} Empty;
+atom = {id:} id | {str:} str ;
diff --git a/contrib/nitcc/t/inf5000-06-grammaire2-grammaire.sablecc b/contrib/nitcc/t/inf5000-06-grammaire2-grammaire.sablecc
new file mode 100644 (file)
index 0000000..7aa1461
--- /dev/null
@@ -0,0 +1,15 @@
+Grammar grammaire;
+Lexer
+id = ('a'..'z')+;
+altid = '{' id ':}';
+str = '\'' (Any* - '\'') '\'';
+blank = ' ' | #9 | #10 | #13;
+
+Parser
+Ignored blank;
+prods = {many:} prods prod  | {one:} prod ;
+prod = id '=' alts ';' ;
+alts = {many:} alts '|' alt | {one:} alt ;
+alt = altid atoms | atoms ;
+atoms = {many:} atoms atom | {none:} ;
+atom = {id:} id | {str:} str ;
diff --git a/contrib/nitcc/t/inf5000-06-grammaire2-grammaire2.input b/contrib/nitcc/t/inf5000-06-grammaire2-grammaire2.input
new file mode 100644 (file)
index 0000000..9507760
--- /dev/null
@@ -0,0 +1,6 @@
+prods = {many:} prods prod  | {one:} prod ;
+prod = id '=' alts ';' ;
+alts = {many:} alts '|' alt | {one:} alt ;
+alt = altid atoms | atoms ;
+atoms = {many:} atoms atom | {none:} Empty;
+atom = {id:} id | {str:} str ;
diff --git a/contrib/nitcc/t/inf5000-06-grammaire2-grammaire2.sablecc b/contrib/nitcc/t/inf5000-06-grammaire2-grammaire2.sablecc
new file mode 100644 (file)
index 0000000..0f99f0c
--- /dev/null
@@ -0,0 +1,13 @@
+Grammar grammaire;
+Lexer
+id = ('a'..'z')+;
+altid = '{' id ':}';
+str = '\'' (Any* - '\'') '\'';
+blank = ' ' | #9 | #10 | #13;
+
+Parser
+Ignored blank;
+prods = prod+;
+prod = id '=' (alt Separator '|')+ ';' ;
+alt = altid? atom* ;
+atom = {id:} id | {str:} str ;
diff --git a/contrib/nitcc/t/inf5000-06-grammaire2-instructions.input b/contrib/nitcc/t/inf5000-06-grammaire2-instructions.input
new file mode 100644 (file)
index 0000000..5e77413
--- /dev/null
@@ -0,0 +1,2 @@
+x = y;
+while (z) { print(t); k=u; }
diff --git a/contrib/nitcc/t/inf5000-06-grammaire2-instructions.sablecc b/contrib/nitcc/t/inf5000-06-grammaire2-instructions.sablecc
new file mode 100644 (file)
index 0000000..c0cb7f7
--- /dev/null
@@ -0,0 +1,22 @@
+Grammar instuctions;
+Lexer
+id = ('a'..'z')+;
+blank = ' ' | #9 | #10 | #13;
+
+Parser
+Ignored blank;
+
+prog = stmt* ;
+stmt =
+  {assign:} id '=' expr ';' |
+  {print:} 'print' '(' expr ')' ';' |
+  {while:} 'while' '(' expr ')' '{' stmt* '}'
+//alt1 | {until:} 'do' '{' stmt* '}' 'until' '(' expr ')' ';'
+//alt2 | {if:} 'if' '('expr')' '{'stmt*'}' elsex?
+//alt3 | {call:} id '(' args ')' ';'
+  ;
+
+//alt2 elsex = 'else' '{' stmt* '}' ;
+//alt3 args = (expr Separator ',')* ;
+
+expr = id;
diff --git a/contrib/nitcc/t/inf5000-06-grammaire2-polygone.input b/contrib/nitcc/t/inf5000-06-grammaire2-polygone.input
new file mode 100644 (file)
index 0000000..23aa920
--- /dev/null
@@ -0,0 +1 @@
+((0x,0y), (10, 0deg), (0x, 10y))
diff --git a/contrib/nitcc/t/inf5000-06-grammaire2-polygone.sablecc b/contrib/nitcc/t/inf5000-06-grammaire2-polygone.sablecc
new file mode 100644 (file)
index 0000000..41b031b
--- /dev/null
@@ -0,0 +1,11 @@
+Grammar polygones;
+Lexer
+  num = ('0'..'9')+;
+  blank = ' ' | #9 | #10 | #13;
+
+Parser
+  Ignored blank;
+  polygone = '(' (point Separator ',')* ')' ;
+  point =
+    {cart:} '(' num 'x' ',' num 'y' ')' |
+    {pol:} '(' num ',' num 'deg' ')' ;
diff --git a/contrib/nitcc/t/lalr.sablecc b/contrib/nitcc/t/lalr.sablecc
new file mode 100644 (file)
index 0000000..a29e7ee
--- /dev/null
@@ -0,0 +1,5 @@
+Grammar lalr;
+Parser
+p = q 'a' | r 'b' ;
+q = 'x' ;
+r = 'x';
diff --git a/contrib/nitcc/t/lexer-c-comment.sablecc b/contrib/nitcc/t/lexer-c-comment.sablecc
new file mode 100644 (file)
index 0000000..c4f494a
--- /dev/null
@@ -0,0 +1,19 @@
+Grammar re;
+Lexer
+
+        notst = Any - '*';
+        notstsl = notst - '/';
+
+        com1 = '/*' (notst | '*'+ notstsl)* '*'+ '/';
+        com2 = '/*' notst* ('*' (notstsl notst*)?)* '*/'; //alt1 //alt2 //alt3 //alt4
+        //alt1 com2 = Shortest ('/*' Any* '*/');
+        //alt2 com2 = '/*' (Any* - '*/') '*/';
+        //alt3 com2 = '/*' (('' Lookahead Not '*/') Any)* '*/';
+        //alt4 com2 = '/*' (Any* Except (Any* '*/' Any*)) '*/';
+
+        dummy = notst | notstsl;
+
+Parser
+
+p = com1 | com2 | dummy;
+
diff --git a/contrib/nitcc/t/lexer-errors.sablecc b/contrib/nitcc/t/lexer-errors.sablecc
new file mode 100644 (file)
index 0000000..dd7290c
--- /dev/null
@@ -0,0 +1,15 @@
+Grammar re;
+Lexer
+
+        //alt1 a = '';
+        //alt2 a = 'a' - 'a';
+        //alt3 a = a;
+        //alt4 a = b; b = a;
+        //alt5 a = fail;
+        //alt6 a = 'a'; i = 'i';
+        //alt7 a = '' Lookahead 'a';
+        //alt8 a = 'a';
+
+Parser
+//alt8 Ignored fail;
+t = a;
diff --git a/contrib/nitcc/t/lexer-implicit-longest-and-priority.input b/contrib/nitcc/t/lexer-implicit-longest-and-priority.input
new file mode 100644 (file)
index 0000000..bf59612
--- /dev/null
@@ -0,0 +1 @@
+aabb
diff --git a/contrib/nitcc/t/lexer-implicit-longest-and-priority.sablecc b/contrib/nitcc/t/lexer-implicit-longest-and-priority.sablecc
new file mode 100644 (file)
index 0000000..07ad6ef
--- /dev/null
@@ -0,0 +1,10 @@
+Grammar re;
+Lexer
+a='a';
+anb='a' Lookahead Not 'b';
+ab='ab'; //alt1 ab='DUMMY';
+b='b';
+blank=#10|#13|#32;
+Parser
+Ignored blank;
+t = a | anb | ab | b;
diff --git a/contrib/nitcc/t/lexer-implicit-longest.input b/contrib/nitcc/t/lexer-implicit-longest.input
new file mode 100644 (file)
index 0000000..e170dc3
--- /dev/null
@@ -0,0 +1 @@
+ababac
diff --git a/contrib/nitcc/t/lexer-implicit-longest.sablecc b/contrib/nitcc/t/lexer-implicit-longest.sablecc
new file mode 100644 (file)
index 0000000..af88c9a
--- /dev/null
@@ -0,0 +1,8 @@
+Grammar re;
+Lexer
+a = 'a' Lookahead 'b'; //alt1 a = 'a'  Lookahead ('b'|'c');
+b = 'ab';
+blank = #10 | #13 | #32;
+Parser
+Ignored blank;
+t = a | b;
diff --git a/contrib/nitcc/t/lexer-markers.input b/contrib/nitcc/t/lexer-markers.input
new file mode 100644 (file)
index 0000000..5a69e17
--- /dev/null
@@ -0,0 +1 @@
+aabacaba
diff --git a/contrib/nitcc/t/lexer-markers.sablecc b/contrib/nitcc/t/lexer-markers.sablecc
new file mode 100644 (file)
index 0000000..24393c5
--- /dev/null
@@ -0,0 +1,10 @@
+Grammar re;
+Lexer
+a = 'a';
+b = 'a' 'b' 'a' 'c'; //alt1 //alt2
+//alt1 b = 'a' 'b' 'a'* 'c';
+//alt2 b = 'a'* 'b' 'a' 'c';
+blank = #10 | #13 | #32;
+Parser
+Ignored blank;
+t = a | b;
diff --git a/contrib/nitcc/t/lexer-precedences.input b/contrib/nitcc/t/lexer-precedences.input
new file mode 100644 (file)
index 0000000..b34225a
--- /dev/null
@@ -0,0 +1 @@
+aababa
diff --git a/contrib/nitcc/t/lexer-precedences.sablecc b/contrib/nitcc/t/lexer-precedences.sablecc
new file mode 100644 (file)
index 0000000..9401c25
--- /dev/null
@@ -0,0 +1,14 @@
+Grammar re;
+Lexer
+        //alt1,2,3 a = 'a'; b = 'a' | 'b' ;
+        //alt4,5 a = 'a' | 'c' ; b = 'a' | 'b' ;
+        //alt6,7 a = 'a' ; b = 'b' ;
+        //alt8 a = ('a' Lookahead 'b') | 'c'; b = 'a';
+        //alt9,10 a = 'a'; b = 'b';
+
+xa = a; xb =b; //alt2,5,7,10 xa = a ; xb = b - a; //Precedence a > b; //alt3 xa = a - b ; xb = b; //Precedence b > a;
+blank = #10 | #13;
+
+Parser
+Ignored blank;
+t = xa | xb;
diff --git a/contrib/nitcc/t/lexer-shortest-longest.input b/contrib/nitcc/t/lexer-shortest-longest.input
new file mode 100644 (file)
index 0000000..a9af52d
--- /dev/null
@@ -0,0 +1 @@
+abaaba
diff --git a/contrib/nitcc/t/lexer-shortest-longest.sablecc b/contrib/nitcc/t/lexer-shortest-longest.sablecc
new file mode 100644 (file)
index 0000000..c449061
--- /dev/null
@@ -0,0 +1,20 @@
+Grammar re;
+Lexer
+        a = 'a';
+        ab = 'ab';
+        a_ab = a | ab;
+        alb_ab = 'a' Lookahead Not 'b' | 'ab';
+        s = Shortest(a_ab);
+        l = Longest(a_ab);
+        dummy = 'x' (a|ab|alb_ab|s|l);
+       blank = #10 | #13 | #32; 
+
+Parser
+Ignored blank;
+        t = 
+        ab | l | //alt1
+//alt1        a | s |
+//alt2        a |
+//alt3        alb_ab |
+        dummy;
+
diff --git a/contrib/nitcc/t/lexer-shortest-longest2.input b/contrib/nitcc/t/lexer-shortest-longest2.input
new file mode 100644 (file)
index 0000000..6f27bcf
--- /dev/null
@@ -0,0 +1 @@
+aab
diff --git a/contrib/nitcc/t/lexer-shortest-longest2.sablecc b/contrib/nitcc/t/lexer-shortest-longest2.sablecc
new file mode 100644 (file)
index 0000000..45cff19
--- /dev/null
@@ -0,0 +1,12 @@
+Grammar re;
+Lexer
+a = 'a' 'b'?;
+la = Longest(a);
+sa = Shortest(a);
+sla = Shortest(la);
+dummy = 'X' (a|la|sa|sla);
+blank = #10 | #13 | #32;
+Parser
+Ignored blank;
+t = dummy |
+a | la; //alt1 a | sa; //alt2 a | sla; //alt3 la | sa; //alt4 la | sla;
diff --git a/contrib/nitcc/t/lexer_conflict_token.sablecc b/contrib/nitcc/t/lexer_conflict_token.sablecc
new file mode 100644 (file)
index 0000000..c4cc6e8
--- /dev/null
@@ -0,0 +1,10 @@
+Grammar lexer_conflict_token;
+
+Lexer
+
+a = 'a'|'x';
+b = 'b'|'x';
+
+Parser
+
+p = a | b;
diff --git a/contrib/nitcc/t/lexer_empty_token.sablecc b/contrib/nitcc/t/lexer_empty_token.sablecc
new file mode 100644 (file)
index 0000000..f053667
--- /dev/null
@@ -0,0 +1,10 @@
+Grammar lexer_empty_token;
+
+Lexer
+
+a= 'a'*;
+b= '';
+
+Parser
+
+p = a | b;
diff --git a/contrib/nitcc/t/lexer_features.input b/contrib/nitcc/t/lexer_features.input
new file mode 100644 (file)
index 0000000..8a72a2e
--- /dev/null
@@ -0,0 +1,5 @@
+i if iff ifff
+70
+zero
+0xFFff // unseen
+192.168.0.1
diff --git a/contrib/nitcc/t/lexer_features.input2 b/contrib/nitcc/t/lexer_features.input2
new file mode 100644 (file)
index 0000000..9a62de2
--- /dev/null
@@ -0,0 +1 @@
+10.5
diff --git a/contrib/nitcc/t/lr1.sablecc b/contrib/nitcc/t/lr1.sablecc
new file mode 100644 (file)
index 0000000..a995b61
--- /dev/null
@@ -0,0 +1,5 @@
+Grammar lr1;
+Parser
+p = q 'a' q 'b' | r 'a';
+q = 'x';
+r = 'x';
diff --git a/contrib/nitcc/t/modif.input1 b/contrib/nitcc/t/modif.input1
new file mode 100644 (file)
index 0000000..7ec9a4b
--- /dev/null
@@ -0,0 +1 @@
+aa
\ No newline at end of file
diff --git a/contrib/nitcc/t/modif.input2 b/contrib/nitcc/t/modif.input2
new file mode 100644 (file)
index 0000000..4063933
--- /dev/null
@@ -0,0 +1 @@
+abccbbcccdcba
\ No newline at end of file
diff --git a/contrib/nitcc/t/modif.input3 b/contrib/nitcc/t/modif.input3
new file mode 100644 (file)
index 0000000..28db331
--- /dev/null
@@ -0,0 +1 @@
+abba
\ No newline at end of file
diff --git a/contrib/nitcc/t/modif.input4 b/contrib/nitcc/t/modif.input4
new file mode 100644 (file)
index 0000000..2827b0f
--- /dev/null
@@ -0,0 +1 @@
+abcddcba
\ No newline at end of file
diff --git a/contrib/nitcc/t/modif.sablecc b/contrib/nitcc/t/modif.sablecc
new file mode 100644 (file)
index 0000000..47ef2b6
--- /dev/null
@@ -0,0 +1,8 @@
+Grammar modif;
+
+Parser
+
+p = 'a' q* 'a';
+q = 'b' r+ 'b';
+r = 'c' s? 'c';
+s = 'd';
diff --git a/contrib/nitcc/t/nit_expr.sablecc b/contrib/nitcc/t/nit_expr.sablecc
new file mode 100644 (file)
index 0000000..18d88fc
--- /dev/null
@@ -0,0 +1,11 @@
+Grammar nit_expr;
+Parser
+e =
+       e '[' e ']' |
+       '[' e ']' |
+       '[' e '..' e '[' |
+       '[' e '..' e ']' |
+       'id' e |
+       'id';
+       
+       
diff --git a/contrib/nitcc/t/not_lalr.sablecc b/contrib/nitcc/t/not_lalr.sablecc
new file mode 100644 (file)
index 0000000..7d4ca5d
--- /dev/null
@@ -0,0 +1,5 @@
+Grammar not_lalr;
+Parser
+p = 'a' x 'a' | 'a' y 'b' | 'b' y 'a' | 'b' x 'b' ;
+x = 'a';
+y = 'a';
diff --git a/contrib/nitcc/t/not_slr.sablecc b/contrib/nitcc/t/not_slr.sablecc
new file mode 100644 (file)
index 0000000..3096599
--- /dev/null
@@ -0,0 +1,7 @@
+Grammar not_slr;
+
+Parser
+
+s = g '=' d | d ;
+g = '*' d | 'id' ;
+d = g ;
diff --git a/contrib/nitcc/t/pri.sablecc b/contrib/nitcc/t/pri.sablecc
new file mode 100644 (file)
index 0000000..1106403
--- /dev/null
@@ -0,0 +1,7 @@
+Grammar pri;
+Parser
+a = 'p' p | 'q' q | 'r' r? ;
+p = p '+' p | 'p';
+q = q q | 'q' ;
+r = r2?;
+r2 = 'r';
diff --git a/contrib/nitcc/t/priority.sablecc b/contrib/nitcc/t/priority.sablecc
new file mode 100644 (file)
index 0000000..1fe549e
--- /dev/null
@@ -0,0 +1,7 @@
+Grammar priority;
+Parser
+e =
+       e '+' e |
+       e '-' e |
+       e '*' e |
+       '0' ;
diff --git a/contrib/nitcc/t/qualified.sablecc b/contrib/nitcc/t/qualified.sablecc
new file mode 100644 (file)
index 0000000..d3a13ed
--- /dev/null
@@ -0,0 +1,8 @@
+Grammar qualified;
+
+Parser
+       e = r q id;
+       r = e '.' | ;
+       q = qe+ | ;
+       qe = id '::' ;
+       id = 'id';
diff --git a/contrib/nitcc/t/run b/contrib/nitcc/t/run
new file mode 100755 (executable)
index 0000000..fbc7e8c
--- /dev/null
@@ -0,0 +1 @@
+./t "$@" *.sablecc ../examples/*.sablecc
diff --git a/contrib/nitcc/t/sav/calc.res b/contrib/nitcc/t/sav/calc.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/empty.alt1.res b/contrib/nitcc/t/sav/empty.alt1.res
new file mode 100644 (file)
index 0000000..7d3ae78
--- /dev/null
@@ -0,0 +1,2 @@
+* parse error in state Start on token Eof@(16:1-16:1)=''
+NParserError@(16:1-16:1)=''
diff --git a/contrib/nitcc/t/sav/empty.alt2.res b/contrib/nitcc/t/sav/empty.alt2.res
new file mode 100644 (file)
index 0000000..983984c
--- /dev/null
@@ -0,0 +1 @@
+Error: grammar with no production
diff --git a/contrib/nitcc/t/sav/empty.alt3.input.res b/contrib/nitcc/t/sav/empty.alt3.input.res
new file mode 100644 (file)
index 0000000..821fc27
--- /dev/null
@@ -0,0 +1 @@
+1,1. Syntax error: Unexpected character 'a'.
diff --git a/contrib/nitcc/t/sav/empty.alt3.input2.res b/contrib/nitcc/t/sav/empty.alt3.input2.res
new file mode 100644 (file)
index 0000000..d67f8e9
--- /dev/null
@@ -0,0 +1 @@
+TEnd@1,1:
diff --git a/contrib/nitcc/t/sav/empty.alt3.res b/contrib/nitcc/t/sav/empty.alt3.res
new file mode 100644 (file)
index 0000000..983984c
--- /dev/null
@@ -0,0 +1 @@
+Error: grammar with no production
diff --git a/contrib/nitcc/t/sav/empty.alt4.res b/contrib/nitcc/t/sav/empty.alt4.res
new file mode 100644 (file)
index 0000000..983984c
--- /dev/null
@@ -0,0 +1 @@
+Error: grammar with no production
diff --git a/contrib/nitcc/t/sav/empty.alt5.input.res b/contrib/nitcc/t/sav/empty.alt5.input.res
new file mode 100644 (file)
index 0000000..8088cc2
--- /dev/null
@@ -0,0 +1,2 @@
+T_A@1,1:a
+TEnd@1,2:
diff --git a/contrib/nitcc/t/sav/empty.alt5.input2.res b/contrib/nitcc/t/sav/empty.alt5.input2.res
new file mode 100644 (file)
index 0000000..d67f8e9
--- /dev/null
@@ -0,0 +1 @@
+TEnd@1,1:
diff --git a/contrib/nitcc/t/sav/empty.alt5.res b/contrib/nitcc/t/sav/empty.alt5.res
new file mode 100644 (file)
index 0000000..983984c
--- /dev/null
@@ -0,0 +1 @@
+Error: grammar with no production
diff --git a/contrib/nitcc/t/sav/empty.alt6.input.res b/contrib/nitcc/t/sav/empty.alt6.input.res
new file mode 100644 (file)
index 0000000..8088cc2
--- /dev/null
@@ -0,0 +1,2 @@
+T_A@1,1:a
+TEnd@1,2:
diff --git a/contrib/nitcc/t/sav/empty.alt6.input2.res b/contrib/nitcc/t/sav/empty.alt6.input2.res
new file mode 100644 (file)
index 0000000..d67f8e9
--- /dev/null
@@ -0,0 +1 @@
+TEnd@1,1:
diff --git a/contrib/nitcc/t/sav/empty.alt6.res b/contrib/nitcc/t/sav/empty.alt6.res
new file mode 100644 (file)
index 0000000..983984c
--- /dev/null
@@ -0,0 +1 @@
+Error: grammar with no production
diff --git a/contrib/nitcc/t/sav/empty.input.res b/contrib/nitcc/t/sav/empty.input.res
new file mode 100644 (file)
index 0000000..02b99f2
--- /dev/null
@@ -0,0 +1,2 @@
+NParserError@(1:2-1:2)=''
+Nodes
diff --git a/contrib/nitcc/t/sav/empty.input2.res b/contrib/nitcc/t/sav/empty.input2.res
new file mode 100644 (file)
index 0000000..f22973a
--- /dev/null
@@ -0,0 +1,2 @@
+NLexerError@(1:1-1:1)=''
+Nodes
diff --git a/contrib/nitcc/t/sav/empty.res b/contrib/nitcc/t/sav/empty.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/expression.res b/contrib/nitcc/t/sav/expression.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/if.res b/contrib/nitcc/t/sav/if.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/inf5000-04-lexer-automate.input.res b/contrib/nitcc/t/sav/inf5000-04-lexer-automate.input.res
new file mode 100644 (file)
index 0000000..11142bd
--- /dev/null
@@ -0,0 +1,46 @@
+Start
+  p
+    Nodes
+      t_1
+        if@(1:1-1:3)='if'
+      t_0
+        id@(1:4-1:7)='iff'
+      t_0
+        id@(1:8-1:11)='iff'
+      t_0
+        id@(1:12-1:13)='i'
+      t_0
+        id@(1:14-1:15)='f'
+      t_0
+        id@(2:1-2:6)='if50i'
+      t_1
+        if@(3:1-3:3)='if'
+      t_2
+        int@(3:4-3:6)='50'
+      t_0
+        id@(3:7-3:8)='i'
+      t_2
+        int@(4:1-4:3)='50'
+      t_3
+        float@(5:1-5:6)='50.50'
+      t_2
+        int@(6:1-6:3)='50'
+      t_4
+        dot@(6:3-6:4)='.'
+      t_4
+        dot@(7:1-7:2)='.'
+      t_2
+        int@(7:2-7:4)='50'
+      t_2
+        int@(8:1-8:3)='50'
+      t_4
+        dot@(8:3-8:4)='.'
+      t_0
+        id@(8:4-8:5)='f'
+      t_0
+        id@(9:1-9:2)='f'
+      t_4
+        dot@(9:2-9:3)='.'
+      t_2
+        int@(9:3-9:5)='50'
+  Eof@(10:1-10:1)=''
diff --git a/contrib/nitcc/t/sav/inf5000-04-lexer-automate.res b/contrib/nitcc/t/sav/inf5000-04-lexer-automate.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/inf5000-04-lexer-demo.input.res b/contrib/nitcc/t/sav/inf5000-04-lexer-demo.input.res
new file mode 100644 (file)
index 0000000..84152ca
--- /dev/null
@@ -0,0 +1,22 @@
+Start
+  p
+    Nodes
+      t_2
+        if@(1:1-1:3)='if'
+      t_0
+        identifier@(1:4-1:7)='iff'
+      t_0
+        identifier@(1:8-1:11)='iff'
+      t_0
+        identifier@(1:12-1:13)='i'
+      t_0
+        identifier@(1:14-1:15)='f'
+      t_0
+        identifier@(2:1-2:6)='if50i'
+      t_2
+        if@(3:1-3:3)='if'
+      t_1
+        comma@(3:3-3:4)=','
+      t_0
+        identifier@(3:4-3:5)='i'
+  Eof@(4:1-4:1)=''
diff --git a/contrib/nitcc/t/sav/inf5000-04-lexer-demo.input2.res b/contrib/nitcc/t/sav/inf5000-04-lexer-demo.input2.res
new file mode 100644 (file)
index 0000000..eaa2468
--- /dev/null
@@ -0,0 +1,3 @@
+NLexerError@(1:1-1:1)='5'
+Nodes
+  p
diff --git a/contrib/nitcc/t/sav/inf5000-04-lexer-demo.res b/contrib/nitcc/t/sav/inf5000-04-lexer-demo.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/inf5000-04-lexer-pire_cout.input.res b/contrib/nitcc/t/sav/inf5000-04-lexer-pire_cout.input.res
new file mode 100644 (file)
index 0000000..63d3f49
--- /dev/null
@@ -0,0 +1,6 @@
+Start
+  p
+    Nodes
+      t_1
+        b@(1:1-1:34)='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab'
+  Eof@(2:1-2:1)=''
diff --git a/contrib/nitcc/t/sav/inf5000-04-lexer-pire_cout.input2.res b/contrib/nitcc/t/sav/inf5000-04-lexer-pire_cout.input2.res
new file mode 100644 (file)
index 0000000..29e09b2
--- /dev/null
@@ -0,0 +1,68 @@
+Start
+  p
+    Nodes
+      t_0
+        a@(1:1-1:2)='a'
+      t_0
+        a@(1:2-1:3)='a'
+      t_0
+        a@(1:3-1:4)='a'
+      t_0
+        a@(1:4-1:5)='a'
+      t_0
+        a@(1:5-1:6)='a'
+      t_0
+        a@(1:6-1:7)='a'
+      t_0
+        a@(1:7-1:8)='a'
+      t_0
+        a@(1:8-1:9)='a'
+      t_0
+        a@(1:9-1:10)='a'
+      t_0
+        a@(1:10-1:11)='a'
+      t_0
+        a@(1:11-1:12)='a'
+      t_0
+        a@(1:12-1:13)='a'
+      t_0
+        a@(1:13-1:14)='a'
+      t_0
+        a@(1:14-1:15)='a'
+      t_0
+        a@(1:15-1:16)='a'
+      t_0
+        a@(1:16-1:17)='a'
+      t_0
+        a@(1:17-1:18)='a'
+      t_0
+        a@(1:18-1:19)='a'
+      t_0
+        a@(1:19-1:20)='a'
+      t_0
+        a@(1:20-1:21)='a'
+      t_0
+        a@(1:21-1:22)='a'
+      t_0
+        a@(1:22-1:23)='a'
+      t_0
+        a@(1:23-1:24)='a'
+      t_0
+        a@(1:24-1:25)='a'
+      t_0
+        a@(1:25-1:26)='a'
+      t_0
+        a@(1:26-1:27)='a'
+      t_0
+        a@(1:27-1:28)='a'
+      t_0
+        a@(1:28-1:29)='a'
+      t_0
+        a@(1:29-1:30)='a'
+      t_0
+        a@(1:30-1:31)='a'
+      t_0
+        a@(1:31-1:32)='a'
+      t_0
+        a@(1:32-1:33)='a'
+  Eof@(2:1-2:1)=''
diff --git a/contrib/nitcc/t/sav/inf5000-04-lexer-pire_cout.res b/contrib/nitcc/t/sav/inf5000-04-lexer-pire_cout.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/inf5000-04-lexer-priorite_d_inclusion.input.res b/contrib/nitcc/t/sav/inf5000-04-lexer-priorite_d_inclusion.input.res
new file mode 100644 (file)
index 0000000..e5baa77
--- /dev/null
@@ -0,0 +1,12 @@
+Start
+  p
+    Nodes
+      t_0
+        identifier@(1:1-1:2)='i'
+      t_0
+        identifier@(1:3-1:4)='f'
+      t_1
+        if@(2:1-2:3)='if'
+      t_0
+        identifier@(3:1-3:4)='ify'
+  Eof@(4:1-4:1)=''
diff --git a/contrib/nitcc/t/sav/inf5000-04-lexer-priorite_d_inclusion.res b/contrib/nitcc/t/sav/inf5000-04-lexer-priorite_d_inclusion.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/inf5000-04-lexer-priorite_declaree.input.res b/contrib/nitcc/t/sav/inf5000-04-lexer-priorite_declaree.input.res
new file mode 100644 (file)
index 0000000..057c58a
--- /dev/null
@@ -0,0 +1,6 @@
+T_Identifier@1,1:z10
+T_Hexinteger@2,1:00ff1
+T_Identifier@3,1:fff
+T_Hexinteger@4,1:00f
+T_Identifier@4,4:g1
+TEnd@5,1:
diff --git a/contrib/nitcc/t/sav/inf5000-04-lexer-priorite_declaree.res b/contrib/nitcc/t/sav/inf5000-04-lexer-priorite_declaree.res
new file mode 100644 (file)
index 0000000..284eee7
--- /dev/null
@@ -0,0 +1,2 @@
+* parse error in state 'Grammar' id ';' 'Lexer' id '=' re on token NLexerError@(6:34-6:34)='E'
+NLexerError@(6:34-6:34)='E'
diff --git a/contrib/nitcc/t/sav/inf5000-05-grammaire-arithmetique.alt1.res b/contrib/nitcc/t/sav/inf5000-05-grammaire-arithmetique.alt1.res
new file mode 100644 (file)
index 0000000..bb9f116
--- /dev/null
@@ -0,0 +1,2 @@
+* parse error in state grammar on token NLexerError@(16:1-16:2)='Pr'
+NLexerError@(16:1-16:2)='Pr'
diff --git a/contrib/nitcc/t/sav/inf5000-05-grammaire-arithmetique.input.res b/contrib/nitcc/t/sav/inf5000-05-grammaire-arithmetique.input.res
new file mode 100644 (file)
index 0000000..974aa14
--- /dev/null
@@ -0,0 +1,60 @@
+Start
+  exps
+    Nodes
+      exp_add
+        exp_int
+          int@(1:1-1:2)='5'
+        '+'@(1:3-1:4)
+        exp_mul
+          exp_int
+            int@(1:5-1:6)='4'
+          '*'@(1:7-1:8)
+          exp_int
+            int@(1:9-1:10)='2'
+      exp_min
+        exp_int
+          int@(2:1-2:2)='5'
+        '-'@(2:3-2:4)
+        exp_min
+          exp_int
+            int@(2:5-2:6)='4'
+          '-'@(2:7-2:8)
+          exp_int
+            int@(2:9-2:10)='2'
+      exp_add
+        exp_int
+          int@(3:1-3:2)='5'
+        '+'@(3:3-3:4)
+        exp_add
+          exp_int
+            int@(3:5-3:6)='4'
+          '+'@(3:7-3:8)
+          exp_int
+            int@(3:9-3:10)='2'
+      exp_mul
+        exp_par
+          '('@(4:1-4:2)
+          exp_add
+            exp_int
+              int@(4:2-4:3)='5'
+            '+'@(4:4-4:5)
+            exp_int
+              int@(4:6-4:7)='4'
+          ')'@(4:7-4:8)
+        '*'@(4:9-4:10)
+        exp_int
+          int@(4:11-4:12)='2'
+      exp_add
+        exp_int
+          int@(5:1-5:2)='5'
+        '+'@(5:3-5:4)
+        exp_par
+          '('@(5:5-5:6)
+          exp_mul
+            exp_int
+              int@(5:6-5:7)='4'
+            '*'@(5:8-5:9)
+            exp_int
+              int@(5:10-5:11)='2'
+          ')'@(5:11-5:12)
+  Eof@(6:1-6:1)=''
diff --git a/contrib/nitcc/t/sav/inf5000-05-grammaire-arithmetique.res b/contrib/nitcc/t/sav/inf5000-05-grammaire-arithmetique.res
new file mode 100644 (file)
index 0000000..05b05f7
--- /dev/null
@@ -0,0 +1 @@
+Error: there is conflicts
diff --git a/contrib/nitcc/t/sav/inf5000-05-grammaire-arithmetique2.input.res b/contrib/nitcc/t/sav/inf5000-05-grammaire-arithmetique2.input.res
new file mode 100644 (file)
index 0000000..0f4c052
--- /dev/null
@@ -0,0 +1,81 @@
+Start
+  exps
+    Nodes
+      exp_add
+        exp_factor
+          factor_term
+            term_int
+              int@(1:1-1:2)='5'
+        '+'@(1:3-1:4)
+        factor_mul
+          factor_term
+            term_int
+              int@(1:5-1:6)='4'
+          '*'@(1:7-1:8)
+          term_int
+            int@(1:9-1:10)='2'
+      exp_min
+        exp_min
+          exp_factor
+            factor_term
+              term_int
+                int@(2:1-2:2)='5'
+          '-'@(2:3-2:4)
+          factor_term
+            term_int
+              int@(2:5-2:6)='4'
+        '-'@(2:7-2:8)
+        factor_term
+          term_int
+            int@(2:9-2:10)='2'
+      exp_add
+        exp_add
+          exp_factor
+            factor_term
+              term_int
+                int@(3:1-3:2)='5'
+          '+'@(3:3-3:4)
+          factor_term
+            term_int
+              int@(3:5-3:6)='4'
+        '+'@(3:7-3:8)
+        factor_term
+          term_int
+            int@(3:9-3:10)='2'
+      exp_factor
+        factor_mul
+          factor_term
+            term_par
+              '('@(4:1-4:2)
+              exp_add
+                exp_factor
+                  factor_term
+                    term_int
+                      int@(4:2-4:3)='5'
+                '+'@(4:4-4:5)
+                factor_term
+                  term_int
+                    int@(4:6-4:7)='4'
+              ')'@(4:7-4:8)
+          '*'@(4:9-4:10)
+          term_int
+            int@(4:11-4:12)='2'
+      exp_add
+        exp_factor
+          factor_term
+            term_int
+              int@(5:1-5:2)='5'
+        '+'@(5:3-5:4)
+        factor_term
+          term_par
+            '('@(5:5-5:6)
+            exp_factor
+              factor_mul
+                factor_term
+                  term_int
+                    int@(5:6-5:7)='4'
+                '*'@(5:8-5:9)
+                term_int
+                  int@(5:10-5:11)='2'
+            ')'@(5:11-5:12)
+  Eof@(6:1-6:1)=''
diff --git a/contrib/nitcc/t/sav/inf5000-05-grammaire-arithmetique2.res b/contrib/nitcc/t/sav/inf5000-05-grammaire-arithmetique2.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/inf5000-05-grammaire-formes.input.res b/contrib/nitcc/t/sav/inf5000-05-grammaire-formes.input.res
new file mode 100644 (file)
index 0000000..f603e3b
--- /dev/null
@@ -0,0 +1,21 @@
+Start
+  forme_cercle
+    'centre'@(1:1-1:7)
+    point
+      '('@(1:8-1:9)
+      long
+        nombre@(1:9-1:10)='5'
+        unite_2
+          'pt'@(1:10-1:12)
+      ','@(1:12-1:13)
+      long
+        nombre@(1:14-1:15)='1'
+        unite_0
+          'cm'@(1:15-1:17)
+      ')'@(1:17-1:18)
+    'rayon'@(1:19-1:24)
+    long
+      nombre@(1:25-1:27)='10'
+      unite_3
+        'px'@(1:28-1:30)
+  Eof@(2:1-2:1)=''
diff --git a/contrib/nitcc/t/sav/inf5000-05-grammaire-formes.res b/contrib/nitcc/t/sav/inf5000-05-grammaire-formes.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/inf5000-05-grammaire-lisp.input.res b/contrib/nitcc/t/sav/inf5000-05-grammaire-lisp.input.res
new file mode 100644 (file)
index 0000000..1904ff6
--- /dev/null
@@ -0,0 +1,39 @@
+Start
+  item_par
+    '('@(1:1-1:2)
+    list_many
+      item_id
+        id@(1:2-1:5)='ida'
+      list_many
+        item_par
+          '('@(1:5-1:6)
+          list_many
+            item_id
+              id@(1:6-1:9)='idb'
+            list_one
+              item_id
+                id@(1:10-1:13)='idc'
+          ')'@(1:13-1:14)
+        list_many
+          item_par
+            '('@(1:14-1:15)
+            list_many
+              item_id
+                id@(1:15-1:18)='idd'
+              list_many
+                item_id
+                  id@(1:19-1:22)='ide'
+                list_one
+                  item_par
+                    '('@(1:22-1:23)
+                    list_one
+                      item_id
+                        id@(1:23-1:26)='idf'
+                    ')'@(1:26-1:27)
+            ')'@(1:27-1:28)
+          list_one
+            item_nil
+              '('@(1:28-1:29)
+              ')'@(1:29-1:30)
+    ')'@(1:30-1:31)
+  Eof@(2:1-2:1)=''
diff --git a/contrib/nitcc/t/sav/inf5000-05-grammaire-lisp.res b/contrib/nitcc/t/sav/inf5000-05-grammaire-lisp.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/inf5000-05-grammaire-listes.input.res b/contrib/nitcc/t/sav/inf5000-05-grammaire-listes.input.res
new file mode 100644 (file)
index 0000000..d658dae
--- /dev/null
@@ -0,0 +1,8 @@
+Start
+  list_many
+    id@(1:1-1:4)='ida'
+    list_many
+      id@(1:5-1:8)='idb'
+      list_one
+        id@(1:9-1:12)='idc'
+  Eof@(2:1-2:1)=''
diff --git a/contrib/nitcc/t/sav/inf5000-05-grammaire-listes.res b/contrib/nitcc/t/sav/inf5000-05-grammaire-listes.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/inf5000-05-grammaire-parentheses.input.res b/contrib/nitcc/t/sav/inf5000-05-grammaire-parentheses.input.res
new file mode 100644 (file)
index 0000000..65c805b
--- /dev/null
@@ -0,0 +1,11 @@
+Start
+  par_item
+    '('@(1:1-1:2)
+    par_item
+      '('@(1:2-1:3)
+      par_empty
+        '('@(1:3-1:4)
+        ')'@(1:4-1:5)
+      ')'@(1:5-1:6)
+    ')'@(1:6-1:7)
+  Eof@(2:1-2:1)=''
diff --git a/contrib/nitcc/t/sav/inf5000-05-grammaire-parentheses.res b/contrib/nitcc/t/sav/inf5000-05-grammaire-parentheses.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/inf5000-06-grammaire2-calculatrice.input.res b/contrib/nitcc/t/sav/inf5000-06-grammaire2-calculatrice.input.res
new file mode 100644 (file)
index 0000000..2b41938
--- /dev/null
@@ -0,0 +1,12 @@
+T_Int@1,1:1
+TAnonymous@1,2:+
+T_Int@1,3:2
+TAnonymous@1,4:*
+TAnonymous@1,5:(
+T_Int@1,6:3
+TAnonymous@1,7:+
+T_Int@1,8:4
+TAnonymous@1,9:)
+TAnonymous@1,10:+
+T_Int@1,11:5
+TEnd@2,1:
diff --git a/contrib/nitcc/t/sav/inf5000-06-grammaire2-calculatrice.res b/contrib/nitcc/t/sav/inf5000-06-grammaire2-calculatrice.res
new file mode 100644 (file)
index 0000000..afd46a2
--- /dev/null
@@ -0,0 +1,2 @@
+* parse error in state grammar on token NLexerError@(15:7-15:8)='Pr'
+NLexerError@(15:7-15:8)='Pr'
diff --git a/contrib/nitcc/t/sav/inf5000-06-grammaire2-grammaire.input.res b/contrib/nitcc/t/sav/inf5000-06-grammaire2-grammaire.input.res
new file mode 100644 (file)
index 0000000..1bddbfc
--- /dev/null
@@ -0,0 +1,109 @@
+NLexerError@(5:38-5:38)='E'
+Nodes
+  prods_many
+    prods_many
+      prods_many
+        prods_one
+          prod
+            id@(1:1-1:6)='prods'
+            '='@(1:7-1:8)
+            alts_many
+              alts_one
+                alt_0
+                  altid@(1:9-1:16)='{many:}'
+                  atoms_many
+                    atoms_many
+                      atoms_none
+                      atom_id
+                        id@(1:17-1:22)='prods'
+                    atom_id
+                      id@(1:23-1:27)='prod'
+              '|'@(1:29-1:30)
+              alt_0
+                altid@(1:31-1:37)='{one:}'
+                atoms_many
+                  atoms_none
+                  atom_id
+                    id@(1:38-1:42)='prod'
+            ';'@(1:43-1:44)
+        prod
+          id@(2:1-2:5)='prod'
+          '='@(2:6-2:7)
+          alts_one
+            alt_1
+              atoms_many
+                atoms_many
+                  atoms_many
+                    atoms_many
+                      atoms_none
+                      atom_id
+                        id@(2:8-2:10)='id'
+                    atom_str
+                      str@(2:11-2:14)='\'=\''
+                  atom_id
+                    id@(2:15-2:19)='alts'
+                atom_str
+                  str@(2:20-2:23)='\';\''
+          ';'@(2:24-2:25)
+      prod
+        id@(3:1-3:5)='alts'
+        '='@(3:6-3:7)
+        alts_many
+          alts_one
+            alt_0
+              altid@(3:8-3:15)='{many:}'
+              atoms_many
+                atoms_many
+                  atoms_many
+                    atoms_none
+                    atom_id
+                      id@(3:16-3:20)='alts'
+                  atom_str
+                    str@(3:21-3:24)='\'|\''
+                atom_id
+                  id@(3:25-3:28)='alt'
+          '|'@(3:29-3:30)
+          alt_0
+            altid@(3:31-3:37)='{one:}'
+            atoms_many
+              atoms_none
+              atom_id
+                id@(3:38-3:41)='alt'
+        ';'@(3:42-3:43)
+    prod
+      id@(4:1-4:4)='alt'
+      '='@(4:5-4:6)
+      alts_many
+        alts_one
+          alt_1
+            atoms_many
+              atoms_many
+                atoms_none
+                atom_id
+                  id@(4:7-4:12)='altid'
+              atom_id
+                id@(4:13-4:18)='atoms'
+        '|'@(4:19-4:20)
+        alt_1
+          atoms_many
+            atoms_none
+            atom_id
+              id@(4:21-4:26)='atoms'
+      ';'@(4:27-4:28)
+  id@(5:1-5:6)='atoms'
+  '='@(5:7-5:8)
+  alts_many
+    alts_one
+      alt_0
+        altid@(5:9-5:16)='{many:}'
+        atoms_many
+          atoms_many
+            atoms_none
+            atom_id
+              id@(5:17-5:22)='atoms'
+          atom_id
+            id@(5:23-5:27)='atom'
+    '|'@(5:28-5:29)
+    alt_0
+      altid@(5:30-5:37)='{none:}'
+      atoms_none
diff --git a/contrib/nitcc/t/sav/inf5000-06-grammaire2-grammaire.res b/contrib/nitcc/t/sav/inf5000-06-grammaire2-grammaire.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/inf5000-06-grammaire2-grammaire2.input.res b/contrib/nitcc/t/sav/inf5000-06-grammaire2-grammaire2.input.res
new file mode 100644 (file)
index 0000000..78e60f9
--- /dev/null
@@ -0,0 +1,41 @@
+T_Id@1,1:prods
+TAnonymous@1,7:=
+T_Altid@1,9:{many:}
+T_Id@1,17:prods
+T_Id@1,23:prod
+TAnonymous@1,29:|
+T_Altid@1,31:{one:}
+T_Id@1,38:prod
+TAnonymous@1,43:;
+T_Id@2,1:prod
+TAnonymous@2,6:=
+T_Id@2,8:id
+T_Str@2,11:'='
+T_Id@2,15:alts
+T_Str@2,20:';'
+TAnonymous@2,24:;
+T_Id@3,1:alts
+TAnonymous@3,6:=
+T_Altid@3,8:{many:}
+T_Id@3,16:alts
+T_Str@3,21:'|'
+T_Id@3,25:alt
+TAnonymous@3,29:|
+T_Altid@3,31:{one:}
+T_Id@3,38:alt
+TAnonymous@3,42:;
+T_Id@4,1:alt
+TAnonymous@4,5:=
+T_Id@4,7:altid
+T_Id@4,13:atoms
+TAnonymous@4,19:|
+T_Id@4,21:atoms
+TAnonymous@4,27:;
+T_Id@5,1:atoms
+TAnonymous@5,7:=
+T_Altid@5,9:{many:}
+T_Id@5,17:atoms
+T_Id@5,23:atom
+TAnonymous@5,28:|
+T_Altid@5,30:{none:}
+5,38. Syntax error: Unexpected character 'E'.
diff --git a/contrib/nitcc/t/sav/inf5000-06-grammaire2-grammaire2.res b/contrib/nitcc/t/sav/inf5000-06-grammaire2-grammaire2.res
new file mode 100644 (file)
index 0000000..c227e39
--- /dev/null
@@ -0,0 +1,2 @@
+* parse error in state 'Grammar' id ';' 'Parser' id '=' alts on token '('@(11:15-11:16)
+NParserError@(11:15-11:16)='('
diff --git a/contrib/nitcc/t/sav/inf5000-06-grammaire2-instructions.alt1.input.res b/contrib/nitcc/t/sav/inf5000-06-grammaire2-instructions.alt1.input.res
new file mode 100644 (file)
index 0000000..40503ba
--- /dev/null
@@ -0,0 +1,32 @@
+Start
+  prog
+    Nodes
+      stmt_assign
+        id@(1:1-1:2)='x'
+        '='@(1:3-1:4)
+        expr
+          id@(1:5-1:6)='y'
+        ';'@(1:6-1:7)
+      stmt_while
+        'while'@(2:1-2:6)
+        '('@(2:7-2:8)
+        expr
+          id@(2:8-2:9)='z'
+        ')'@(2:9-2:10)
+        '{'@(2:11-2:12)
+        Nodes
+          stmt_print
+            'print'@(2:13-2:18)
+            '('@(2:18-2:19)
+            expr
+              id@(2:19-2:20)='t'
+            ')'@(2:20-2:21)
+            ';'@(2:21-2:22)
+          stmt_assign
+            id@(2:23-2:24)='k'
+            '='@(2:24-2:25)
+            expr
+              id@(2:25-2:26)='u'
+            ';'@(2:26-2:27)
+        '}'@(2:28-2:29)
+  Eof@(3:1-3:1)=''
diff --git a/contrib/nitcc/t/sav/inf5000-06-grammaire2-instructions.alt1.res b/contrib/nitcc/t/sav/inf5000-06-grammaire2-instructions.alt1.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/inf5000-06-grammaire2-instructions.alt2.input.res b/contrib/nitcc/t/sav/inf5000-06-grammaire2-instructions.alt2.input.res
new file mode 100644 (file)
index 0000000..40503ba
--- /dev/null
@@ -0,0 +1,32 @@
+Start
+  prog
+    Nodes
+      stmt_assign
+        id@(1:1-1:2)='x'
+        '='@(1:3-1:4)
+        expr
+          id@(1:5-1:6)='y'
+        ';'@(1:6-1:7)
+      stmt_while
+        'while'@(2:1-2:6)
+        '('@(2:7-2:8)
+        expr
+          id@(2:8-2:9)='z'
+        ')'@(2:9-2:10)
+        '{'@(2:11-2:12)
+        Nodes
+          stmt_print
+            'print'@(2:13-2:18)
+            '('@(2:18-2:19)
+            expr
+              id@(2:19-2:20)='t'
+            ')'@(2:20-2:21)
+            ';'@(2:21-2:22)
+          stmt_assign
+            id@(2:23-2:24)='k'
+            '='@(2:24-2:25)
+            expr
+              id@(2:25-2:26)='u'
+            ';'@(2:26-2:27)
+        '}'@(2:28-2:29)
+  Eof@(3:1-3:1)=''
diff --git a/contrib/nitcc/t/sav/inf5000-06-grammaire2-instructions.alt2.res b/contrib/nitcc/t/sav/inf5000-06-grammaire2-instructions.alt2.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/inf5000-06-grammaire2-instructions.alt3.input.res b/contrib/nitcc/t/sav/inf5000-06-grammaire2-instructions.alt3.input.res
new file mode 100644 (file)
index 0000000..664d772
--- /dev/null
@@ -0,0 +1,18 @@
+T_Id@1,1:x
+TAnonymous@1,3:=
+T_Id@1,5:y
+TAnonymous@1,6:;
+TAnonymous@2,1:while
+TAnonymous@2,7:(
+T_Id@2,8:z
+TAnonymous@2,9:)
+TAnonymous@2,11:{
+TAnonymous@2,13:print
+T_Id@2,19:t
+TAnonymous@2,20:;
+T_Id@2,22:k
+TAnonymous@2,23:=
+T_Id@2,24:u
+TAnonymous@2,25:;
+TAnonymous@2,27:}
+TEnd@3,1:
diff --git a/contrib/nitcc/t/sav/inf5000-06-grammaire2-instructions.alt3.res b/contrib/nitcc/t/sav/inf5000-06-grammaire2-instructions.alt3.res
new file mode 100644 (file)
index 0000000..e3aa78f
--- /dev/null
@@ -0,0 +1,2 @@
+* parse error in state 'Grammar' id ';' 'Parser' id '=' alts on token '('@(20:8-20:9)
+NParserError@(20:8-20:9)='('
diff --git a/contrib/nitcc/t/sav/inf5000-06-grammaire2-instructions.input.res b/contrib/nitcc/t/sav/inf5000-06-grammaire2-instructions.input.res
new file mode 100644 (file)
index 0000000..40503ba
--- /dev/null
@@ -0,0 +1,32 @@
+Start
+  prog
+    Nodes
+      stmt_assign
+        id@(1:1-1:2)='x'
+        '='@(1:3-1:4)
+        expr
+          id@(1:5-1:6)='y'
+        ';'@(1:6-1:7)
+      stmt_while
+        'while'@(2:1-2:6)
+        '('@(2:7-2:8)
+        expr
+          id@(2:8-2:9)='z'
+        ')'@(2:9-2:10)
+        '{'@(2:11-2:12)
+        Nodes
+          stmt_print
+            'print'@(2:13-2:18)
+            '('@(2:18-2:19)
+            expr
+              id@(2:19-2:20)='t'
+            ')'@(2:20-2:21)
+            ';'@(2:21-2:22)
+          stmt_assign
+            id@(2:23-2:24)='k'
+            '='@(2:24-2:25)
+            expr
+              id@(2:25-2:26)='u'
+            ';'@(2:26-2:27)
+        '}'@(2:28-2:29)
+  Eof@(3:1-3:1)=''
diff --git a/contrib/nitcc/t/sav/inf5000-06-grammaire2-instructions.res b/contrib/nitcc/t/sav/inf5000-06-grammaire2-instructions.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/inf5000-06-grammaire2-polygone.input.res b/contrib/nitcc/t/sav/inf5000-06-grammaire2-polygone.input.res
new file mode 100644 (file)
index 0000000..4beb812
--- /dev/null
@@ -0,0 +1,10 @@
+TAnonymous@1,1:(
+TAnonymous@1,2:(
+T_Num@1,3:0
+TAnonymous@1,4:x
+TAnonymous@1,5:,
+T_Num@1,6:0
+TAnonymous@1,7:y
+TAnonymous@1,8:)
+TAnonymous@1,9:,
+1,10. Syntax error: Unexpected character ' '.
diff --git a/contrib/nitcc/t/sav/inf5000-06-grammaire2-polygone.res b/contrib/nitcc/t/sav/inf5000-06-grammaire2-polygone.res
new file mode 100644 (file)
index 0000000..8d7cebd
--- /dev/null
@@ -0,0 +1,2 @@
+* parse error in state 'Grammar' id ';' 'Parser' id '=' alts on token '('@(8:18-8:19)
+NParserError@(8:18-8:19)='('
diff --git a/contrib/nitcc/t/sav/json.res b/contrib/nitcc/t/sav/json.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/lalr.res b/contrib/nitcc/t/sav/lalr.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/lexer-c-comment.alt1.res b/contrib/nitcc/t/sav/lexer-c-comment.alt1.res
new file mode 100644 (file)
index 0000000..deece4b
--- /dev/null
@@ -0,0 +1,2 @@
+* parse error in state 'Grammar' id ';' 'Lexer' id '=' on token NLexerError@(9:16-9:16)='S'
+NLexerError@(9:16-9:16)='S'
diff --git a/contrib/nitcc/t/sav/lexer-c-comment.alt2.res b/contrib/nitcc/t/sav/lexer-c-comment.alt2.res
new file mode 100644 (file)
index 0000000..b835c24
--- /dev/null
@@ -0,0 +1 @@
+Not Yet Implemented Error: '-' only works on single char
diff --git a/contrib/nitcc/t/sav/lexer-c-comment.alt3.res b/contrib/nitcc/t/sav/lexer-c-comment.alt3.res
new file mode 100644 (file)
index 0000000..8cbbfa8
--- /dev/null
@@ -0,0 +1,2 @@
+* parse error in state 'Grammar' id ';' 'Lexer' id '=' '(' re on token NLexerError@(11:26-11:27)='Lo'
+NLexerError@(11:26-11:27)='Lo'
diff --git a/contrib/nitcc/t/sav/lexer-c-comment.alt4.res b/contrib/nitcc/t/sav/lexer-c-comment.alt4.res
new file mode 100644 (file)
index 0000000..d8fd238
--- /dev/null
@@ -0,0 +1,2 @@
+* parse error in state 'Grammar' id ';' 'Lexer' id '=' '(' re on token NLexerError@(12:27-12:27)='E'
+NLexerError@(12:27-12:27)='E'
diff --git a/contrib/nitcc/t/sav/lexer-c-comment.res b/contrib/nitcc/t/sav/lexer-c-comment.res
new file mode 100644 (file)
index 0000000..f66dc98
--- /dev/null
@@ -0,0 +1 @@
+ERROR: Conflicting tokens: com1 com2
diff --git a/contrib/nitcc/t/sav/lexer-errors.alt1.res b/contrib/nitcc/t/sav/lexer-errors.alt1.res
new file mode 100644 (file)
index 0000000..dc6af8c
--- /dev/null
@@ -0,0 +1 @@
+ERROR: Empty tokens a
diff --git a/contrib/nitcc/t/sav/lexer-errors.alt2.res b/contrib/nitcc/t/sav/lexer-errors.alt2.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/lexer-errors.alt3.res b/contrib/nitcc/t/sav/lexer-errors.alt3.res
new file mode 100644 (file)
index 0000000..6f17e3b
--- /dev/null
@@ -0,0 +1 @@
+Error: circular regular expression a.
diff --git a/contrib/nitcc/t/sav/lexer-errors.alt4.res b/contrib/nitcc/t/sav/lexer-errors.alt4.res
new file mode 100644 (file)
index 0000000..6f17e3b
--- /dev/null
@@ -0,0 +1 @@
+Error: circular regular expression a.
diff --git a/contrib/nitcc/t/sav/lexer-errors.alt5.res b/contrib/nitcc/t/sav/lexer-errors.alt5.res
new file mode 100644 (file)
index 0000000..38d2860
--- /dev/null
@@ -0,0 +1 @@
+Error: unknown name fail
diff --git a/contrib/nitcc/t/sav/lexer-errors.alt6.res b/contrib/nitcc/t/sav/lexer-errors.alt6.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/lexer-errors.alt7.res b/contrib/nitcc/t/sav/lexer-errors.alt7.res
new file mode 100644 (file)
index 0000000..88facbb
--- /dev/null
@@ -0,0 +1,2 @@
+* parse error in state 'Grammar' id ';' 'Lexer' id '=' re on token NLexerError@(10:16-10:17)='Lo'
+NLexerError@(10:16-10:17)='Lo'
diff --git a/contrib/nitcc/t/sav/lexer-errors.alt8.res b/contrib/nitcc/t/sav/lexer-errors.alt8.res
new file mode 100644 (file)
index 0000000..38d2860
--- /dev/null
@@ -0,0 +1 @@
+Error: unknown name fail
diff --git a/contrib/nitcc/t/sav/lexer-errors.res b/contrib/nitcc/t/sav/lexer-errors.res
new file mode 100644 (file)
index 0000000..866a8f6
--- /dev/null
@@ -0,0 +1 @@
+Error: unknown name a
diff --git a/contrib/nitcc/t/sav/lexer-implicit-longest-and-priority.alt1.input.res b/contrib/nitcc/t/sav/lexer-implicit-longest-and-priority.alt1.input.res
new file mode 100644 (file)
index 0000000..2b5621c
--- /dev/null
@@ -0,0 +1,5 @@
+T_Anb@1,1:a
+T_A@1,2:a
+T_B@1,3:b
+T_B@1,4:b
+TEnd@2,1:
diff --git a/contrib/nitcc/t/sav/lexer-implicit-longest-and-priority.alt1.res b/contrib/nitcc/t/sav/lexer-implicit-longest-and-priority.alt1.res
new file mode 100644 (file)
index 0000000..94e5458
--- /dev/null
@@ -0,0 +1,2 @@
+* parse error in state 'Grammar' id ';' 'Lexer' id '=' re on token NLexerError@(4:9-4:10)='Lo'
+NLexerError@(4:9-4:10)='Lo'
diff --git a/contrib/nitcc/t/sav/lexer-implicit-longest-and-priority.res b/contrib/nitcc/t/sav/lexer-implicit-longest-and-priority.res
new file mode 100644 (file)
index 0000000..94e5458
--- /dev/null
@@ -0,0 +1,2 @@
+* parse error in state 'Grammar' id ';' 'Lexer' id '=' re on token NLexerError@(4:9-4:10)='Lo'
+NLexerError@(4:9-4:10)='Lo'
diff --git a/contrib/nitcc/t/sav/lexer-implicit-longest.alt1.input.res b/contrib/nitcc/t/sav/lexer-implicit-longest.alt1.input.res
new file mode 100644 (file)
index 0000000..12dc63d
--- /dev/null
@@ -0,0 +1,4 @@
+T_B@1,1:ab
+T_B@1,3:ab
+T_A@1,5:a
+1,6. Syntax error: Unexpected character 'c'.
diff --git a/contrib/nitcc/t/sav/lexer-implicit-longest.alt1.res b/contrib/nitcc/t/sav/lexer-implicit-longest.alt1.res
new file mode 100644 (file)
index 0000000..d39b7be
--- /dev/null
@@ -0,0 +1,2 @@
+* parse error in state 'Grammar' id ';' 'Lexer' id '=' re on token NLexerError@(3:10-3:11)='Lo'
+NLexerError@(3:10-3:11)='Lo'
diff --git a/contrib/nitcc/t/sav/lexer-implicit-longest.res b/contrib/nitcc/t/sav/lexer-implicit-longest.res
new file mode 100644 (file)
index 0000000..b5b5d7b
--- /dev/null
@@ -0,0 +1,2 @@
+* parse error in state 'Grammar' id ';' 'Lexer' id '=' re on token NLexerError@(3:9-3:10)='Lo'
+NLexerError@(3:9-3:10)='Lo'
diff --git a/contrib/nitcc/t/sav/lexer-markers.alt1.input.res b/contrib/nitcc/t/sav/lexer-markers.alt1.input.res
new file mode 100644 (file)
index 0000000..32aae2f
--- /dev/null
@@ -0,0 +1,4 @@
+NParserError@(1:2-1:6)='abac'
+Nodes
+  t_0
+    a@(1:1-1:2)='a'
diff --git a/contrib/nitcc/t/sav/lexer-markers.alt1.res b/contrib/nitcc/t/sav/lexer-markers.alt1.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/lexer-markers.alt2.input.res b/contrib/nitcc/t/sav/lexer-markers.alt2.input.res
new file mode 100644 (file)
index 0000000..d0d504b
--- /dev/null
@@ -0,0 +1,4 @@
+NParserError@(1:6-1:7)='a'
+Nodes
+  t_1
+    b@(1:1-1:6)='aabac'
diff --git a/contrib/nitcc/t/sav/lexer-markers.alt2.res b/contrib/nitcc/t/sav/lexer-markers.alt2.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/lexer-markers.input.res b/contrib/nitcc/t/sav/lexer-markers.input.res
new file mode 100644 (file)
index 0000000..32aae2f
--- /dev/null
@@ -0,0 +1,4 @@
+NParserError@(1:2-1:6)='abac'
+Nodes
+  t_0
+    a@(1:1-1:2)='a'
diff --git a/contrib/nitcc/t/sav/lexer-markers.res b/contrib/nitcc/t/sav/lexer-markers.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/lexer-precedences.alt1.input.res b/contrib/nitcc/t/sav/lexer-precedences.alt1.input.res
new file mode 100644 (file)
index 0000000..4b0c2ea
--- /dev/null
@@ -0,0 +1,4 @@
+NParserError@(1:2-1:3)='a'
+Nodes
+  t_0
+    xa@(1:1-1:2)='a'
diff --git a/contrib/nitcc/t/sav/lexer-precedences.alt1.res b/contrib/nitcc/t/sav/lexer-precedences.alt1.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/lexer-precedences.alt10.input.res b/contrib/nitcc/t/sav/lexer-precedences.alt10.input.res
new file mode 100644 (file)
index 0000000..4b0c2ea
--- /dev/null
@@ -0,0 +1,4 @@
+NParserError@(1:2-1:3)='a'
+Nodes
+  t_0
+    xa@(1:1-1:2)='a'
diff --git a/contrib/nitcc/t/sav/lexer-precedences.alt10.res b/contrib/nitcc/t/sav/lexer-precedences.alt10.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/lexer-precedences.alt2.input.res b/contrib/nitcc/t/sav/lexer-precedences.alt2.input.res
new file mode 100644 (file)
index 0000000..4b0c2ea
--- /dev/null
@@ -0,0 +1,4 @@
+NParserError@(1:2-1:3)='a'
+Nodes
+  t_0
+    xa@(1:1-1:2)='a'
diff --git a/contrib/nitcc/t/sav/lexer-precedences.alt2.res b/contrib/nitcc/t/sav/lexer-precedences.alt2.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/lexer-precedences.alt3.input.res b/contrib/nitcc/t/sav/lexer-precedences.alt3.input.res
new file mode 100644 (file)
index 0000000..ab653e5
--- /dev/null
@@ -0,0 +1,4 @@
+NParserError@(1:2-1:3)='a'
+Nodes
+  t_1
+    xb@(1:1-1:2)='a'
diff --git a/contrib/nitcc/t/sav/lexer-precedences.alt3.res b/contrib/nitcc/t/sav/lexer-precedences.alt3.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/lexer-precedences.alt4.input.res b/contrib/nitcc/t/sav/lexer-precedences.alt4.input.res
new file mode 100644 (file)
index 0000000..4b0c2ea
--- /dev/null
@@ -0,0 +1,4 @@
+NParserError@(1:2-1:3)='a'
+Nodes
+  t_0
+    xa@(1:1-1:2)='a'
diff --git a/contrib/nitcc/t/sav/lexer-precedences.alt4.res b/contrib/nitcc/t/sav/lexer-precedences.alt4.res
new file mode 100644 (file)
index 0000000..6a70780
--- /dev/null
@@ -0,0 +1 @@
+ERROR: Conflicting tokens: xa xb
diff --git a/contrib/nitcc/t/sav/lexer-precedences.alt5.input.res b/contrib/nitcc/t/sav/lexer-precedences.alt5.input.res
new file mode 100644 (file)
index 0000000..4b0c2ea
--- /dev/null
@@ -0,0 +1,4 @@
+NParserError@(1:2-1:3)='a'
+Nodes
+  t_0
+    xa@(1:1-1:2)='a'
diff --git a/contrib/nitcc/t/sav/lexer-precedences.alt5.res b/contrib/nitcc/t/sav/lexer-precedences.alt5.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/lexer-precedences.alt6.input.res b/contrib/nitcc/t/sav/lexer-precedences.alt6.input.res
new file mode 100644 (file)
index 0000000..4b0c2ea
--- /dev/null
@@ -0,0 +1,4 @@
+NParserError@(1:2-1:3)='a'
+Nodes
+  t_0
+    xa@(1:1-1:2)='a'
diff --git a/contrib/nitcc/t/sav/lexer-precedences.alt6.res b/contrib/nitcc/t/sav/lexer-precedences.alt6.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/lexer-precedences.alt7.input.res b/contrib/nitcc/t/sav/lexer-precedences.alt7.input.res
new file mode 100644 (file)
index 0000000..4b0c2ea
--- /dev/null
@@ -0,0 +1,4 @@
+NParserError@(1:2-1:3)='a'
+Nodes
+  t_0
+    xa@(1:1-1:2)='a'
diff --git a/contrib/nitcc/t/sav/lexer-precedences.alt7.res b/contrib/nitcc/t/sav/lexer-precedences.alt7.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/lexer-precedences.alt8.res b/contrib/nitcc/t/sav/lexer-precedences.alt8.res
new file mode 100644 (file)
index 0000000..c7cef22
--- /dev/null
@@ -0,0 +1,2 @@
+* parse error in state 'Grammar' id ';' 'Lexer' id '=' '(' re on token NLexerError@(6:18-6:19)='Lo'
+NLexerError@(6:18-6:19)='Lo'
diff --git a/contrib/nitcc/t/sav/lexer-precedences.alt9.input.res b/contrib/nitcc/t/sav/lexer-precedences.alt9.input.res
new file mode 100644 (file)
index 0000000..4b0c2ea
--- /dev/null
@@ -0,0 +1,4 @@
+NParserError@(1:2-1:3)='a'
+Nodes
+  t_0
+    xa@(1:1-1:2)='a'
diff --git a/contrib/nitcc/t/sav/lexer-precedences.alt9.res b/contrib/nitcc/t/sav/lexer-precedences.alt9.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/lexer-precedences.res b/contrib/nitcc/t/sav/lexer-precedences.res
new file mode 100644 (file)
index 0000000..866a8f6
--- /dev/null
@@ -0,0 +1 @@
+Error: unknown name a
diff --git a/contrib/nitcc/t/sav/lexer-shortest-longest.alt1.res b/contrib/nitcc/t/sav/lexer-shortest-longest.alt1.res
new file mode 100644 (file)
index 0000000..0e9fe66
--- /dev/null
@@ -0,0 +1,2 @@
+* parse error in state 'Grammar' id ';' 'Lexer' id '=' re on token NLexerError@(6:22-6:23)='Lo'
+NLexerError@(6:22-6:23)='Lo'
diff --git a/contrib/nitcc/t/sav/lexer-shortest-longest.alt2.res b/contrib/nitcc/t/sav/lexer-shortest-longest.alt2.res
new file mode 100644 (file)
index 0000000..0e9fe66
--- /dev/null
@@ -0,0 +1,2 @@
+* parse error in state 'Grammar' id ';' 'Lexer' id '=' re on token NLexerError@(6:22-6:23)='Lo'
+NLexerError@(6:22-6:23)='Lo'
diff --git a/contrib/nitcc/t/sav/lexer-shortest-longest.alt3.res b/contrib/nitcc/t/sav/lexer-shortest-longest.alt3.res
new file mode 100644 (file)
index 0000000..0e9fe66
--- /dev/null
@@ -0,0 +1,2 @@
+* parse error in state 'Grammar' id ';' 'Lexer' id '=' re on token NLexerError@(6:22-6:23)='Lo'
+NLexerError@(6:22-6:23)='Lo'
diff --git a/contrib/nitcc/t/sav/lexer-shortest-longest.input.res b/contrib/nitcc/t/sav/lexer-shortest-longest.input.res
new file mode 100644 (file)
index 0000000..87a3bbb
--- /dev/null
@@ -0,0 +1,5 @@
+T_Ab@1,1:ab
+T_L@1,3:a
+T_Ab@1,4:ab
+T_L@1,6:a
+TEnd@2,1:
diff --git a/contrib/nitcc/t/sav/lexer-shortest-longest.res b/contrib/nitcc/t/sav/lexer-shortest-longest.res
new file mode 100644 (file)
index 0000000..0e9fe66
--- /dev/null
@@ -0,0 +1,2 @@
+* parse error in state 'Grammar' id ';' 'Lexer' id '=' re on token NLexerError@(6:22-6:23)='Lo'
+NLexerError@(6:22-6:23)='Lo'
diff --git a/contrib/nitcc/t/sav/lexer-shortest-longest2.alt1.input.res b/contrib/nitcc/t/sav/lexer-shortest-longest2.alt1.input.res
new file mode 100644 (file)
index 0000000..c0167f1
--- /dev/null
@@ -0,0 +1,3 @@
+T_Sa@1,1:a
+T_A@1,2:ab
+TEnd@2,1:
diff --git a/contrib/nitcc/t/sav/lexer-shortest-longest2.alt1.res b/contrib/nitcc/t/sav/lexer-shortest-longest2.alt1.res
new file mode 100644 (file)
index 0000000..81db0c3
--- /dev/null
@@ -0,0 +1,2 @@
+* parse error in state 'Grammar' id ';' 'Lexer' id '=' on token NLexerError@(4:6-4:7)='Lo'
+NLexerError@(4:6-4:7)='Lo'
diff --git a/contrib/nitcc/t/sav/lexer-shortest-longest2.alt2.res b/contrib/nitcc/t/sav/lexer-shortest-longest2.alt2.res
new file mode 100644 (file)
index 0000000..81db0c3
--- /dev/null
@@ -0,0 +1,2 @@
+* parse error in state 'Grammar' id ';' 'Lexer' id '=' on token NLexerError@(4:6-4:7)='Lo'
+NLexerError@(4:6-4:7)='Lo'
diff --git a/contrib/nitcc/t/sav/lexer-shortest-longest2.alt3.input.res b/contrib/nitcc/t/sav/lexer-shortest-longest2.alt3.input.res
new file mode 100644 (file)
index 0000000..32655e1
--- /dev/null
@@ -0,0 +1,3 @@
+T_Sa@1,1:a
+T_La@1,2:ab
+TEnd@2,1:
diff --git a/contrib/nitcc/t/sav/lexer-shortest-longest2.alt3.res b/contrib/nitcc/t/sav/lexer-shortest-longest2.alt3.res
new file mode 100644 (file)
index 0000000..81db0c3
--- /dev/null
@@ -0,0 +1,2 @@
+* parse error in state 'Grammar' id ';' 'Lexer' id '=' on token NLexerError@(4:6-4:7)='Lo'
+NLexerError@(4:6-4:7)='Lo'
diff --git a/contrib/nitcc/t/sav/lexer-shortest-longest2.alt4.res b/contrib/nitcc/t/sav/lexer-shortest-longest2.alt4.res
new file mode 100644 (file)
index 0000000..81db0c3
--- /dev/null
@@ -0,0 +1,2 @@
+* parse error in state 'Grammar' id ';' 'Lexer' id '=' on token NLexerError@(4:6-4:7)='Lo'
+NLexerError@(4:6-4:7)='Lo'
diff --git a/contrib/nitcc/t/sav/lexer-shortest-longest2.res b/contrib/nitcc/t/sav/lexer-shortest-longest2.res
new file mode 100644 (file)
index 0000000..81db0c3
--- /dev/null
@@ -0,0 +1,2 @@
+* parse error in state 'Grammar' id ';' 'Lexer' id '=' on token NLexerError@(4:6-4:7)='Lo'
+NLexerError@(4:6-4:7)='Lo'
diff --git a/contrib/nitcc/t/sav/lexer_conflict_token.res b/contrib/nitcc/t/sav/lexer_conflict_token.res
new file mode 100644 (file)
index 0000000..438487c
--- /dev/null
@@ -0,0 +1 @@
+ERROR: Conflicting tokens: a b
diff --git a/contrib/nitcc/t/sav/lexer_empty_token.res b/contrib/nitcc/t/sav/lexer_empty_token.res
new file mode 100644 (file)
index 0000000..a22914d
--- /dev/null
@@ -0,0 +1 @@
+ERROR: Empty tokens b a
diff --git a/contrib/nitcc/t/sav/lexer_features.input.res b/contrib/nitcc/t/sav/lexer_features.input.res
new file mode 100644 (file)
index 0000000..ecd49a8
--- /dev/null
@@ -0,0 +1,9 @@
+T_Identifier@1,1:i
+TAnonymous@1,3:if
+T_Identifier@1,6:iff
+T_Identifier@1,10:ifff
+T_Decimal@2,1:70
+T_Zero@3,1:zero
+T_Hex@4,1:0xFFff
+T_IpAddress@5,1:192.168.0.1
+TEnd@6,1:
diff --git a/contrib/nitcc/t/sav/lexer_features.input2.res b/contrib/nitcc/t/sav/lexer_features.input2.res
new file mode 100644 (file)
index 0000000..7f02009
--- /dev/null
@@ -0,0 +1,2 @@
+T_Decimal@1,1:10
+1,3. Syntax error: Unexpected character '.'.
diff --git a/contrib/nitcc/t/sav/lexer_features.res b/contrib/nitcc/t/sav/lexer_features.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/lr1.res b/contrib/nitcc/t/sav/lr1.res
new file mode 100644 (file)
index 0000000..05b05f7
--- /dev/null
@@ -0,0 +1 @@
+Error: there is conflicts
diff --git a/contrib/nitcc/t/sav/minilang.res b/contrib/nitcc/t/sav/minilang.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/mixed_list.res b/contrib/nitcc/t/sav/mixed_list.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/modif.input1.res b/contrib/nitcc/t/sav/modif.input1.res
new file mode 100644 (file)
index 0000000..3f7ce7d
--- /dev/null
@@ -0,0 +1,5 @@
+Start
+  p
+    'a'@(1:1-1:2)
+    'a'@(1:2-1:3)
+  Eof@(1:3-1:3)=''
diff --git a/contrib/nitcc/t/sav/modif.input2.res b/contrib/nitcc/t/sav/modif.input2.res
new file mode 100644 (file)
index 0000000..3a89b3e
--- /dev/null
@@ -0,0 +1,25 @@
+Start
+  p
+    'a'@(1:1-1:2)
+    Nodes
+      q
+        'b'@(1:2-1:3)
+        Nodes
+          r
+            'c'@(1:3-1:4)
+            'c'@(1:4-1:5)
+        'b'@(1:5-1:6)
+      q
+        'b'@(1:6-1:7)
+        Nodes
+          r
+            'c'@(1:7-1:8)
+            'c'@(1:8-1:9)
+          r
+            'c'@(1:9-1:10)
+            s
+              'd'@(1:10-1:11)
+            'c'@(1:11-1:12)
+        'b'@(1:12-1:13)
+    'a'@(1:13-1:14)
+  Eof@(1:14-1:14)=''
diff --git a/contrib/nitcc/t/sav/modif.input3.res b/contrib/nitcc/t/sav/modif.input3.res
new file mode 100644 (file)
index 0000000..efaf7c5
--- /dev/null
@@ -0,0 +1,4 @@
+NParserError@(1:3-1:4)='b'
+Nodes
+  'a'@(1:1-1:2)
+  'b'@(1:2-1:3)
diff --git a/contrib/nitcc/t/sav/modif.input4.res b/contrib/nitcc/t/sav/modif.input4.res
new file mode 100644 (file)
index 0000000..c333c96
--- /dev/null
@@ -0,0 +1,7 @@
+NParserError@(1:5-1:6)='d'
+Nodes
+  'a'@(1:1-1:2)
+  'b'@(1:2-1:3)
+  'c'@(1:3-1:4)
+  s
+    'd'@(1:4-1:5)
diff --git a/contrib/nitcc/t/sav/modif.res b/contrib/nitcc/t/sav/modif.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/nit_expr.res b/contrib/nitcc/t/sav/nit_expr.res
new file mode 100644 (file)
index 0000000..05b05f7
--- /dev/null
@@ -0,0 +1 @@
+Error: there is conflicts
diff --git a/contrib/nitcc/t/sav/not_lalr.res b/contrib/nitcc/t/sav/not_lalr.res
new file mode 100644 (file)
index 0000000..05b05f7
--- /dev/null
@@ -0,0 +1 @@
+Error: there is conflicts
diff --git a/contrib/nitcc/t/sav/not_slr.res b/contrib/nitcc/t/sav/not_slr.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/pri.res b/contrib/nitcc/t/sav/pri.res
new file mode 100644 (file)
index 0000000..05b05f7
--- /dev/null
@@ -0,0 +1 @@
+Error: there is conflicts
diff --git a/contrib/nitcc/t/sav/priority.res b/contrib/nitcc/t/sav/priority.res
new file mode 100644 (file)
index 0000000..05b05f7
--- /dev/null
@@ -0,0 +1 @@
+Error: there is conflicts
diff --git a/contrib/nitcc/t/sav/qualified.res b/contrib/nitcc/t/sav/qualified.res
new file mode 100644 (file)
index 0000000..05b05f7
--- /dev/null
@@ -0,0 +1 @@
+Error: there is conflicts
diff --git a/contrib/nitcc/t/sav/trans.input.res b/contrib/nitcc/t/sav/trans.input.res
new file mode 100644 (file)
index 0000000..ee9a31b
--- /dev/null
@@ -0,0 +1,7 @@
+'x'@(1:1-1:2)
+'x'@(1:2-1:3)
+'y'@(1:3-1:4)
+'y'@(1:4-1:5)
+'x'@(1:5-1:6)
+'y'@(1:6-1:7)
+NLexerError@(1:7-1:7)='\n'
diff --git a/contrib/nitcc/t/sav/trans.res b/contrib/nitcc/t/sav/trans.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/sav/trans_inline.input.res b/contrib/nitcc/t/sav/trans_inline.input.res
new file mode 100644 (file)
index 0000000..67e695f
--- /dev/null
@@ -0,0 +1,7 @@
+'a'@(1:1-1:2)
+'b'@(1:2-1:3)
+'x'@(1:3-1:4)
+'y'@(1:4-1:5)
+'c'@(1:5-1:6)
+'d'@(1:6-1:7)
+NLexerError@(1:7-1:7)='\n'
diff --git a/contrib/nitcc/t/sav/trans_inline.res b/contrib/nitcc/t/sav/trans_inline.res
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/contrib/nitcc/t/t b/contrib/nitcc/t/t
new file mode 100755 (executable)
index 0000000..14669a6
--- /dev/null
@@ -0,0 +1,139 @@
+#!/bin/bash
+
+# This file is part of Nit ( http://nitlanguage.org ).
+#
+# See the NOTICE file distributed with this work for copyright information.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This program is used to perform regression tests of nitcc.
+
+NITCC=../nitcc
+NITC=../../../bin/nitc
+
+mkdir alt out 2>/dev/null
+
+if test "x$#" = "x0"
+then
+        echo usage: `basename $0` [-v] grammar-files*
+        exit
+fi
+
+
+verbose=false
+stop=false
+while [ $stop = false ]; do
+        case $1 in
+                -v) verbose=true; shift;;
+                *) stop=true
+        esac
+done
+
+# empty tap output
+tap="tap.output"
+>"$tap"
+tapcount=0
+
+differ() {
+       tapcount=$((tapcount + 1))
+        r="$1"
+        if test \! -f "sav/$r"
+        then
+                if test -s "out/$r"
+                then
+                        echo "[***no sav***] cp 'out/$r' sav/"
+                        test $verbose = true && { cat "out/$r" ; echo ; }
+                       echo >>"$tap" "not ok $tapcount - $name # TODO no sav"
+                else
+                        echo "[0K]"
+                       echo >>"$tap" "ok $tapcount - $name"
+                fi
+        elif diff "sav/$r" "out/$r" >/dev/null
+        then
+                echo "[OK]"
+               echo >>"$tap" "ok $tapcount - $name"
+        else
+                echo "[******failed******] diff -u {sav,out}/$r"
+                test $verbose = true && { diff -u "sav/$r" "out/$r" ; echo ; }
+               echo >>"$tap" "not ok $tapcount - $name"
+        fi
+}
+
+for f in "$@"
+do
+        for a in "$f" `./alterner.pl $f`
+        do
+                cla=""
+               langname=""
+                echo -n "* $a: "
+               bn=`basename "$a" .sablecc`
+                res="$bn".res
+                $NITCC "$a" >"out/$bn.nitcc.log" 2>&1
+                if test $? != 0
+                then
+                        echo -n "!nitcc "
+               else
+                       t=`grep -o '[^ ]*_test_parser' < "out/$bn.nitcc.log"`
+                       if test -f "${t}.nit"
+                       then
+                               echo -n ". "
+                               $NITC -I .. "${t}.nit" >/dev/null 2>&1
+                               if test $? != 0
+                               then
+                                       echo -n "!nitc "
+                               else
+                                       echo -n ". "
+                                       cla="${t}"
+                                       langname="${t/_test_parser}"
+                               fi
+                       else
+                               echo -n "!res "
+                               echo
+                               tapcount=$((tapcount + 1))
+                               echo >>"$tap" "not ok $tapcount - $a # TODO no res"
+                               continue
+                       fi
+               fi
+
+               grep -i "error" "out/$bn.nitcc.log" > "out/$res"
+               name="$a"
+                differ $res
+
+                if test \! -z $cla
+                then
+                        bf=`basename "$f" .sablecc`
+                        for i in "$bf".input*
+                        do
+                                test -f $i || { echo "   - no input: $i" ; continue ; }
+                                ni=${i#$bf}
+                                resi="$bn$ni".res
+                               rm "$langname.ast.out" 2>/dev/null
+                                echo -n "  - $i: "
+                                ./"$cla" "$i" > "out/$bn.$ni.log"
+                                if test $? != 0
+                                then
+                                        echo -n "!run "
+                                else
+                                        echo -n ". "
+                                fi
+
+                               cp "$langname.ast.out" "out/$resi"
+                               name="$a $i"
+                                differ "$resi"
+                        done
+                fi
+        done
+done
+
+echo >>"$tap" "1..$tapcount"
+#prove --formatter=TAP::Formatter::JUnit /bin/cat :: tap.output > tap.xml
diff --git a/contrib/nitcc/t/trans.sablecc b/contrib/nitcc/t/trans.sablecc
new file mode 100644 (file)
index 0000000..494e866
--- /dev/null
@@ -0,0 +1,7 @@
+Grammar trans;
+
+Parser
+
+a = a a2 | a2;
+a2 {-> a} = 'x' | a3 {-> a3};
+a3 {-> a} = 'y';
diff --git a/contrib/nitcc/t/trans_inline.sablecc b/contrib/nitcc/t/trans_inline.sablecc
new file mode 100644 (file)
index 0000000..b380d65
--- /dev/null
@@ -0,0 +1,6 @@
+Grammar trans_inline;
+
+Parser
+
+p = 'a' 'b' q_inline 'c' 'd' ;
+q_inline = 'x' 'y' ;