May 22, 2013 at 10:56 AM
Edited May 22, 2013 at 1:08 PM
I have been struggling to find a step by step tutorial for the latest version of Irony. I can only find the two posts created by Daniel Flower on Code project. Yes they are good, but unfortunately, it is only applicable to the old version of Irony.
I am trying to generate/build a string (sql statements) based on the user input. Using the previous Irony, I needed my ast nodes classes to implement a generator interface, and then within each node class there is a function for generating/appending a string.
How can I accomplish this in the new Irony?
Please help. Thank you.
Currently, the best tutorials are the sample projects in the source code. Unfortunately, there are no step-by-step tutorials as Roman has been swamped, but I'm sure he would accept user submissions with regards to this.
Sounds like you are already off to a good start with code previously designed around the old Irony architecture. I am not sure how to your request for help on the current Irony without some context to your issues. If you could, please post some of your old
code, and the community may be able to help.
Thank you for your reply. I am trying to generate an sql script based on the user input. The old tutorials were really helpful, but the new source code seems a bit complicated without any documentation. Basically, I had the following:
A compiler class with the following function:
public static string Compile(string sourceCode)
// create a compiler from the grammar
FLGrammar grammar = new FLGrammar();
LanguageCompiler compiler = new LanguageCompiler(grammar);
// Attempt to compile into an Abstract Syntax Tree. Because FLGrammar
// defines the root node as ProgramNode, that is what will be returned.
// This happens to implement ILangGenerator, which is what we need.
ILangGenerator program = (ILangGenerator)compiler.Parse(sourceCode);
if (program == null || compiler.Context.Errors.Count > 0)
// Didn't compile. Generate an error message.
SyntaxError error = compiler.Context.Errors;
string location = string.Empty;
if (error.Location.Line > 0 && error.Location.Column > 0)
location = "Line " + (error.Location.Line + 1) + ", column " + (error.Location.Column + 1);
string message = location + ": " + error.Message + ":" + Environment.NewLine;
message += sourceCode.Split('\n')[error.Location.Line];
throw new CompilationException(message);
StringBuilder js = new StringBuilder();
A grammar class:
#region Initial setup of the grammar
this.CaseSensitive = false;
// define all the non-terminals
var program = new NonTerminal("program", typeof(ProgramNode));
var statementList = new NonTerminal("statementList", typeof(StatementListNode));
var condition = new NonTerminal("statement", typeof(ConditionNode));
var oper = new NonTerminal("operator", typeof(OperatorNode));
// define all the terminals
var variable = new IdentifierTerminal("variable");
variable.AddKeywords("where","set", "to", "if", "freight", "cost", "is", "loop", "through", "order");
var number = new NumberLiteral("number");
var stringLiteral = new StringLiteral("string", "\"", ScanFlags.None);
// remove uninteresting nodes from the AST (note: in current version of Irony,
// keywords added to the variable cannot be registered as punctuation).
this.RegisterPunctuation(";", "[", "]", "(", ")");
// specify the non-terminal which is the root of the AST
this.Root = program;
#region Define the grammar
//<Program> ::= <StatementList> <FreightDeclaration>
program.Rule = statementList;
//<StatementList> ::= <Statement>*
statementList.Rule = Symbol("where") + condition;
//<condition>::= <string> <operator> <string> | <condition> <operator> <condition> | “(“ <condition> “)”
//<Statement> ::= <SetVariable> ";" | <IfStatement> | <OrderLoop> | <Expression> ";"
condition.Rule = condition + oper + condition | "(" + condition + ")" | variable |
number | stringLiteral;
//<BinaryOperator> ::= "+" | "-" | "*" | "/" | "<" | ">" | "<=" | ">=" | "is"
oper.Rule = Symbol("+") | "-" | "*" | "/" | "<" | ">" | "<=" | ">=" | "is" |
"=" | "like" | "and" | "or";
A class for each node, to generate the related SQL statements. Each class inherits AstNode, and implements a Generator interface which has a virtual function for generating scripts.
With the new Irony source code, I have looked at the ExpressionEvaluatorGrammar example. I can see three classes for the grammar:
ExpressionEvaluator, ExpressionEvaluatorGrammar & ExpressionEvaluatorRuntime. In addition to that, there are are classes for AstNode. This time, these classes only inherit from AstNode. I dont know where should I implement the logic for generating the SQL
script. Should it be in the overriden Init function?
Also it seems the ExpressionEvaluator example makes use of several LanguageRuntime classes: LanguageRuntime, LanguageRuntime_Binding, LanguageRuntime_OpDispatch, LanguageRuntime_OpDispatch_Init. Do I need to implement all these three classes to achieve what
I am looking for?
Please help. Thank you.
May 24, 2013 at 5:41 AM
I don't think you need AST nodes at all, and all that interpreter/runtime stuff. You can take the same approach as FTS search grammar - it generates SQL FTS clause by directly traversing the parse tree, without generating AST. Have a look, it is in samples.
When you hit Run in GE, it generates the FTS clause and writes it to the output.