Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/incubator-corinthia
diff --git a/experiments/flat/grammars/arithmetic.flat b/experiments/flat/grammars/arithmetic.flat
new file mode 100644
index 0000000..6f9c1e1
--- /dev/null
+++ b/experiments/flat/grammars/arithmetic.flat
@@ -0,0 +1,22 @@
+# Note: The Term and Factor rules are right recursive. They are actually
+# supposed to be left recursive, but we don't support that yet.
+Start   : Expr !.;
+Expr    : Term;
+Term    : $Add(Factor PLUS Term)
+        | $Sub(Factor MINUS Term)
+        | Factor;
+Factor  : $Mul(Primary TIMES Factor)
+        | $Div(Primary SLASH Factor)
+        | Primary;
+Primary : $Ident(ID)
+        | $Integer(INT)
+        | OPEN Expr CLOSE;
+PLUS    : "+" Spacing;
+MINUS   : "-" Spacing;
+TIMES   : "*" Spacing;
+SLASH   : "/" Spacing;
+OPEN    : "(" Spacing;
+CLOSE   : ")" Spacing;
+ID      : $([a-zA-Z_] [a-zA-Z_0-9]*) Spacing;
+INT     : $([1-9] [0-9]*) Spacing;
+Spacing : $((" " | "\t" | "\r" | "\n")*);
diff --git a/experiments/flat/grammars/flat.flat b/experiments/flat/grammars/flat.flat
index bf6e794..4fe4293 100644
--- a/experiments/flat/grammars/flat.flat
+++ b/experiments/flat/grammars/flat.flat
@@ -6,6 +6,7 @@
 Suffix     : Primary (QUESTION | STAR | PLUS)?;
 Primary    : Identifier !COLON
            | DOLLAR OPEN Expression CLOSE
+           | DOLLAR Identifier OPEN Expression CLOSE
            | OPEN Expression CLOSE
            | Literal
            | Class
diff --git a/experiments/flat/src/BuildGrammar.c b/experiments/flat/src/BuildGrammar.c
index 7425878..b34a7aa 100644
--- a/experiments/flat/src/BuildGrammar.c
+++ b/experiments/flat/src/BuildGrammar.c
@@ -303,15 +303,25 @@
             return ExpressionNewString(result);
         }
         case 2: {
+            assert(isSequence(choice,5));
+            Term *ident = TermChildAt(choice,1);
+            char *label = identifierString(builder,ident);
+            Term *expression = TermChildAt(choice,3);
+            Expression *result = buildExpression(builder,expression);
+            result = ExpressionNewLabel(label,result);
+            free(label);
+            return result;
+        }
+        case 3: {
             assert(isSequence(choice,3));
             Term *expression = TermChildAt(choice,1);
             return buildExpression(builder,expression);
         }
-        case 3:
-            return buildLiteral(builder,choice);
         case 4:
-            return buildClass(builder,choice);
+            return buildLiteral(builder,choice);
         case 5:
+            return buildClass(builder,choice);
+        case 6:
             return buildDot(builder,choice);
         default:
             assert(!"Invalid choice for Primary");
@@ -474,6 +484,8 @@
         GrammarDefine(builder->gram,ruleName,ruleExpr);
         free(ruleName);
     }
+
+    GrammarResolve(builder->gram);
 }
 
 // This function creates a new Grammar object from the result of parsing a file usin the built-in
diff --git a/experiments/flat/src/Builtin.c b/experiments/flat/src/Builtin.c
index ce060cb..291272b 100644
--- a/experiments/flat/src/Builtin.c
+++ b/experiments/flat/src/Builtin.c
@@ -88,6 +88,7 @@
 
     // Primary : Identifier !COLON
     //         | DOLLAR OPEN Expression CLOSE
+    //         | DOLLAR Identifier OPEN Expression CLOSE
     //         | OPEN Expression CLOSE
     //         | Literal
     //         | Class
@@ -95,6 +96,7 @@
     GrammarDefine(gram,"Primary",
                   choice(seq(ref("Identifier"),not(ref("COLON"))),
                          seq(ref("DOLLAR"),ref("OPEN"),ref("Expression"),ref("CLOSE")),
+                         seq(ref("DOLLAR"),ref("Identifier"),ref("OPEN"),ref("Expression"),ref("CLOSE")),
                          seq(ref("OPEN"),ref("Expression"),ref("CLOSE")),
                          ref("Literal"),
                          ref("Class"),
diff --git a/experiments/flat/src/Builtin.h b/experiments/flat/src/Builtin.h
index 76d3f38..14a2f71 100644
--- a/experiments/flat/src/Builtin.h
+++ b/experiments/flat/src/Builtin.h
@@ -31,6 +31,7 @@
  *     Suffix     : Primary (QUESTION | STAR | PLUS)?;
  *     Primary    : Identifier !COLON
  *                | DOLLAR OPEN Expression CLOSE
+ *                | DOLLAR Identifier OPEN Expression CLOSE
  *                | OPEN Expression CLOSE
  *                | Literal
  *                | Class
diff --git a/experiments/flat/src/Expression.c b/experiments/flat/src/Expression.c
index ad2fc2e..9af0d2c 100644
--- a/experiments/flat/src/Expression.c
+++ b/experiments/flat/src/Expression.c
@@ -61,6 +61,8 @@
             return "Range";
         case StringExpr:
             return "String";
+        case LabelExpr:
+            return "Label";
     }
     return "?";
 }
@@ -197,6 +199,17 @@
     return expr;
 }
 
+Expression *ExpressionNewLabel(const char *label, Expression *child)
+{
+    assert(child != NULL);
+    Expression *expr = (Expression *)calloc(1,sizeof(Expression)+1*sizeof(Expression *));
+    expr->kind = LabelExpr;
+    expr->value = strdup(label);
+    expr->count = 1;
+    expr->children[0] = child;
+    return expr;
+}
+
 void ExpressionFree(Expression *expr)
 {
     if (expr == NULL)
@@ -232,6 +245,7 @@
         case DotExpr:
             return 5;
         case StringExpr:
+        case LabelExpr:
             return 6;
         case RangeExpr:
             return 7;
@@ -329,6 +343,12 @@
             ExpressionPrint(ExprStringChild(expr),highestPrecedence,NULL);
             printf(")");
             break;
+        case LabelExpr:
+            printf("$%s(",ExprLabelIdent(expr));
+            highestPrecedence = 1; // because of brackets
+            ExpressionPrint(ExprLabelChild(expr),highestPrecedence,NULL);
+            printf(")");
+            break;
     }
     if (brackets)
         printf(")");
@@ -494,3 +514,23 @@
     assert(expr->children[0] != NULL);
     return expr->children[0];
 }
+
+// Label
+
+const char *ExprLabelIdent(Expression *expr)
+{
+    assert(expr->kind == LabelExpr);
+    assert(expr->count == 1);
+    assert(expr->value != NULL);
+    assert(expr->children[0] != NULL);
+    return expr->value;
+}
+
+Expression *ExprLabelChild(Expression *expr)
+{
+    assert(expr->kind == LabelExpr);
+    assert(expr->count == 1);
+    assert(expr->value != NULL);
+    assert(expr->children[0] != NULL);
+    return expr->children[0];
+}
diff --git a/experiments/flat/src/Expression.h b/experiments/flat/src/Expression.h
index 1058be0..3d81460 100644
--- a/experiments/flat/src/Expression.h
+++ b/experiments/flat/src/Expression.h
@@ -73,6 +73,14 @@
  * StringExpr - Instructs the parser to construct a single node in the parse tree representing
  * everything within the child expression. Doesn't have any effect on what is or isn't accepted
  * by the parser.
+ *
+ * LabelExpr - Instructs the parser to construct a label node in the parse tree, indicating
+ * semantically important information. Many nodes in the parse tree are there simply because
+ * they formed part of the call tree used during parsing, but do not necessarily have any
+ * use for subsequent analysis of the tree. Label expressions are intended to, in the future,
+ * allow us to have simpler trees which only contain the information necessary for analysing
+ * a syntax tree. Like String expressions, Label expressions do not have any effect on what is or
+ * isn't accepted by the parser.
  */
 
 typedef enum {
@@ -89,6 +97,7 @@
     DotExpr,
     RangeExpr,
     StringExpr,
+    LabelExpr,
 } ExprKind;
 
 typedef struct Expression Expression;
@@ -108,6 +117,7 @@
 Expression *ExpressionNewDot(void);
 Expression *ExpressionNewRange(int lo, int hi);
 Expression *ExpressionNewString(Expression *child);
+Expression *ExpressionNewLabel(const char *label, Expression *child);
 void ExpressionFree(Expression *expr);
 void ExpressionPrint(Expression *expr, int highestPrecedence, const char *indent);
 
@@ -153,3 +163,8 @@
 // String
 
 Expression *ExprStringChild(Expression *expr);
+
+// Label
+
+const char *ExprLabelIdent(Expression *expr);
+Expression *ExprLabelChild(Expression *expr);
diff --git a/experiments/flat/src/Grammar.c b/experiments/flat/src/Grammar.c
index f015dfb..6743953 100644
--- a/experiments/flat/src/Grammar.c
+++ b/experiments/flat/src/Grammar.c
@@ -131,3 +131,11 @@
 
     free(prefix);
 }
+
+const char *GrammarFirstRuleName(Grammar *gram)
+{
+    if (gram->defList == NULL)
+        return NULL;
+    else
+        return gram->defList->name;
+}
diff --git a/experiments/flat/src/Grammar.h b/experiments/flat/src/Grammar.h
index e94e51b..f51bd18 100644
--- a/experiments/flat/src/Grammar.h
+++ b/experiments/flat/src/Grammar.h
@@ -28,3 +28,4 @@
 Expression *GrammarLookup(Grammar *gram, const char *name);
 void GrammarResolve(Grammar *gram);
 void GrammarPrint(Grammar *gram);
+const char *GrammarFirstRuleName(Grammar *gram);
diff --git a/experiments/flat/src/Parser.c b/experiments/flat/src/Parser.c
index 74c1e28..5c76a1a 100644
--- a/experiments/flat/src/Parser.c
+++ b/experiments/flat/src/Parser.c
@@ -212,6 +212,12 @@
             // (which can be recovered from the input, and the start and end fields of the term).
             return TermNew(expr,startPos,p->pos,NULL);
         }
+        case LabelExpr: {
+            Term *term = parseExpr(p,ExprLabelChild(expr));
+            if (term == NULL)
+                return NULL;
+            return TermNew(expr,startPos,p->pos,TermListNew(term,NULL));
+        }
     }
     assert(!"unknown expression type");
     return NULL;
diff --git a/experiments/flat/src/Term.c b/experiments/flat/src/Term.c
index e3fc44b..f0369eb 100644
--- a/experiments/flat/src/Term.c
+++ b/experiments/flat/src/Term.c
@@ -105,6 +105,9 @@
         case IdentExpr:
             printf("%s %s\n",ExprKindAsString(ExpressionKind(term->type)),ExprIdentValue(term->type));
             break;
+        case LabelExpr:
+            printf("%s %s\n",ExprKindAsString(ExpressionKind(term->type)),ExprLabelIdent(term->type));
+            break;
         case LitExpr:
         case RangeExpr:
         case DotExpr:
diff --git a/experiments/flat/src/flat.c b/experiments/flat/src/flat.c
index 8aa4f74..ee3c2bb 100644
--- a/experiments/flat/src/flat.c
+++ b/experiments/flat/src/flat.c
@@ -44,6 +44,29 @@
     return data;
 }
 
+static Grammar *grammarFromFile(const char *filename)
+{
+    char *input = readStringFromFile(filename);
+    if (input == NULL) {
+        perror(filename);
+        exit(1);
+    }
+
+    Grammar *flatGrammar = GrammarNewBuiltin();
+    Term *term = parse(flatGrammar,"Grammar",input,0,strlen(input));
+    if (term == NULL) {
+        fprintf(stderr,"%s: Parse failed\n",filename);
+        exit(1);
+    }
+
+    Grammar *builtGrammar = grammarFromTerm(term,input);
+
+    free(input);
+    GrammarFree(flatGrammar);
+
+    return builtGrammar;
+}
+
 int main(int argc, const char **argv)
 {
 
@@ -71,28 +94,32 @@
         GrammarFree(gram);
     }
     else if ((argc == 3) && !strcmp(argv[1],"-b")) {
-        const char *filename = argv[2];
-        char *input = readStringFromFile(filename);
-        if (input == NULL) {
-            perror(filename);
-            exit(1);
-        }
-
-        Grammar *gram = GrammarNewBuiltin();
-        Term *term = parse(gram,"Grammar",input,0,strlen(input));
-        if (term == NULL) {
-            fprintf(stderr,"%s: Parse failed\n",filename);
-            exit(1);
-        }
-
-
-        Grammar *built = grammarFromTerm(term,input);
+        Grammar *built = grammarFromFile(argv[2]);
         GrammarPrint(built);
-
-        free(input);
-        GrammarFree(gram);
         GrammarFree(built);
     }
+    else if (argc == 3) {
+        const char *grammarFilename = argv[1];
+        const char *inputFilename = argv[2];
+
+        char *inputStr = readStringFromFile(inputFilename);
+        if (inputStr == NULL) {
+            perror(inputFilename);
+            exit(1);
+        }
+
+        Grammar *builtGrammar = grammarFromFile(grammarFilename);
+        const char *firstRuleName = GrammarFirstRuleName(builtGrammar);
+        Term *inputTerm = parse(builtGrammar,firstRuleName,inputStr,0,strlen(inputStr));
+        if (inputTerm == NULL) {
+            fprintf(stderr,"%s: Parse failed\n",inputFilename);
+            exit(1);
+        }
+        TermPrint(inputTerm,inputStr,"");
+
+        free(inputStr);
+        GrammarFree(builtGrammar);
+    }
     else {
         printf("Usage:\n"
                "\n"
@@ -109,6 +136,11 @@
                "\n"
                "    Parse FILENAME using the built-in PEG grammar, then use the resulting parse\n"
                "    tree to build a Grammar object, and print out the constructed grammar.\n"
+               "\n"
+               "flat GRAMMAR INPUT\n"
+               "\n"
+               "    Use the grammar defined in file GRAMMAR to parse the file INPUT, and print\n"
+               "    out the resulting parse tree\n"
                "\n");
 
         return 1;