Your first programming assignment is to implement a Scalable Vector Graphics viewer for a small subset of the SVG specification by writing a lexer/scanner and a top-down predictive parser by hand. SVG is a standard for describing two-dimensional graphics and animations in XML. Most web browsers are capable of rendering .svg files like the following, which shows the contents of the file min-grammar.svg:
<svg xmlns="http://www.w3.org/2000/svg"> <!-- rectangles --> <rect x="20" y="20" width="300" height="250" fill="red" /> <rect x="30" y="20" width="300" height="250" fill="blue" /> <rect x = "40" y = "20" width = "300" height = "250" fill="green" /> <!-- white circle on top of rectangles --> <circle cx="120" cy="150" r="60" fill="white" /> <!-- black diagonal line --> <line x1="0" y1="0" x2="300" y2="300" stroke="black" /> </svg>A rendering of the above SVG description can be seen by saving the following file to your drive and then opening it in your browser: min-grammar.svg
For this programming assignment, we provide the MiniSVG driver class and many utility routines to get you started. Download MiniSVGStart.tar. When executed with the following commands (or from within Eclipse by doing a Run As Java Application with TestCases/face.svg as the arguments):
% tar xf MiniSVGStart.tar
% cd MiniSVGStart/src
% javac driver/MiniSVG.java
% java driver.MiniSVG ../TestCases/face.svg
the MiniSVG driver opens
a window and renders a HARDCODED series of graphics commands for
the same set of objects described in the min-grammar.svg file.
When you close the graphics window, the program will exit.
The face.svg file specified above is only needed so that the MiniSVG driver
is able to open a valid file.
Currently the driver creates a PushbackReader for the given input file,
but parser.Parse.parse_svg()
does not actually read anything from the file. Your assignment
is to write lexer and a parser that parses the input .svg file and
renders the graphics elements specified in the .svg file. See
the TODO items in the MiniSVGStart/src/lexer/Lexer.java and
MiniSVGStart/src/parser/Parser.java.
svg -> SVG_START elem_list SVG_END
elem_list -> elem elem_list | epsilon
elem ->
RECT_START KW_X EQ NUM KW_Y EQ NUM KW_WIDTH EQ NUM KW_HEIGHT EQ NUM KW_FILL EQ COLOR ELEM_END
| CIRCLE_START KW_CX EQ NUM KW_CY EQ NUM KW_R EQ NUM KW_FILL EQ COLOR ELEM_END
| LINE_START KW_X1 EQ NUM KW_Y1 EQ NUM KW_X2 EQ NUM KW_Y2 EQ NUM KW_STROKE EQ COLOR ELEM_END
To recognize the above grammar, you should write a top-down, predictive
parser.
As each elem grammar rule is matched in the predictive parser, the
specified element should be rendered to a window and the appropriate
SVGReporter method should be called to output logging messages.
(See the parse_svg() method in MiniSVGStart/src/parser/Parser.java to
see examples of how this can be done with the provided IDrawSVG and
IReportSVG interfaces).
The parser queries the lexer for a stream of tokens. The lexer is actually the more difficult part of this programming assignment. Here are all of the regular expressions, specified using JLex syntax, for the terminals in the MiniSVG grammar. Note that {VAR} indicates textual substitution for VAR just as in many unix scripting languages.
// The set starting with EOL and ending with NOT_DASH
// are not terminals/tokens. They are just helper
// regular expressions.
EOL=\r|\n|\r\n
WHITE_SPACE=[\r\n\t]
DIGIT=[0-9]
NOT_GT=[^>]
NOT_DASH=[^-]
// Starting with SVG_START through NUM are the regular
// expressions for tokens that the lexer will pass back
// to the parser when scan() is called.
// Note that the COMMENT token will be skipped by the
// lexer and the parser will never see it.
SVG_START="<svg"{NOT_GT}*">"
SVG_END="</svg>"
RECT_START="<rect"
CIRCLE_START="<circle"
LINE_START="<line"
ELEM_END="/>"
KW_X="x"
KW_Y="y"
KW_WIDTH="width"
KW_HEIGHT="height"
KW_FILL="fill"
KW_CX="cx"
KW_CY="cy"
KW_R="r"
KW_X1="x1"
KW_Y1="y1"
KW_X2="x2"
KW_Y2="y2"
KW_STROKE="stroke"
EQ="="
COLOR=\""red"\"|\""blue"\"|\""green"\"|\""black"\"|\""white"\"
NUM=\"DIGIT+\"
COMMENT="<!--"({NOT_DASH})*"-->"
The MiniSVGStart project provides token classes (i.e., Token, Word, Color, Num)
and provides some utility methods for implementing the lexer.
As we will discuss in class, to implement the lexer the deterministic
finite automatas (DFAs) for all of the tokens can be combined into a single
DFA (or transition diagram) to guide implementation of the lexer.
To help ensure that your implementation results in error messages identical
to the reference MiniSVG implementation, use the DFA in
MiniSVG-lexer-DFA-simplified.pdf
for your lexer implementation.
The book describes the transition diagrams (also called deterministic finite automata) in Chapter 3.4.1 and provides some sample code in Chapter 2.6.
Notes about the grammar and the tokens:
Lexer generators such as JLex and parser generators such as JavaCUP are not allowed for this programming assignment.
Your program should include error handling through the use of the ParseException class for the following situations:
[LINE,POS] Expecting character 'X' and got 'D'.
[LINE,POS] Expect only numbers or colors in quotes.
[LINE,POS] Unexpected word 'theword'.
[LINE,POS] Unexpected character 'C'.
[LINE,POS] Expected token TOKENTAG got < OTHERTOKENTAG, otherinfo >.
[LINE,POS] Unexpected token < TOKENTAG, otherinfo >.
% svn log -r HEAD:1
% svn info
% svnlook tree REPOSITORY_PATH // svnlook must be issued on a department machine
Revision control is important.
See SVN notes for an example of how to
set up a subversion repository. Subversion will also be covered
in the discussion section.
Start this assignment by copying MiniSVGStart.tar to your directory. MiniSVGStart.tar untars to a MiniSVGStart/ directory that contains the src/ and TestCases/ subdirectories. The TestCases/ directory contains example input and output. You can check the visual component by comparing with what a web browser displays. For grading, we will be performing diffs on your text output with the text output from the reference compiler. The src/ directory has the following organization:
driver/
MiniSVG.java
exceptions/
...
lexer/
...
Lexer.java
Token.java
...
parser/
Parser.java
util/
...
The main for this code is in MiniSVG.java. The main function calls render(),
which in turn calls parser.parse_svg(). Currently parse_svg() hardcodes calls to the reporter and drawer routines, but it should be turned into a top-down parser that makes those calls based on what is being parsed. You will be putting implementation
into the Lexer.java and Parser.java files. The Lexer.scan() routine
returns Token instances to the Parser.
Set up a subversion repository for the programming assignment.
After setting up the subversion repository, check that the given MiniSVG runs and step through the code with a debugger to understand what it is doing.
Implement a lexer that can recognize the various tokens in the MiniSVG grammar.
Implement a predictive parser that reports what SVG elements were parsed and renders the elements to the screen.
If you send an example .svg file to the class mailing list, then we will send you back the reference compiler text output.
Here are some sites with SVG examples:
% svn log -r HEAD:1
% svn info
% svnlook tree REPOSITORY_PATH // svnlook must be issued on the machine where the repository is stored
tar cvf PA1_username.tar PA1
~cs453/bin/checkin PA1 PA1_username.tar
% tar xf PA1_username.tar
% cd PA1/src
% javac driver/MiniSVG.java
% java driver.MiniSVG ../TestCases/input.svg --batch