Skip to content

Commit 10a41c2

Browse files
authored
* Added more docs on Kaleidoscope (#47)
* Added support for BlockDiag format generation for conversion to SVG for docs * removed redundant unused TestWriter from the ReplLoop<T> implementation * updated chapter 2 sample to generate all the tree representations and not show the xml anymore (it was noisy and not all that helpful to see in the command line anyway) * Fixed bug in getCharinterval utility that would crash if the token was EOF.
1 parent dcf70ca commit 10a41c2

25 files changed

+2381
-71
lines changed

Samples/Kaleidoscope/Chapter2/CodeGenerator.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414
namespace Kaleidoscope
1515
{
1616
/// <summary>Static extension methods to perform LLVM IR Code generation from the Kaledoscope AST</summary>
17+
/// <remarks>
18+
/// This doesn't actually generate any code. The only thing it does is to record any user defined operators
19+
/// in the <see cref="DynamicRuntimeState"/> so that subsequent parsing takes the operator precednece into
20+
/// account. (If the language didn't support user defined precedence this would not be needed at all)
21+
/// </remarks>
1722
internal sealed class CodeGenerator
1823
: KaleidoscopeBaseVisitor<int>
1924
, IDisposable
@@ -30,6 +35,11 @@ public void Dispose( )
3035

3136
public int Generate( Parser parser, IParseTree tree, DiagnosticRepresentations additionalDiagnostics )
3237
{
38+
if( parser.NumberOfSyntaxErrors > 0 )
39+
{
40+
return 0;
41+
}
42+
3343
return Visit( tree );
3444
}
3545

Samples/Kaleidoscope/Chapter2/Program.cs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
using System;
66
using System.Diagnostics.CodeAnalysis;
7-
using Antlr4.Runtime.Tree;
87
using Kaleidoscope.Grammar;
98
using Kaleidoscope.Runtime;
109

@@ -27,7 +26,11 @@ public static void Main( string[ ] args )
2726
{
2827
Console.WriteLine( "LLVM Kaleidoscope Syntax Viewer - {0}", parser.LanguageLevel );
2928

30-
var replLoop = new ReplLoop<int>( generator, parser, DiagnosticRepresentations.Xml | DiagnosticRepresentations.Dgml );
29+
// generate hopefully helpful representations of parse trees
30+
var replLoop = new ReplLoop<int>( generator
31+
, parser
32+
, DiagnosticRepresentations.Xml | DiagnosticRepresentations.Dgml | DiagnosticRepresentations.BlockDiag
33+
);
3134
replLoop.ReadyStateChanged += ( s, e ) => Console.Write( e.PartialParse ? ">" : "Ready>" );
3235
replLoop.GeneratedResultAvailable += OnGeneratedResultAvailable;
3336

@@ -37,11 +40,10 @@ public static void Main( string[ ] args )
3740

3841
private static void OnGeneratedResultAvailable( object sender, GeneratedResultAvailableArgs<int> e )
3942
{
40-
var docListener = new XDocumentListener( e.Recognizer );
41-
ParseTreeWalker.Default.Walk( docListener, e.ParseTree );
42-
Console.WriteLine( "Parsed:" );
43-
docListener.Document.Save( Console.Out );
44-
Console.WriteLine( );
43+
if( e.Recognizer.NumberOfSyntaxErrors == 0 )
44+
{
45+
Console.WriteLine( "Parsed {0}", e.ParseTree.GetType( ).Name );
46+
}
4547
}
4648
}
4749
}

Samples/Kaleidoscope/Chapter3/CodeGenerator.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
using static Kaleidoscope.Grammar.KaleidoscopeParser;
1818

19+
#pragma warning disable SA1512, SA1513, SA1515 // single line comments used to tag regions for extraction into docs
20+
1921
namespace Kaleidoscope
2022
{
2123
/// <summary>Static extension methods to perform LLVM IR Code generation from the Kaledoscope AST</summary>
@@ -24,6 +26,7 @@ internal sealed class CodeGenerator
2426
, IDisposable
2527
, IKaleidoscopeCodeGenerator<Value>
2628
{
29+
// <Initialization>
2730
public CodeGenerator( DynamicRuntimeState globalState )
2831
{
2932
RuntimeState = globalState;
@@ -32,6 +35,7 @@ public CodeGenerator( DynamicRuntimeState globalState )
3235
InstructionBuilder = new InstructionBuilder( Context );
3336
NamedValues = new Dictionary<string, Value>( );
3437
}
38+
// </Initialization>
3539

3640
public void Dispose( )
3741
{
@@ -219,11 +223,13 @@ private Function DefineFunction( Function function, ExpressionContext body )
219223
return function;
220224
}
221225

226+
// <PrivateMembers>
222227
private readonly DynamicRuntimeState RuntimeState;
223228
private static int AnonNameIndex;
224229
private readonly Context Context;
225230
private BitcodeModule Module;
226231
private readonly InstructionBuilder InstructionBuilder;
227232
private readonly IDictionary<string, Value> NamedValues;
233+
// </PrivateMembers>
228234
}
229235
}

Samples/Kaleidoscope/Kaleidoscope.Parser/AntlrUtilities.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ public static class AntlrUtilities
2020
/// <returns>Character based interval covered by the context</returns>
2121
public static Interval GetCharInterval( this ParserRuleContext ruleContext )
2222
{
23+
if( ruleContext.start.Type == Recognizer<IToken, Antlr4.Runtime.Atn.ParserATNSimulator>.Eof )
24+
{
25+
return Interval.Invalid;
26+
}
27+
2328
int startChar = ruleContext.Start.StartIndex;
2429
int endChar = ruleContext.Stop.StopIndex - 1;
2530
return Interval.Of( Min( startChar, endChar ), Max( startChar, endChar ) );
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// <copyright file="BlockDiagGenerator.cs" company=".NET Foundation">
2+
// Copyright (c) .NET Foundation. All rights reserved.
3+
// </copyright>
4+
5+
#if NET47
6+
using System.CodeDom.Compiler;
7+
using System.IO;
8+
9+
namespace Kaleidoscope.Grammar
10+
{
11+
/// <summary>Extension class to generate a blockdiag file from a DGML graph</summary>
12+
/// <remarks>
13+
/// <para>This isn't a generator in the same sense that the <see cref="DgmlGenerator"/> and
14+
/// <see cref="XDocumentListener"/> are. Rather it is an extension class that allows
15+
/// generating a blockdiag diagram, from the directed graph created by the DgmlGenerator.
16+
/// The resulting ".diag" file is convertible to SVG form for documentation.</para>
17+
/// <para>
18+
/// The generated diagrams include a numbered element for binary operator expressions
19+
/// to indicate the precedence value that is diyamically evaluated for the expression.
20+
/// This is particularly useful for debugging custom operator precedence problems.
21+
/// </para>
22+
/// </remarks>
23+
/// <seealso href="http://blockdiag.com"/>
24+
public static class BlockDiagGenerator
25+
{
26+
public static void WriteBlockDiag( this DgmlGenerator generator, string file )
27+
{
28+
using( var strmWriter = new StreamWriter( File.Open( file, FileMode.Create, FileAccess.ReadWrite, FileShare.None ) ) )
29+
using( var writer = new IndentedTextWriter( strmWriter, " " ) )
30+
{
31+
writer.WriteLine( "blockdiag" );
32+
writer.WriteLine( '{' );
33+
++writer.Indent;
34+
writer.WriteLine( "default_shape = roundedbox" );
35+
writer.WriteLine( "orientation = portrait" );
36+
37+
writer.WriteLineNoTabs( string.Empty );
38+
writer.WriteLine( "// Nodes" );
39+
foreach( var node in generator.Graph.Nodes )
40+
{
41+
writer.Write( "N{0} [label= \"{1}\"", node.Id, node.Label );
42+
if( node.Properties.TryGetValue("Precedence", out object precedence))
43+
{
44+
writer.Write( ", numbered = {0}", precedence );
45+
}
46+
47+
if( node.Category == "Terminal")
48+
{
49+
writer.Write( ", shape = circle" );
50+
}
51+
52+
writer.WriteLine("];");
53+
}
54+
55+
writer.WriteLineNoTabs( string.Empty );
56+
writer.WriteLine( "// Edges" );
57+
foreach( var link in generator.Graph.Links )
58+
{
59+
writer.WriteLine( "N{0} -> N{1}", link.Source, link.Target );
60+
}
61+
62+
--writer.Indent;
63+
writer.WriteLine( '}' );
64+
}
65+
}
66+
}
67+
}
68+
#endif

Samples/Kaleidoscope/Kaleidoscope.Parser/DgmlGenerator.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ namespace Kaleidoscope.Grammar
1414
{
1515
/// <summary>Parse tree listener to generate a DGML Graph of the parsed syntax</summary>
1616
/// <remarks>
17-
/// This is similar to ther <see cref="XDocumentListener"/> but allows writing to a
17+
/// This is similar to the <see cref="XDocumentListener"/> but allows writing to a
1818
/// DGML file for visualizing in VisualStudio or any available DGML viewer.
1919
/// </remarks>
2020
public class DgmlGenerator
@@ -49,8 +49,7 @@ public override void EnterUnaryOpExpression( [NotNull] UnaryOpExpressionContext
4949

5050
public override void EnterExpression( [NotNull] ExpressionContext context )
5151
{
52-
base.EnterExpression( context );
53-
ActiveNode.Properties.Add( "ChildCount", context.ChildCount );
52+
ActiveNode.Properties.Add( "Precedence", context._p );
5453
}
5554

5655
public override void VisitTerminal( [NotNull] ITerminalNode node )
@@ -114,6 +113,8 @@ public void WriteDgmlGraph( string path )
114113
Graph.WriteToFile( path );
115114
}
116115

116+
internal DirectedGraph Graph { get; } = new DirectedGraph( );
117+
117118
private Node ActiveNode => NodeStack.Peek();
118119

119120
private Node Pop( )
@@ -130,7 +131,6 @@ private void Push( Node element )
130131
private const string ContextTypeNameSuffix = "Context";
131132

132133
private KaleidoscopeParser Recognizer;
133-
private DirectedGraph Graph = new DirectedGraph();
134134
private Stack<Node> NodeStack = new Stack<Node>();
135135
}
136136
}

Samples/Kaleidoscope/Kaleidoscope.Parser/Kaleidoscope.g4

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
//
77
grammar Kaleidoscope;
88

9-
// <Lexer>
10-
119
// Lexer Rules -------
1210
fragment NonZeroDecimalDigit_: [1-9];
1311
fragment DecimalDigit_: [0-9];
@@ -50,7 +48,6 @@ NOTEQUAL: '!=';
5048
PLUSPLUS: '++';
5149
MINUSMINUS: '--';
5250

53-
// <FeatureControlledKeywords>
5451
IF: {FeatureControlFlow}? 'if';
5552
THEN: {FeatureControlFlow}? 'then';
5653
ELSE: {FeatureControlFlow}? 'else';
@@ -59,16 +56,13 @@ IN: {FeatureControlFlow}? 'in';
5956
VAR: {FeatureMutableVars}? 'var';
6057
UNARY: {FeatureUserOperators}? 'unary';
6158
BINARY: {FeatureUserOperators}? 'binary';
62-
// </FeatureControlledKeywords>
6359

6460
LineComment: '#' ~[\r\n]* EndOfLine_ -> skip;
6561
WhiteSpace: [ \t\r\n\f]+ -> skip;
6662

6763
Identifier: [a-zA-Z][a-zA-Z0-9]*;
6864
Number: Digits_ ('.' DecimalDigit_+)?;
69-
// </Lexer>
7065

71-
// <Parser>
7266
// Parser rules ------
7367

7468
// built-in operator symbols
@@ -109,13 +103,47 @@ unaryop
109103
| SLASH
110104
| LEFTANGLE
111105
| CARET
112-
| userdefinedop
106+
| EXCLAMATION
107+
| PERCENT
108+
| AMPERSAND
109+
| PERIOD
110+
| COLON
111+
| RIGHTANGLE
112+
| QMARK
113+
| ATSIGN
114+
| BACKSLASH
115+
| UNDERSCORE
116+
| VBAR
117+
| EQUALEQUAL
118+
| NOTEQUAL
119+
| PLUSPLUS
120+
| MINUSMINUS
113121
;
114122

115123
// All binary operators
116124
binaryop
117-
: builtinop
118-
| userdefinedop
125+
: ASSIGN
126+
| ASTERISK
127+
| PLUS
128+
| MINUS
129+
| SLASH
130+
| LEFTANGLE
131+
| CARET
132+
| EXCLAMATION
133+
| PERCENT
134+
| AMPERSAND
135+
| PERIOD
136+
| COLON
137+
| RIGHTANGLE
138+
| QMARK
139+
| ATSIGN
140+
| BACKSLASH
141+
| UNDERSCORE
142+
| VBAR
143+
| EQUALEQUAL
144+
| NOTEQUAL
145+
| PLUSPLUS
146+
| MINUSMINUS
119147
;
120148

121149
// pull the initializer out to a distinct rule so it is easier to get at
@@ -133,7 +161,8 @@ primaryExpression
133161
| FOR initializer COMMA expression[0] (COMMA expression[0])? IN expression[0] # ForExpression
134162
| {IsPrefixOp()}? unaryop expression[0] # UnaryOpExpression
135163
| Identifier # VariableExpression
136-
| Number # ConstExpression;
164+
| Number # ConstExpression
165+
;
137166

138167
// Need to make precedence handling explicit in the code behind
139168
// since precedence is potentially user defined at runtime.
@@ -155,4 +184,3 @@ repl
155184
| expression[0] # TopLevelExpression
156185
| SEMICOLON # TopLevelSemicolon
157186
;
158-
// </Parser>

Samples/Kaleidoscope/Kaleidoscope.Parser/XDocumentListener.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public class XDocumentListener
1515
{
1616
public XDocumentListener( IRecognizer recognizer )
1717
{
18-
Document = new XDocument( );
18+
Document = new XDocument( ) { Declaration = new XDeclaration( "1.0", "utf-8", "yes" ) };
1919
Push( new XElement( "Kaleidoscope" ) );
2020
Recognizer = recognizer;
2121
}

Samples/Kaleidoscope/Kaleidoscope.Runtime/GeneratedResultAvailableArgs.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ namespace Kaleidoscope.Runtime
1111
public class GeneratedResultAvailableArgs<TResult>
1212
: EventArgs
1313
{
14-
public GeneratedResultAvailableArgs( TResult result, IRecognizer recognizer, IParseTree parseTree )
14+
public GeneratedResultAvailableArgs( TResult result, Parser recognizer, IParseTree parseTree )
1515
{
1616
Result = result;
1717
ParseTree = parseTree;
@@ -22,6 +22,6 @@ public GeneratedResultAvailableArgs( TResult result, IRecognizer recognizer, IPa
2222

2323
public IParseTree ParseTree { get; }
2424

25-
public IRecognizer Recognizer { get; }
25+
public Parser Recognizer { get; }
2626
}
2727
}

Samples/Kaleidoscope/Kaleidoscope.Runtime/IKaleidoscopeCodeGenerator.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ public enum DiagnosticRepresentations
2121
/// <summary>Generate a DGML representation of the parse tree</summary>
2222
Dgml,
2323

24+
/// <summary>Generates a BlockDiag representation of the parse tree</summary>
25+
BlockDiag,
26+
2427
/// <summary>Generate a textual representation of the Lllvm IR</summary>
2528
LlvmIR,
2629

0 commit comments

Comments
 (0)