HW 4: Pic2PS, Part 1
Overview
The pic
language is a domain-specific language (DSL) for drawing pictures.
In this assignment, you will implement a compiler/translator
that turns a useful subset of the pic
language into PostScript. In particular,
you will:
-
Write helper functions that generate PostScript code (e.g., to draw a box).
-
Use the helper functions to implement an evaluator for
pic
. The evaluator takes as input apic
AST and generates as output the corresponding PostScript code.
Specifications
There are two specifications that come with this assignment: one for pic
and one for
PostScript. Your compiler must correctly translate the pic
semantics to PostScript, so
it is important that you read and understand these parts, and keep them beside you for
reference as your implement pic2ps
.
We recommend you skim through them now, then read them in more detail before and as your work on the assignment.
Materials
Use the assignment workflow and the link provided on Piazza to get access to this week’s files.
Style, Elegance, and Errors (10%)
Your code should be reasonably well-commented in order to help the graders understand your code. Ten percent of your grade will be based on clarity (e.g., well-documented with comments, good variable names, and generally easy it to understand how your code works) and elegance (e.g., factoring out common code rather than duplicating sections of code).
As always, to get credit, your final submission may not have syntax or type errors. Because you’re coding to a specification, submitted functions must have the exact names and types given in the assignment (though you are encouraged to define other helper functions, as needed).
Your task: Write useful comments and use good names for variables and functions, as you write your code. To make your code elegant, you may need a few iterations of writing—it’s often difficult to write elegant code on the first try. Instead, focus on writing correct, readable code. Then, focus on making it elegant (perhaps by enlisting help from a grutor or professor).
Part 1: A PostScript Library (28%)
The PostScript
module defined in the file PostScript.hs
is supposed
to contain helper functions that generate PostScript code for most of the
shapes needed for pic
.
For example, the function
circleCode :: XYPos -> Scalar -> [PostScriptLine]
is supposed to generate PostScript code (i.e., a list of strings, where each string is a line of PostScript code) that draws a circle.
Your task: Implement the undefined functions in PostScript.hs
.
Comments / Suggestions
Understand before you code. Be sure you feel relatively good about
PostScript programs, especially the stack-based model and how to draw shapes.
Also, read over the given code, especially in PostScript.hs
, to understand
what’s already been implemented, to see what is required of you, and to start
getting some ideas for your implementation.
Implementation techniques. For debugging purposes, it can be handy to have your code add comments to the generated PostScript output itself, but you are not required to do so.
Testing. Because there are many ways to
generate PostScript for a given picture, we can’t auto-test the string outputs
of your functions. You can manually test your functions by loading
PostScript.hs
into ghci
, then using emitCode
with the name of an output
PostScript file
and whatever lines of PostScript you want to check. For example:
emitCode "testtext.ps" (textCode (3,4) ["Strings centered", "at (3,4)"])
emitCode "testbox.ps" (boxCode (5,5) 2 2)
You can then look at your output file (e.g., testtext.ps
) with gv
on knuth. On a Mac, you should run
pstopdf
or ps2pdf
on your PostScript file to get a PDF file, and then open
the PDF file with Preview.
Part 2: A Pic-to-PostScript evaluator (62%)
This assignment comes with a number of other files, most of which implement a
parser that translates pic
concrete syntax into abstract syntax.
The file PicAST.hs
defines the abstract syntax, as Haskell data types.
The main code for drawing pictures is in PicEvaluator.hs
. In this file, the core of
evaluation happens in the function
doElem :: Element -> State -> ([PostScriptLine], State)
Given pic
’s current state (current page position and current direction) and a
pic
element, the doElem
function yields lines of PostScript code for that
command, along with the new page position and the new current direction.
Unfortunately, this function is unfinished, and there are a number of very handy
helper functions that are not being used (yet).
Your task: Complete the pic
evaluator, by finishing doElem
.
Comments / Suggestions
Understand before you code. Be sure you feel relatively good about
pic
programs, especially the semantics.
Do some planning before you start writing your code. At a minimum, you should
decide how you’ll break this problem down into helper functions (and possibly
how those functions will be broken down in turn). You may also want to see what
helper functions already exist (I’m looking at you, PicEvaluation.hs
and
Coords.hs
!). Don’t overlook the provided comments.
Use good programming practices. Be sure to comment your code well. You might need to read / modify this translator in a later assignment; and, besides, it makes it easier for the course staff to help you with your code.
Using your evaluator. Once doElem
is complete, you can use the predefined function
run
to create a PostScript output file from a pic
input
file. Specifically, load pic2ps.hs
in ghci
and type run "test1.pic"
.
The run
function reads the input file test1.pic
, runs it through the lexer,
the parser, and your translator, and puts the PostScript output into the
file test1.ps
.
Testing. Because you are producing images and because there are many ways to
generate PostScript for a given pic
AST, we can’t directly test the code
generated by the evaluator. However, we can test that the evaluator
implements pic
’s semantics for direction and position. We’ve provided a few
tests that do so, which you can run with the command:
ghc test/StateSpec.hs -e "StateSpec.main"
We recommend that you also check your generated PostScript files against the
output of the “official” pic
implementation, using the groff
procedure from
Lab. The picture may appear on a different part of the page, but the shapes and
sizes should match.
Where to go from here
Check out the paper on “Little Languages” by
Jon Bentley! It uses the pic
language as an example.