Archive for the ‘Code’ Category

ArcTo / ArcSegment like GraphicsPath.AddArc

This article gives a simpler interface (facade) to use the ArcTo Method… Providing a GraphicsPath AddArc like method.

public static GeometryDrawing GetArc(Rect rect, Angle start, Angle sweep){}

Today I implemented an adapter for GDI+ and WPF to draw similar objects. Simple ons like line, rectangle, ellipse,.. but I kinda struggled with arc??!!

public abstract void ArcTo(
	Point point,
	Size size,
	double rotationAngle,
	bool isLargeArc,
	SweepDirection sweepDirection,
	bool isStroked,
	bool isSmoothJoin
)

This is an Api that has way to much parameters if you ask me. All I need (and want) was a api like the AddArc on the GDI+ GraphicsPath which looks like :

public void AddArc(
	RectangleF rect,
	float startAngle,
	float sweepAngle
)

Which is all I need anyway.

In My Code I’m using the ArcTo method on a StreamGeometryContext instance (ArcSegment has a similair api so I’mmentioning it). First you have to move to the first point (which is done by calling BeginFigure) then you have to add a second point. Next argument Size has an interesting description on the MSDN documentation:

The width and height of an oval whose perimeter is used to draw the angle. If the oval is very rounded in all directions, the arc will be rounded, if it is nearly flat, so will the arc. For example, a very large width and height would represent a very large oval, which would give a slight curvature for the angle.

Ehh.. right.. how about just saying radius?

The next argument, rotationangle, can be done with a Matrix transform (rotate),.. so why it it there?

well the others make sense…

Well here is my facade to the ArcTo:

public static GeometryDrawing GetArc(Rect rect, Angle start, Angle sweep)

the way i like it,.. nice and simple.

public static GeometryDrawing GetArc(Rect rect, Angle start, Angle sweep)
        {
            GeometryDrawing ret = new GeometryDrawing();
            StreamGeometry geo = new StreamGeometry();

            //Set correct parameters
            SweepDirection sweepDir = sweep.Degrees < 0 ? SweepDirection.Counterclockwise : SweepDirection.Clockwise;
            bool isLargeArc = Math.Abs(sweep.Degrees) > 180;

            double cx = rect.Width / 2;
            double cy = rect.Height / 2;
            //Calculate start point
            double x1 = rect.X + cx + (Math.Cos(start.Radians) * cx);
            double y1 = rect.Y + cy + (Math.Sin(start.Radians) * cy);
            //Calculate end point
            double x2 = rect.X + cx + (Math.Cos(start.Radians + sweep.Radians) * cx);
            double y2 = rect.Y + cy + (Math.Sin(start.Radians + sweep.Radians) * cy);

            using (StreamGeometryContext ctx = geo.Open())
            {
                ctx.BeginFigure(new Point(x1, y1), false, false);
                ctx.ArcTo(new Point(x2, y2), new Size(cx,cy), 0, isLargeArc, sweepDir, true, false);
            }

            ret.Geometry = geo;
            return ret;
        }

!NOTE! The Angle class is just a simple converter form degrees to radians Nothing to worry about….

Here you can download a sample solution to get the demo working.

Or use this Extention Method in a static class..

public static void AddArc(this StreamGeometryContext ctx, Rect rect, double startRad, double sweepRad)
{
SweepDirection sweepDir = sweepRad < 0 ? SweepDirection.Counterclockwise : SweepDirection.Clockwise;
bool isLargeArc = Math.Abs(sweepRad) > Math.PI;
double cx = rect.Width / 2;
double cy = rect.Height / 2;
double x1 = rect.X + cx + (Math.Cos(startRad) * cx);
double y1 = rect.Y + cy + (Math.Sin(startRad) * cy);
double x2 = rect.X + cx + (Math.Cos(startRad + sweepRad) * cx);
double y2 = rect.Y + cy + (Math.Sin(startRad + sweepRad) * cy);
ctx.BeginFigure(new Point(x1, y1), false, false);
ctx.ArcTo(new Point(x2, y2), new Size(cx, cy), 0, isLargeArc, sweepDir, true, false);
}

your app might be bleeding inside with exceptions

Hi,..

Have you ever heard of “if it ain’t broke it’s bleeding inside” ?

This might be the case for your program, many of us use the try catch statement for catching exceptions. But you might be amazed by the shear number of exceptions that occur during runtime. We all know an exception is an exceptionally strong message that you need to respond to and not just smudge it away.

private void logMessage(string msg)
{
  try
  {
    File.AppendAllText(logfile, msg);
  }
  catch{} //ignore
}

There may be enough constructions like this throughout your code. When you throw an exception like that you need to think about this twice. At the very least tell other team members in comment why you did this.

So what happens when the drive is full? Well the entry is not written, but how bad is this?
What happens when the logfile value is configured (by app.config) with a non existing path? Is this a problem that needs to be handled?
What happens if you have insufficient rights to a certain location?

Think about it..

Let’s assume the”logMessage” function is not critical and we basicly do not care if does anything or not. You still have a performance issue. If the drive is full, why try to write again. Just set some flag and do not call File.AppendAllText… again.

Detecting the blood:

These are all just simple examples, endulge me and turn on the “Break when an exceptions is THROWN” Debug -> Exceptions, ath the “common Language Runtime Exceptions” check the Thrown and OK away. Now run your application.

If hardly nothing happens,.. good job!
If you feel like you are beeing shot at, time rethink some lines of code.

ANTLR common pitfalls

Personally I think ANTLR is a great tool, It has a steep learning curve and it has a few quirks. I hope the description here will help you find your problem, understand it and help you fix the issue.

Recognition problems

Recognizes number as ‘1234’ but not as ‘1’:
Example:

grammar number;

number :	INT;
DIGIT	:	'0'..'9';
INT	:	DIGIT+;

Explanation, the input such as ‘1’ or ‘4’ is just one char, it will be recognized as a ‘DIGIT’, not as an ‘INT’. You have two options :
– delete the DIGIT rule, and rewrite the INT rule as ” INT:’0′..’9′; ” (works)
– place the ‘fragment’ keyword in front of DIGIT. DIGIT will not be seen as a token.

Grammar Check Errors

The following token definitions are unreachable: INT (AntlrWorks 1.1.7)
The following token definitions can never be matched because prior tokens match the same input: INT (AntlrWorks 1.2) (AntlrWorks 1.3)

Example:

grammar number;

DIGIT:	'0'..'9';
INT	:	DIGIT;

What has INT to offer? As is it is a redundant rule. Probably you meant more than one number (thus matching 43) so make it INT : DIGIT+;

Another possibility:

factExpression:	Fact fact;
fact 	:	ID;

propertyExpression:	fact Property property;

property:	ID;

NEWLINE	:	'\r'?'\n';
WS	:	(' ' | '\t' | '\n' | '\r') { skip(); };

Fact	: 'There is ' ARTICLE //added extra space since it needs to be there
;

Property
:	'has '  ARTICLE //added extra space since it needs to be there
;

ID 	:	('a'..'z'|'A'..'Z')+;

ARTICLE
:	('a'|'an')
;

Here the error is “The following token…match the same input: ARTICLE”. ID can both match ‘a’ and ‘an’, but in this case ARTICLE is more important. Flip the ID and ARTICLE rule, and it’s fine.
More on Ambiguous rules.


syntax error: codegen: :0:0: unexpected end of subtree (AntlrWorks 1.1.7 & 1.2)
Example:

grammar number;
//number 	:	INT | FLOAT;
DIGIT	 :	'0'..'9';
INT	:	DIGIT+;
FLOAT	:	DIGIT* '.' DIGIT+;

You are working with a mixed grammar (both LEXER and PARSER).
You did not include any parser rules, please do so. Uncomment the ‘number’ parser rule.
Another possibility: is that the last line of your grammar is comment, just move it.

*Updated 10-nov-2009 : Added internal link to explain more on Ambiguous rules.;
*Updated 13-oct-2009 : Syntax Highlighting;
*Updated 25-jan-2010 : Small updates
*Updated 17-ock-2014 : Ending support for antlr 3. Thank you, it was fun!

Antlr, AST and rewriting rules.

Onward with my little project, with writing a SVG renderer. It’s intended as a study to get to know ANTLR and SVG.

The good folks of W3.org are so kind to publish a BNF that can be rewritten to an AntLr Grammar.

The goal of this post is to interpret:

M115 285 C115 400 285 400 285 285 C400 285 400 115 285 115 C285 0 115 0 115 115 C0 115 0 285 115 285 z

Into a drawing of some sort.

After reading the BNF it’s clear that the letters stand for commands, and are usually followed by one or more coordinates. EG. ‘M’ is the move to command, and ‘C’ is a curve command, and so on.

The Grammar for SVG will be posted soon in another post. This post is about rewriting.

AST tree SVG Path

AST tree SVG Path

When using the grammar, that I need to post, the AST output looks like this. My first thought was “so I’ve done all this an this is what I get!?” The Definitive ANTLR Reference: Building Domain-Specific Languages (Pragmatic Programmers) showed me I can rewrite and restructure the tree.

Learn by a Simpler Example:

Let say we want to parse a C# function header in an interface, which kinda looks like:

public void foo(string prm1, out int val1);

the ANTLR grammar would look something like:


grammar functionheader; 

function_header
	: access_modifier? return_type function_name LPAREN argument_list? RPAREN SEMICOLON;

 argument_list
	:	argument (COMMA  argument_list)?
	;  

argument : argument_accessor? type argument_name
	; 

argument_accessor
	:	'ref'|'out';

access_modifier
	:	 'public'|'private'|'protected'|'internal'; 

return_type
	:	type|'void';

type	:	'string'|'int'|'float'|'double'|'long'; 

argument_name
	:	NAME; 

function_name
	:	NAME;

//PARSER

COMMA	:	',';

SEMICOLON
	:	';'; 

NAME	:	CHAR(DIGIT|CHAR)+; 

CHAR 	:	('a'..'z'|'A'..'Z'|'_');

DIGIT
	:	('0'..'9'); 

LPAREN	:	'(';

RPAREN	:	')';

WHITESPACE
	: ( '\t' | ' ' | '\r' | '\n'| '\u000C') 	{ $channel = HIDDEN; } ;

Rewrite Rules, Omitting items

function_header : access_modifier? return_type function_name LPAREN argument_list? RPAREN SEMICOLON;

the parser rule above contains some parts that are not really interesting at all. The LPAREN RPAREN and SEMICOLON are not really interesting at all. They are just there to help separate the different aspects from the function header. So when ANTLR has done it’s job there is no need for them any more and we can leave them out with rewriting rules. Thus the rewrite statement looks like:

function_header :
access_modifier? return_type function_name LPAREN argument_list? RPAREN SEMICOLON
->access_modifier? return_type function_name argument_list?;

Resulting in:

ast tree function before rewrite

ast tree function before rewrite

ast tree function after rewrite

ast tree function after rewrite

You can clearly see the symbols being omitted.

Rewrite Rules, Creating children

Next big rewrite option is to structure the tree in a tree you are comfortable with to walk/interpret in your own code. The symbol that is used is the ‘^’ sign. Also used in to describe the POW function.

There are two way’s of doing it. This first one is to put it in your parser rule like:

function_header
: access_modifier? return_type function_name^ LPAREN argument_list? RPAREN SEMICOLON;
Result of rewrite rule

Result of rewrite rule

making the function_name the root^  (Do not use rewrites ANTLR will throw errors in your face).

The second method is to use it in your rewrite rule (my personal favorite) :

function_header
: access_modifier? return_type function_name LPAREN argument_list? RPAREN SEMICOLON
 -> ^(function_name access_modifier? return_type argument_list? )
rewrite rule

rewrite rule

so that is “^(root child child … child)”, you may also write “^(root child..child ^(subroot child..Child) child..child)”. etc..

Rewrite Rules, Adding some extra nodes

To make the AST tree just right, so your code can handle your AST much better you may need to insert some tokens. You have seen some rewriting rules, with those you can insert some ‘dummy’ nodes. Just tell ANTLR you need some extra tokens like this:

tokens
{
FUNCTION;
NAME;
MODIFIER;
RETURNTYPE;
PARAMS;
TYPE;
ACCESSER;
}
function_header
: access_modifier? return_type function_name LPAREN argument_list? RPAREN SEMICOLUMN
-> ^(FUNCTION ^(NAME function_name) ^(MODIFIER access_modifier)? ^(RETURNTYPE return_type) ^(PARAMS argument_list)? )
;

note there is a difference in opt1=”^(PARAMS argument_list)?” and opt2=”^(PARAMS argument_list?)”

opt1 will ommit the PARAMS token from the tree when arument_list is empty. While opt2 will show a PARAMS token, but it won’t have children when the agument_list is empty.

here is a final listing and a sample output of the AST:

The AST tree fully manipulated.

The AST tree fully manipulated.

grammar functionheader;
options
{
    output=AST;
}
tokens
{
	FUNCTION;
	NAME;
	MODIFIER;
	RETURNTYPE;
	PARAMS;
	TYPE;
	ACCESSER;
}
function_header
	: access_modifier? return_type function_name LPAREN argument_list? RPAREN SEMICOLUMN
	-> ^(FUNCTION ^(NAME function_name) ^(MODIFIER access_modifier)? ^(RETURNTYPE return_type) ^(PARAMS argument_list)? )
	;
argument_list
	:	argument (COMMA  argument_list)?
	->	argument argument_list?
	; 
argument : argument_accesser? type argument_name
	-> ^(argument_name (ACCESSER argument_accesser)? TYPE type )
	;
argument_accesser
	:	'ref'|'out';
access_modifier
	:	 'public'|'private'|'protected'|'internal';
return_type
	:	type|'void';
type	:	'string'|'int'|'float'|'double'|'long';
argument_name
	:	NAME;
function_name
	:	NAME;
//PARSER
COMMA	:	',';
SEMICOLUMN
	:	';';
NAME	:	CHAR(DIGIT|CHAR)+;
CHAR 	:	('a'..'z'|'A'..'Z'|'_');
DIGIT
	:	('0'..'9');
LPAREN	:	'(';
RPAREN	:	')';
WHITESPACE
	: ( '\t' | ' ' | '\r' | '\n'| '\u000C') 	{ $channel = HIDDEN; } ;

this file contains the grammar.

Please, if you have questions or comments, let us know.

Simple Calculator with Antlr.

For quite some time I’ve been interested in creating scripting languages to make existing applications more flexible than thought possible. After writing a couple of parsers I’ve stumbled upon ANTLR (ANother Tool for Language Recognition) which is a Lexer and Parser all in one.

Although I’m aware of the existence of a couple of other tools, such as “yacc, lex,gold parser,.. ” this is the first tool I’m going to try out. I see a appliance to read svg files, and generate code (c#/Java/vb/ada) that will draw the figure.

Here is a preview of what this sample aims to:


But first things first, I longed to create a simple calculator, helping me to asses the possibilities of ANTLR, with a little help from :The Definitive ANTLR Reference: Building Domain-Specific Languages (Pragmatic Programmers) (Rather helpfull), I’ve managed the job quite well.

Since I’ve seen some questions on the Internet requesting a simple example for a simple calculator grammar, here it is:

grammar SimpleCalc;

tokens {
PLUS 	= '+' ;
MINUS	= '-' ;
MULT	= '*' ;
DIV	= '/' ;
RPAREN	= ')' ;
LPAREN	= '(' ;
ASSIGN	= '=' ;
}

/*----------------
* PARSER RULES
*----------------*/

prog :		stat+;
stat :		expr NEWLINE
	|	ID ASSIGN expr NEWLINE
	|	NEWLINE; 			//Do nothing

expr 	:	multExpr ((PLUS | MINUS )multExpr)*;

multExpr:	atom ((MULT | DIV) atom )*;

atom 	:	INT
	|	ID
	|	LPAREN expr RPAREN;

/*----------------
* LEXER RULES
*----------------*/

ID 	:	('a'..'z'|'A'..'Z')+;
INT 	:	'0'..'9'+;
NEWLINE :	'\r'?'\n';
WS 	:	(' '|'\t'|'\n'|'\r')+;

The grammar above can handle expressions such as:

1+2*3
a=4-5
c=a*(6/2)

Now one has to add actions to the rules these will look like:

atom returns[int value] <==Tell Antlr this rule is implemented as a function, returning an int.
: INT {$value = int.Parse($INT.text);} <==The return value '$value' is assign the parsed as an integer string value of int.

Now all you need to do is fill every thing in. When an ID follow by an assignment (a=6) is encounter it will be placed in a Dictionary.

After adding the appropriate actions the calculator is finished, it works internally with an int, so all divisions are integer divisions!. Adaptation for doubles will be no problem at all, but is left to you.

grammar SimpleCalc3;

options
{
language=CSharp;
}

tokens {
PLUS 	= '+' ;
MINUS	= '-' ;
MULT	= '*' ;
DIV	= '/' ;
RPAREN	= ')' ;
LPAREN	= '(' ;
ASSIGN	= '=' ;
}

@members
{
public static System.Collections.Generic.Dictionary IDTable = new System.Collections.Generic.Dictionary();

public static void Main(string[] args)
{
  Console.WriteLine("type '@' to quit...");
  string line = "";
  while (true)
  {
      line = Console.ReadLine();
      if (line.Contains("@"))
        break;

      SimpleCalc3Lexer lex = new SimpleCalc3Lexer(new ANTLRStringStream(line+Environment.NewLine));
      CommonTokenStream tokens = new CommonTokenStream(lex);
      SimpleCalc3Parser parser = new SimpleCalc3Parser(tokens);

      try
      {
        parser.prog();
      }
      catch (RecognitionException e)
      {
        Console.Error.WriteLine(e.StackTrace);
      }
  }
}

}

/*----------------
* PARSER RULES
*----------------*/

prog :	stat+;
stat :	expr NEWLINE			{System.Console.WriteLine($expr.value);}
|	ID ASSIGN expr NEWLINE		{IDTable[$ID.Text] =$expr.value;}
|	NEWLINE; 			//Do nothing

expr returns[int value]
:	a=multExpr {$value = $a.value;} (
PLUS b=multExpr {$value+=$b.value;}
|
MINUS b=multExpr{$value-=$b.value;})*;

multExpr returns[int value]
:	a=atom {$value = $a.value;} (
MULT b=atom {$value*=$b.value;}
|
DIV b=atom{$value/=$b.value;})*;

atom returns[int value]
:	INT				{$value = int.Parse($INT.text);}
|	ID				{if (IDTable.ContainsKey($ID.Text)){$value = IDTable[$ID.Text];}else{System.Console.WriteLine("ID does not exist");}}
|	LPAREN expr RPAREN		{$value = $expr.value;};

/*----------------
* LEXER RULES
*----------------*/

ID :	('a'..'z'|'A'..'Z')+;

INT :	'0'..'9'+;

NEWLINE :	'\r'?'\n';

WS :	(' '|'\t'|'\n'|'\r')+ {Skip();};

If you desire a working example, please download this file, Included are the .net binaries (.dll) from the antlr’s website. When your enviroment path is set correctly to the c# compiler, you will be able to run make.cmd to create the console application.
If you want to download the ANTLR binaries yourself, get them at the original site, look for “ANTLR Tool Binaries”.

enjoy!

*Update 24-aug-2008: Added the grammars to the zip.
*Update 27-apr-2009: Added sample movie.
*Update 13-oct-2009: Syntax Highlighting

Please, if you have questions or comments, let us know.