Created
October 11, 2020 16:12
-
-
Save yallie/4025016ef0a640f39d21072ae1e38de8 to your computer and use it in GitHub Desktop.
Tiny Pascal parser example using Sprache.Calc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Linq; | |
using System.Linq.Expressions; | |
using Mono.Linq.Expressions; | |
using Sprache; | |
using Sprache.Calc; | |
namespace Pascal | |
{ | |
class Program | |
{ | |
static void Main() | |
{ | |
var parser = new PascalParser(); | |
var expr = parser.ParseProgram(@" | |
begin | |
a := 1 + 2; | |
if a > 10 then a := 10; | |
if a < 20 then | |
a := a + 1 | |
else | |
a := a - 1; | |
if a > 20 then | |
begin | |
a := 30; | |
a := a + b | |
end | |
else | |
begin | |
a := b - a | |
end | |
end. | |
"); | |
Console.WriteLine(CSharp.ToCSharpCode(expr)); | |
} | |
} | |
public class PascalParser : XtensibleCalculator | |
{ | |
public Expression ParseProgram(string text) => | |
Program.Parse(text); | |
protected internal virtual Parser<Expression> Program => | |
from b in Block.Token() | |
from s in Parse.Char('.').Token() | |
select b; | |
// block => begin statements end | |
protected internal virtual Parser<Expression> Block => | |
from b in Parse.String("begin").Token() | |
from s in Statements.Token() | |
from e in Parse.String("end").Token() | |
select s; | |
// delimiter => ";" | |
protected internal virtual Parser<Expression> Delimiter => | |
Parse.Char(';').Token().Return(default(Expression)); | |
// statements => statement { ";" statement... } | |
protected internal virtual Parser<Expression> Statements => | |
from st in Statement.Token().DelimitedBy(Delimiter) | |
select Expression.Block(st.Where(s => s != null)); | |
// statement => null | begin ... end | assignment | |
protected internal virtual Parser<Expression> Statement => | |
Parse.String("null").Token().Return(default(Expression)) | |
.XOr(Block) | |
.XOr(IfStatement) | |
.XOr(Assignment) | |
.XOr(Delimiter); | |
protected override Parser<Expression> Parameter => | |
from id in Identifier | |
from n in Parse.Not(Parse.Char('(')) | |
select Expression.Variable(typeof(double), id); | |
protected internal virtual Parser<ExpressionType> GreaterThan => | |
Operator(">", ExpressionType.GreaterThan); | |
protected internal virtual Parser<ExpressionType> LessThan => | |
Operator("<", ExpressionType.LessThan); | |
protected internal virtual Parser<Expression> BoolExpr => | |
Parse.ChainOperator(GreaterThan.Or(LessThan), Expr, Expression.MakeBinary); | |
protected internal virtual Parser<Expression> IfStatement => | |
from i in Parse.String("if").Token() | |
from test in BoolExpr.Token() | |
from t in Parse.String("then").Token() | |
from @then in Statement | |
from @else in ElseStatement.Token().Optional() | |
select @else.IsDefined ? | |
Expression.IfThenElse(test, @then, @else.GetOrDefault()) : | |
Expression.IfThen(test, @then); | |
protected internal virtual Parser<Expression> ElseStatement => | |
from e in Parse.String("else").Token() | |
from st in Statement | |
select st; | |
protected internal virtual Parser<Expression> Assignment => | |
from v in Identifier.Token() | |
from a in Parse.String(":=").Token() | |
from x in Expr.Token() | |
select Expression.Assign(Expression.Variable(typeof(double), v), x); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Project initialization:
Copy and paste
pascal.cs
contents to the Program.cs file, then run;The code will dump C# representation of the Pascal program, something like that: