Optional parameter

May 7, 2010 at 8:49 AM

Hi,

I try to create a simple language format like this :

V 1 2 3 4

V 4 5 6

V 7 8 9 10

The problem that I have is that I have 3 or 4 numeric values, I have try something like this but it doesn't work :

var scene = new NonTerminal("scene", typeof(StatementListNode));
var statement = new NonTerminal("statement", typeof(StatementListNode));
var vertices = new NonTerminal("Vertices");
var vertex = new NonTerminal("vertex", typeof(Nodes.VertexNode));

vertex.Rule = "v" + number + number + number | number;
vertices.Rule = MakeStarRule(vertices, vertex);
statement.Rule = vertices + statement + NewLine;
scene.Rule = vertices + NewLineStar;

It creates 2 vertex ("v") when I have 4 numerics

Thanks

 

May 7, 2010 at 11:07 AM
Edited May 7, 2010 at 11:08 AM

Also,

Here is a test file :

# test scene

o testscene

v 1 2 3
v 1 2 3 4
v 1 2 3 4
v 1 2 3 4

I don't know how to add a 'textual' value like 'testscene'. I have try this , but the grammar explorer does not display any error !!!

 

#region Terminals

            var textual = new StringLiteral("textual", "");
            var comment = new CommentTerminal("comment", "#", "\n", "\r");
            var number = new NumberLiteral("number", NumberOptions.AllowSign | NumberOptions.AllowStartEndDot);
            var scene = new NonTerminal("scene", typeof(StatementListNode));
            var sceneLine = new NonTerminal("scene line");
            var statement = new NonTerminal("statement", typeof(StatementListNode));
            var objectName = new NonTerminal("object name");
            var vertices = new NonTerminal("vertices");
            var vertex = new NonTerminal("vertex", typeof(Nodes.VertexNode));

            #endregion

            #region Rules

            vertex.Rule = "v" + number + number + number | number;
            vertices.Rule = MakeStarRule(vertices, vertex);
            objectName.Rule = "o" + textual;
            statement.Rule = objectName | vertices;
            sceneLine.Rule = statement + NewLine;
            scene.Rule = MakeStarRule(scene, sceneLine);
            NonGrammarTerminals.Add(comment);

            #endregion

            #region Config

            Root = scene;
            LanguageFlags = LanguageFlags.CreateAst | LanguageFlags.NewLineBeforeEOF;
            MarkTransient(statement, sceneLine, objectName);

            #endregion

May 7, 2010 at 12:39 PM
Edited May 7, 2010 at 12:40 PM

Hey Viewon,

 

One issue I see is in the line

 

vertex.Rule = "v" + number + number + number | number;

 

I really think you meant something more like this

 

vertex.Rule = "v" + number + number + number + (number | empty);

 

 

-MindCore

 

May 7, 2010 at 12:44 PM

Thanks,

It is interesting :-)

But I still have the same problem... when I use the grammar explorer and test a file... nothing happend, no result, no tree etc ... :-(

May 7, 2010 at 12:45 PM

Sorry

I got 2 errors :-P

Warning: AstNodeType or AstNodeCreator is not set on non-terminals: vertices Unnamed0.
Transient non-terminal must have zero or one non-punctuation child nodes; non-terminals: object name.

 

May 7, 2010 at 1:23 PM

The first Warning is saying that you don't have an AstNode set for the vertices non-terminal, so when Irony goes to build the Ast Tree, it doesn't know what to do.  The line it is referring to is this line:

var vertices = new NonTerminal("vertices");

It needs to have an AstNode paramter defined like such:

var vertices = new NonTerminal("vertices", typeof(Nodes.VerticesNode));

It appears you have a custome AstNode type for your Vertex, so you may need one for your Vertices branch node.  Check out the IfNode for an example.

 

And the second error is in reference to your MarkTransient step:

MarkTransient(statement, sceneLine, objectName);

My guess is that the Non-terminal it's complaining about is the sceneLine. You actually may be able to eliminate this node as follows:

1. Change the scene Rule (i.e. BnfExpression) to the following:

scene.Rule = MakeStarRule(scene, statement, NewLine);

2. Remove the sceneLine Non-terminal and also remove it from the MarkTransient method call.

Since you are ultimately appending statements using a NewLine, I don't think the additional sceneLine Non-Terminal is needed.

 

-MindCore

May 7, 2010 at 1:51 PM

Thanks,

 

But now in the grammar explorer I got the following error message :

System.IndexOutOfRangeException: Index was outside the bounds of the array.   at Irony.Parsing.StringLiteral.Init(GrammarData grammarData) in D:\Temp\irony_51617\irony-51617\Irony\Parsing\Terminals\StringLiteral.cs:line 133   at Irony.Parsing.Construction.GrammarDataBuilder.InitTermLists() in D:\Temp\irony_51617\irony-51617\Irony\Parsing\Data\Construction\GrammarDataBuilder.cs:line 155   at Irony.Parsing.Construction.GrammarDataBuilder.Build() in D:\Temp\irony_51617\irony-51617\Irony\Parsing\Data\Construction\GrammarDataBuilder.cs:line 37   at Irony.Parsing.Construction.LanguageDataBuilder.Build() in D:\Temp\irony_51617\irony-51617\Irony\Parsing\Data\Construction\LanguageDataBuilder.cs:line 37   at Irony.Parsing.LanguageData.ConstructAll() in D:\Temp\irony_51617\irony-51617\Irony\Parsing\Data\LanguageData.cs:line 38   at Irony.Parsing.LanguageData..ctor(Grammar grammar) in D:\Temp\irony_51617\irony-51617\Irony\Parsing\Data\LanguageData.cs:line 34   at Irony.GrammarExplorer.fmGrammarExplorer.CreateParser() in D:\Temp\irony_51617\irony-51617\Irony.GrammarExplorer\fmGrammarExplorer.cs:line 308   at Irony.GrammarExplorer.fmGrammarExplorer.cboGrammars_SelectedIndexChanged(Object sender, EventArgs e) in D:\Temp\irony_51617\irony-51617\Irony.GrammarExplorer\fmGrammarExplorer.cs:line 497   at System.Windows.Forms.ComboBox.OnSelectedIndexChanged(EventArgs e)   at System.Windows.Forms.ComboBox.WmReflectCommand(Message& m)   at System.Windows.Forms.ComboBox.WndProc(Message& m)   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

Here is my new code/bnf :

 

#region Terminals

            var textual = new StringLiteral("textual", "");
            var comment = new CommentTerminal("comment", "#", "\n", "\r");

            var number = new NumberLiteral("number", NumberOptions.AllowSign | NumberOptions.AllowStartEndDot);
            //number.AddPrefix("0x", NumberFlags.Hex);
            //number.AddSuffixCodes("f", TypeCode.Single);

            var scene = new NonTerminal("scene", typeof(StatementListNode));
            var sceneLine = new NonTerminal("scene line");

            var statement = new NonTerminal("statement", typeof(StatementListNode));

            var objectName = new NonTerminal("object name");

            var vertices = new NonTerminal("vertices");
            var vertex = new NonTerminal("vertex");

            #endregion

            #region Rules

            vertex.Rule = "v" + number + number + number + (number | Empty);
            vertices.Rule = MakeStarRule(vertices, vertex);

            objectName.Rule = "o" + textual;

            statement.Rule = objectName | vertices;

            sceneLine.Rule = statement + NewLine;
            scene.Rule = MakeStarRule(scene, sceneLine, NewLine);

            NonGrammarTerminals.Add(comment);
            NonGrammarTerminals.Add(NewLine);

            #endregion

            #region Config

            Root = scene;
            LanguageFlags = LanguageFlags.CreateAst | LanguageFlags.NewLineBeforeEOF;
            MarkTransient(statement, objectName);

            #endregion

May 7, 2010 at 6:27 PM

This error message is caused by the line

var textual = new StringLiteral("textual", "");

The string literal is for text that has at least a start symbol.  
Using an empty string will cause the parser to capture everything as one long string and blow up.

Try changing this line to

var textual = new IdentifierTerminal("textual");


-MindCore

 

May 10, 2010 at 8:59 AM

Thanks,

Unfortunately I have some errors now :

Warning: AstNodeType or AstNodeCreator is not set on non-terminals: scene line vertices vertex Unnamed0.
Transient non-terminal must have zero or one non-punctuation child nodes; non-terminals: object name.

Regards

May 10, 2010 at 1:12 PM

It appears you missed the second part to my second post.  The Non-Terminal sceneLine is no longer needed as the NewLine suffix is now handled by the MakeStarRule in the scene Non-terminal.

Change the following:

sceneLine.Rule = statement + NewLine;
scene.Rule = MakeStarRule(scene, sceneLine, NewLine);

to:

scene.Rule = MakeStarRule(scene, statement, NewLine);

 

-MindCore

May 10, 2010 at 1:56 PM

Thanks,

But I still have the same error :-<

May 11, 2010 at 3:11 PM
Edited May 11, 2010 at 3:22 PM

Hey,

I've seen that error before (about AstNodeType or AstNodeCreator not set on "Unnamed0"), and I believe the culprit is:

vertex.Rule = "v" + number + number + number + (number | Empty);

(Disclaimer: I have not run the grammar code, in part or in whole, but I had a similar issue, and it looks like the same problem)

The problem is that this line of the grammar is not in BNF.  To be in BNF, it must be an "OR'd" list of "PLUS" rules.  Here, we have a "PLUS" list of "OR" rules.  Internally, when the PLUS ('+') operator encounters an "OR" expression (in this case: "(number | Empty)"), it wraps the expression in an unnamed non-terminal ("Unnamed0" -- If you had more than one, it would start generating "Unnamed1", "Unnamed2", etc.).  This unnamed non-terminal has no AstNodeType or AstNodeCreator set to it, hence the warning message!

To fix it, you must make sure that ALL of your rules are in BNF when creating an AST (BNF doesn't matter if you're NOT creating an AST)!  So, try re-writing the rule as:

vertex.Rule = ("v" + number + number + number) | ("v" + number + number + number + number)

OR:

var optionalVertexParam = new NonTerminal("OptionalVertexParam");
vertex.Rule = "v" + number + number + number + optionalVertexParam;
optionalVertexParam.Rule = Empty | number;
MarkTransient(optionalVertexParam);

The key to the second form is that you are explicitly creating the "unnamed" non-terminal, but are marking it transient!  (So it won't show up in the parse tree -- and therefore does not need an AstNodeType or AstNodeCreator!)

For some more information, check out: http://irony.codeplex.com/Thread/View.aspx?ThreadId=80451.  Roman explains why validation allows non-BNF rules in his 2nd point in the last post.

Hope that helps!

Brian

May 12, 2010 at 9:41 AM

Thanks,

I have try your proposal, but still have the same error message :-(

 

Here is my grammar code :

 

using System;
using Irony;
using Irony.Ast;
using Irony.Parsing;

namespace ASEngine.FilesFormats.Wavefront
{

    [Language("Wavefront Obj file parser", "1.0", "OBJ scene file")]
    public sealed class ObjGrammar : Grammar
    {
        public ObjGrammar()
            : base(true)
        {

            #region Terminals

            var textual = new IdentifierTerminal("textual");
            var comment = new CommentTerminal("comment", "#", "\n", "\r");

            var number = new NumberLiteral("number", NumberOptions.AllowSign | NumberOptions.AllowStartEndDot);
            //number.AddPrefix("0x", NumberFlags.Hex);
            //number.AddSuffixCodes("f", TypeCode.Single);

            var scene = new NonTerminal("scene", typeof(StatementListNode));

            var statement = new NonTerminal("statement", typeof(StatementListNode));

            var objectName = new NonTerminal("object name");

            var vertices = new NonTerminal("vertices");
            var vertex = new NonTerminal("vertex");

            #endregion

            #region Rules

            //vertex.Rule = "v" + number + number + number + (number | Empty);
            vertex.Rule = ("v" + number + number + number) | ("v" + number + number + number + number);
            vertices.Rule = MakeStarRule(vertices, vertex);

            objectName.Rule = "o" + textual;

            statement.Rule = objectName | vertices;

            scene.Rule = MakeStarRule(scene, statement, NewLine);

            NonGrammarTerminals.Add(comment);
            NonGrammarTerminals.Add(NewLine);

            #endregion

            #region Config

            Root = scene;
            LanguageFlags = LanguageFlags.CreateAst | LanguageFlags.NewLineBeforeEOF;
            MarkTransient(statement, objectName);

            #endregion

        }
    }
}

May 12, 2010 at 4:27 PM

Ok, I just ran it in the GrammarExplorer and I'm seeing the following warnings / errors:

1) Warning: AstNodeType or AstNodeCreator is not set on non-terminals: vertices vertex.

2) Error: Transient non-terminal must have zero or one non-punctuation child nodes; non-terminals: object name.

When creating an AST, all Non-Terminals that are not marked as punctuation or transient must have an AstNodeType or AstNodeCreator set.  The easiest way to do this is as Mindcore had suggested, and pass it into the constructor of the non-terminal.  If you do as Mindcore has suggested earlier in the thread:

var vertices = new NonTerminal("vertices", typeof(Nodes.VerticesNode));
var vertex = new NonTerminal("vertex", typeof(Nodes.VertexNode));

then that should get rid of warning #1.  Of course, you will need to create a new class "Nodes.VerticesNode" that derives from "AstNode" that will process the list of vertices.  For example, the "VertexNode" class could read in a definition of a vertex and create some sort of Vertex object instance out of it and place it on the evaluation stack.  The "VerticesNode" class would go through all of it's child nodes (the "VertexNode"s), and evaluate each one and pop all of the Vertex objects off of the evaluation stack, and save them somewhere.  You could "save" them by placing them into a List<Vertex>, and place that back on the evaluation stack (or save it to some larger "Scene" object, etc.).  Later, when parsing the face definitions, you will have this list handy and can index into it.

As for the error #2, it's refering to this rule:

objectName.Rule = "o" + textual;

What this error is saying is that you have marked "objectName" as "transient" (meaning it won't show up in the parse tree), but it contains more than one non-punctuation nodes (in this case, "o" and "textual").  Since this rule specifies that the following vertices / etc. belong to the named object (specified by the identifier "textual"), you probably don't want to ignore this piece of data.  That is, "objectName" should not be marked as "transient".  Like mentioned above, once you remove it from the call to "MakeTransient":

MakeTransient(statement);

then you will also need to pass in some AstNode type to the objectName's constructor:

// Note: it is much easier to debug grammars if the names of non-terminals contain no spaces
var objectName = new NonTerminal("objectName", typeof(Nodes.ObjectNameNode));

As for the implementation of ObjectNameNode, it might do something like create a new "SceneObject" instance that you will be saving the list of vertices / vertex-normals / faces / curves / etc. to as they get parsed.

Brian

May 14, 2010 at 6:53 AM

Thanks for your help,

 

Now it compiles, but when I test it I got the following error : Syntax error, expected: [line break]

Here is my test file :

# test scene

o testscene

v 1 2 3
v 1 2 3 4
v 1 2 3 4
v 1 2 3 4

Here is my code :

#region Terminals

            var textual = new IdentifierTerminal("textual");
            var comment = new CommentTerminal("comment", "#", "\n", "\r");

            var number = new NumberLiteral("number", NumberOptions.AllowSign | NumberOptions.AllowStartEndDot);
            //number.AddPrefix("0x", NumberFlags.Hex);
            //number.AddSuffixCodes("f", TypeCode.Single);

            var scene = new NonTerminal("scene", typeof(StatementListNode));

            var statement = new NonTerminal("statement", typeof(StatementListNode));

            var objectName = new NonTerminal("object name", typeof(Nodes.ObjectNameNode));

            var vertices = new NonTerminal("vertices", typeof(Nodes.VerticesNode));
            var vertex = new NonTerminal("vertex", typeof(Nodes.VertexNode));

            #endregion

            #region Rules

            //vertex.Rule = "v" + number + number + number + (number | Empty);
            vertex.Rule = ("v" + number + number + number); // | ("v" + number + number + number + number);
            vertices.Rule = MakeStarRule(vertices, vertex);

            objectName.Rule = "o" + textual;

            statement.Rule = objectName | vertices;

            scene.Rule = MakeStarRule(scene, statement, NewLine);

            NonGrammarTerminals.Add(comment);
            NonGrammarTerminals.Add(NewLine);

            #endregion

            #region Config

            Root = scene;

            // automatically add NewLine before EOF so that our BNF rules work correctly 
            // when there's no final line break in source
            LanguageFlags = LanguageFlags.CreateAst | LanguageFlags.NewLineBeforeEOF;
            MarkTransient(statement);

            #endregion

May 14, 2010 at 2:57 PM
Edited May 14, 2010 at 2:59 PM

Just looking at it, I think there are two problems with the grammar.  I'm guessing one problem is that you are marking the NewLine terminal as a non-grammar terminal:

NonGrammarTerminals.Add(NewLine);

If you go to the definition of "NonGrammarTerminals" (in Grammar.cs), it has the following comment:

//Terminals not present in grammar expressions and not reachable from the Root
// (Comment terminal is usually one of them)
// Tokens produced by these terminals will be ignored by parser input.
public readonly TerminalSet NonGrammarTerminals = new TerminalSet();

What this means is that if you mark something as a "non-grammar terminal" then the parser will ignore the fact that this terminal ever existed.  For example, comment terminals are listed as non-grammar terminals since they are purely human-readable documentation and there is no code to produce from them.  Source code will work with or without the presence of comments since the comments are ignored by the parser.

When you mark the NewLine terminal as a non-grammar terminal, your input of:

# test scene

o testscene

v 1 2 3
v 1 2 3 4
v 1 2 3 4
v 1 2 3 4

will look like:

# test scene o testscene v 1 2 3 v 1 2 3 4 v 1 2 3 4 v 1 2 3 4

to the parser (because the NewLine is ignored).  The syntax error that you get says that it was expecting to find a line break, but didn't find one.  It never will find a line break as the line breaks are being ignored.  To fix this, just remove the line:

NonGrammarTerminals.Add(NewLine)

As for the other problem, I believe it is the following line:

scene.Rule = MakeStarRule(scene, statement, NewLine);

The function header for MakeStarRule is:

public static BnfExpression MakeStarRule(NonTerminal listNonTerminal, BnfTerm delimiter, BnfTerm listMember)

I believe you have the delimiter and listMember arguments backwards when you call this.  It makes more sense to have the "NewLine"s separate "statement"s rather than "statement"s separating "NewLine"s.  Simple fix:

scene.Rule = MakeStarRule(scene, NewLine, statement);

 Brian

May 14, 2010 at 3:13 PM

Very interesting,

 

But I still have some errors : 

Failed to create AST node for non-terminal [vertex], error: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index

Failed to create AST node for non-terminal [vertex], error: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index

Syntax error, expected: v [line break]

 

Thanks

 

 

May 14, 2010 at 3:25 PM

Ah, there's another problem.  The first line of your input is a comment, and your terminal for comments ("comment") is not included in any of the production rules reachable from the root.  Try adding it to the statement rule:

statement.Rule = objectName | vertices | comment;

As for the errors about creating AST nodes for non-terminal [vertex], it means that your constructor / Init code for your "Nodes.VertexNode" class threw an exception.  Perhaps you tried to access the 4th (optional) number without checking to see if it exists first?

Brian

May 14, 2010 at 3:54 PM

Thanks,

 

I still have the following "Grammar errors" :

Reduce-reduce conflict. State S0, lookaheads: EOF. Selected reduce on first production in conflict set.

And also the following error at test :

Syntax error, expected: v [line break]

 

Thanks

Coordinator
May 18, 2010 at 5:15 PM
Please repost your grammar after all updates
May 19, 2010 at 6:36 AM

Thanks,

 

Here is my updated version :

 

    [Language("Wavefront Obj file parser", "1.0", "OBJ scene file")]
    public sealed class ObjGrammar : Grammar
    {
        public ObjGrammar()
            : base(true)
        {

            #region Terminals

            var textual = new IdentifierTerminal("textual");
            var comment = new CommentTerminal("comment", "#", "\n", "\r");

            var number = new NumberLiteral("number", NumberOptions.AllowSign | NumberOptions.AllowStartEndDot);
            //number.AddPrefix("0x", NumberFlags.Hex);
            //number.AddSuffixCodes("f", TypeCode.Single);

            var scene = new NonTerminal("scene", typeof(StatementListNode));

            var statement = new NonTerminal("statement", typeof(StatementListNode));

            var objectName = new NonTerminal("object name", typeof(Nodes.ObjectNameNode));

            var vertices = new NonTerminal("vertices", typeof(Nodes.VerticesNode));
            var vertex = new NonTerminal("vertex", typeof(Nodes.VertexNode));

            #endregion

            #region Rules

            //vertex.Rule = "v" + number + number + number + (number | Empty);
            vertex.Rule = ("v" + number + number + number); // | ("v" + number + number + number + number);
            vertices.Rule = MakeStarRule(vertices, vertex);

            objectName.Rule = "o" + textual;

            statement.Rule = objectName | vertices | comment;

            scene.Rule = MakeStarRule(scene, NewLine, statement);

            NonGrammarTerminals.Add(comment);

            #endregion

            #region Config

            Root = scene;

            // automatically add NewLine before EOF so that our BNF rules work correctly 
            // when there's no final line break in source
            LanguageFlags = LanguageFlags.CreateAst | LanguageFlags.NewLineBeforeEOF;
            MarkTransient(statement);

            #endregion

        }
    }

Coordinator
May 24, 2010 at 6:26 PM
Edited May 25, 2010 at 12:08 AM
(Sorry, codeplex seems to be going nuts - it removes linebreaks when I save the post) Sorry for a long time to reply. Here it is: using System; using System.Collections.Generic; using System.Linq; using System.Text; using Irony.Parsing; using Irony.Ast; namespace Irony.Samples{ [Language("Wavefront Obj file parser", "1.0", "OBJ scene file")] public sealed class ObjGrammar : Grammar { public ObjGrammar() : base(true) { #region Terminals var textual = new IdentifierTerminal("textual"); var comment = new CommentTerminal("comment", "#", "\n", "\r"); var number = new NumberLiteral("number", NumberOptions.AllowSign | NumberOptions.AllowStartEndDot); //number.AddPrefix("0x", NumberFlags.Hex); //number.AddSuffixCodes("f", TypeCode.Single); var opt_number = new NonTerminal("opt_number", typeof(AstNode)); var scene = new NonTerminal("scene", typeof(StatementListNode)); var statement = new NonTerminal("statement", typeof(StatementListNode)); var objectName = new NonTerminal("object name", typeof(AstNode)); var vertices = new NonTerminal("vertices", typeof(AstNode)); var vertex = new NonTerminal("vertex", typeof(AstNode)); #endregion #region Rules //vertex.Rule = "v" + number + number + number + (number | Empty); vertex.Rule = "v" + number + number + number + opt_number; // | ("v" + number + number + number + number); opt_number.Rule = number | Empty; vertices.Rule = MakePlusRule(vertices, vertex); objectName.Rule = "o" + textual; statement.Rule = objectName | vertices | comment | Empty; scene.Rule = MakePlusRule(scene, NewLine, statement); NonGrammarTerminals.Add(comment); #endregion #region Config Root = scene; // automatically add NewLine before EOF so that our BNF rules work correctly // when there's no final line break in source LanguageFlags = LanguageFlags.CreateAst | LanguageFlags.NewLineBeforeEOF; MarkTransient(statement, opt_number); #endregion } } } Note I replaced some node type references with AstNode - I don't have your custom nodes. I changed some star-lists to plus lists, added optional number non-term, and made some elements optional (with "| Empty"). No conflicts, compiles your sample OK Roman
May 25, 2010 at 9:02 AM

Thanks a lot,

It works fine now :-)

It will be great if some 'documentation' will be available... Irony is a great library but difficult to use for someone without deep knowledge.

At least, it will be fine to have class documentation... before each class like 'NonTerminal, IdentifierTerminal,...' explaining how and when to use it.
Of course, more tutorials, samples etc... will be great too :-)

Congratulation for this library

May 25, 2010 at 11:57 AM

Hi,

I have another problem :

By example, I must parse the following line :

f 0/1/1 0/2/2

where the "/?" are optional... so I have try with this code... but it doesn't account the "/" character ?

 

            var faces = new NonTerminal("faces", typeof(AstNode));
            var faceVertices = new NonTerminal("faceVertices", typeof(AstNode));
            var faceVertice = new NonTerminal("faceVertice", typeof(AstNode));

            var opt_vt = new NonTerminal("opt_vt", typeof(AstNode));
            //opt_vt.Rule = ("/" + (number | Empty)) | Empty;
            opt_vt.Rule = ("/" + number) | Empty;

            faceVertice.Rule = number + opt_vt;
            faceVertices.Rule = MakePlusRule(faceVertices, faceVertice);
            faces.Rule = "f" + faceVertices;

May 25, 2010 at 12:05 PM

Hum,

 

I'm not clear,

by example for the following line :

"f 1/9 2 3 4"

"/9" is an opt_vt : ok

but for the second "faceVertice", I have "9" and not "2"... because 9 is part of "/9" !!

May 25, 2010 at 12:11 PM
Edited May 25, 2010 at 12:12 PM

In fact I should be able to parse the following :

f 1 2 3 4
f 1/9/2 2/4/5 3/6/8
f 1//2 2//5

I have try with this code without success :

            var faces = new NonTerminal("faces", typeof(AstNode));
            var faceVertices = new NonTerminal("faceVertices", typeof(AstNode));
            var faceVertice = new NonTerminal("faceVertice", typeof(AstNode));

            var opt_vt = new NonTerminal("opt_vt", typeof(AstNode));
            opt_vt.Rule = ("/" + (number | Empty)) | Empty;
            //opt_vt.Rule = ("/" + number) | Empty;

            var opt_vn = new NonTerminal("opt_vn", typeof(AstNode));
            opt_vn.Rule = ("/" + (number | Empty)) | Empty;

            faceVertice.Rule = number + opt_vt + opt_vn;
            faceVertices.Rule = MakePlusRule(faceVertices, faceVertice);
            faces.Rule = "f" + faceVertices;

 

 Do you have any idea to solve this ?

Coordinator
May 27, 2010 at 4:28 PM

opt_vt and opt_vn seem to be identical - what's the point?

I think you should define the "1/2/3..." sequence as simply a list of numbers with "/" as a separator, using MakePlusRule 

May 27, 2010 at 4:35 PM
rivantsov wrote:

opt_vt and opt_vn seem to be identical - what's the point?

I think you should define the "1/2/3..." sequence as simply a list of numbers with "/" as a separator, using MakePlusRule 

 The problem with making it a "plus" rule is that "1/2/3/4/5/6/7/8/9/10" is not valid.  In WaveFront OBJ files, the faces are defined as a list of v/vt/vn triplets (where v is the index of the geometric vertex, vt is the texture vertex, and vn is the vertex normal -- all of these values are defined higher up in the file format in the vertices section).

Here's the entire spec: http://www.martinreddy.net/gfx/3d/OBJ.spec

It's been a few years since I had my last graphics class.  :)

Brian

May 28, 2010 at 4:13 PM

It seems that the most complicated part about the face definitions is that they must all be consistent within a line, and that there should not be any space between the numbers and the slashes within a triplet.  Also, there must be at least three vertices (or vertex triplets) listed to compose a face (but can be as many as the OBJ file writer desires).

By "consistent within a line", I mean the following are valid:
f 1 2 3 4 5 6 7 8 9 10 11 12 13
f 1/1/1 2/2/2 3/3/3 4/4/4 5/5/5
f 1//1 2//2 3//3 4//4
f 1// 2// 3//
f 1/1/ 2/2/ 3/3/ 4/4/

And the following are not valid:
f 1 2/2/2 3/3/3
f 1/1/1 2//2 3//3
f 1//1 2/2/ 3//

You can accomplish the line-consistency by either:
1) Allow any vertex or vertex triplet in the list, but enforce consistency through post-parsing validation
Pros: Much cleaner set of grammar rules
Cons: Hides the need for line-consistency somewhere other than the grammar (probably AstNode initialization code)
or
2) Define a set of complex grammar rules to enforce the consistency
Pros: Consistency demand is obvious
Cons: Requires many more grammar rules than #1.

I would probably go with #1...

Brian