Language spec
This page catalogs every form in the language, one table row per form:
the syntax pattern, a real example, and what it means. Lowercase italic
words in patterns (expr, name, position…) are placeholders you fill
in; parts in [ ] are optional; … means “more of the same”.
rpic-only extensions are marked (ext).
A picture, annotated with the role of each line:
.PS
boxwid = 0.7 # assignment
A: box "start" # labeled object
arrow # object, no attributes
box "end" dashed # object + attributes
line -> from A.s down 0.4 # object + path attributes
.PEPicture
| Syntax | Example | Meaning |
|---|---|---|
.PS … .PE |
Everything between the two markers is the picture | |
.PS number |
.PS 3 |
Scale the finished drawing to that width, in inches |
Statements
One statement per line; ; packs several on one line. A statement is one
of the forms below.
| Syntax | Example | Meaning |
|---|---|---|
| object | arrow right 0.5 |
Draw something — see Objects |
Label: statement |
A: box "in" |
Name the object (or a point: P: (1, 0.5)) for later reference |
name = expr |
scale = 2 |
Set a variable; commas chain: a = 1, b = 2 |
up / down / left / right |
down |
Change the current direction for what follows |
{ statements } |
{ box; arrow } |
Run the statements, then restore position and direction |
print expr-or-string |
print sprintf("x=%g", x) |
Write to the diagnostic stream (stderr) |
copy “file” |
copy "lib.pic" |
Include another file, relative to the source |
reset [names] |
reset boxwid, boxht |
Restore variables (or all) to their defaults |
sh “cmd” |
Classic shell escape — tolerated, never executed | |
command “text” |
Classic raw output — tolerated, never injected | |
animate … (ext) |
animate A with "pop" |
Declare a GSAP animation (metadata only) |
class place “name” (ext) |
class A "critical" |
Attach a CSS class to an object already drawn |
Labels start with an uppercase letter (A, Sum, Out2); variables
with lowercase.
Control flow
| Syntax | Example |
|---|---|
if expr then { … } [else { … }] |
if n > 3 then { box } else { circle } |
for name = expr to expr [by [*] expr] do { … } |
for i = 1 to 10 by 2 do { move; box } |
by * expr multiplies the loop variable each step instead of adding —
handy for log scales.
Macros
| Syntax | Example |
|---|---|
define name { body } |
define node { circle rad 0.2 $1 } |
undef name |
undef node |
Bodies are expanded textually before parsing; $1 … $9 are the
call’s arguments: node("hi"). A macro body can hold objects, attributes
(a reusable style!), or whole sub-pictures — see
Variables & macros.
Objects
An object is a primitive followed by any number of attributes:
| Syntax | Example |
|---|---|
| primitive attributes… | box "hi" wid 1 dashed |
| “string” attributes… | "loose text" ljust — standalone text |
[ statements ] attributes… |
[ box; arrow; box ] at P — a block |
The primitives, by family:
| Family | Primitives |
|---|---|
| Closed (have an interior) | box · circle · ellipse |
| Open (are paths) | line · arrow · arc · spline · move |
| Annotation (ext) | brace · dot (junction marker, radius dotrad) |
Attributes
Attributes read left to right; when two conflict, the later one wins.
Dimensions
| Syntax | Example | Applies to |
|---|---|---|
wid expr · ht expr |
box wid 1.2 ht 0.5 |
boxes, ellipses, blocks |
rad expr |
circle rad 0.3 — also box rad 0.1 for rounded corners |
circles, boxes, arcs |
diam expr |
circle diam 0.6 |
circles |
same |
box same |
copy the previous object’s dimensions |
Paths (open objects)
| Syntax | Example | Meaning |
|---|---|---|
| direction [expr] | line right 2 · arrow up |
Go that way (default length if omitted) |
from position |
from A.s |
Start here instead of the current point |
to position |
to B.n |
End here |
by position |
by (0.5, 0.2) |
Step by a relative offset |
then |
right 1 then up 0.5 |
Chain another segment |
close (ext) |
line right 1 then up 1 close |
Close the path into a polygon |
chop [expr] [chop expr] |
chop 0.3 · chop 0.2 chop 0.4 |
Trim a fixed length off each end (bare chop trims circlerad) |
-> · <- · <-> |
line -> right 1 |
Arrowheads at end / start / both |
cw · ccw |
arc cw |
Arc direction |
Placement
| Syntax | Example | Meaning |
|---|---|---|
at position |
box at (1, 2) |
Center the object there |
with corner at position |
box with .sw at A.ne |
Put that corner there instead |
Style
| Syntax | Example | Meaning |
|---|---|---|
dashed [expr] · dotted [expr] |
dashed 0.05 |
Stroke pattern, optional pitch |
invis |
Draw nothing; geometry and anchors remain | |
thick expr |
thick 2.4 |
Stroke width in points |
thin |
thin |
Lighter stroke: ⅔ of linethick (rpic, pikchr-flavoured) |
fill [expr] |
fill 0.9 |
Gray fill: 0 = black … 1 = white |
outlined color |
outlined "seagreen" |
Stroke color |
shaded color |
shaded "honeydew" |
Fill color |
colored color |
colored "teal" |
Stroke and fill at once |
color is a CSS color name (quoted or bare: "gold" or gold), an
rgb(r,g,b) literal, a 0xRRGGBB hex number, or a variable/parenthesised
expression holding one. An unknown name raises an invalid_color warning. See
colour literals.
Text on objects
| Syntax | Example | Meaning |
|---|---|---|
| “string” | box "label" |
Attach text (several strings stack as lines) |
above · below |
"in" above |
Shift relative to the object |
ljust · rjust |
"tag" ljust |
Left/right-justify at the reference point |
rpic extensions (ext)
Each has a full page in the extensions chapter. Extension keywords are
contextual — outside attribute position they are ordinary variable
names, so classic sources using e.g. close = 1 keep their meaning.
| Syntax | Example | Meaning |
|---|---|---|
fit |
box "long label" fit |
Size the object to its text |
behind place |
box behind A |
Paint under another object |
class “name” |
box class "hot" |
CSS hook on the SVG group |
hatch · crosshatch |
box crosshatch |
Hatch-pattern fill |
hatchangle/hatchsep/hatchwid/hatchcolor |
hatchangle 30 |
Hatch controls |
gradient color color |
gradient "gold" "white" |
Two-stop linear gradient fill |
gradientangle expr |
gradientangle 90 |
Gradient direction (90 = bottom→top) |
opacity expr |
opacity 0.5 |
Fill opacity |
bracepos / labeloffset expr |
brace fine-tuning |
Positions and places
A place is a reference to something drawn (usable as a point — its center). A position is any point.
| Syntax | Example | Meaning |
|---|---|---|
Label[.corner] |
A · A.ne |
Named object, optionally a corner |
Label.Label… |
Chip.In |
Label inside a block |
last [kind][.corner] |
last box.e · last.c |
Most recent object (of a kind) |
Nth [last] kind |
2nd circle · 3rd last box |
By order of appearance |
( expr , expr ) |
(1.2, 0.5) |
Absolute coordinates |
position ± (expr,expr) |
A.e + (0.3, 0) |
Vector offset |
expr between p and q |
0.5 between A and B |
Interpolate two positions |
expr of the way between p and q |
1/3 of the way between A and B |
Same, reads like English |
( position , position ) |
(A, B) |
x of the first, y of the second |
Here |
The current position (capital H) |
Corners: .n .ne .e .se .s .sw .w .nw · .c/.center ·
.start/.end (paths) · .t/.b/.l/.r and long forms.
Expressions
| Syntax | Example |
|---|---|
| numbers, variables | 0.5 · boxwid |
| coordinates of a place | A.x · last circle.y |
| arithmetic | 2 * linewid + 0.1 — + - * / % ^ |
| comparison / logic | x >= 2 && y != 0 |
| functions | sqrt(2) · sin(a) · atan2(dy,dx) · max(a,b) · int(x) · rand() |
| strings | "hi" · sprintf("%.2f", x) · concatenation with + |
Environment variables
Numeric variables consulted as defaults; assign to change everything drawn afterwards. Variables are global — assignments inside blocks and macros propagate out, matching dpic.
| Group | Variables |
|---|---|
| Object defaults | boxwid boxht boxrad circlerad ellipsewid ellipseht linewid lineht movewid moveht arcrad |
| Arrows | arrowwid arrowht arrowhead |
| Text | textwid textht textoffset |
| Stroke & fill | linethick dashwid fillval |
| Picture | scale maxpswid maxpsht |
| (ext) canvas | margin topmargin rightmargin bottommargin leftmargin |
| (ext) math | texlabels — typeset $…$ labels as TeX |
| (ext) dots | dotrad — default dot radius (0.035) |
Lexical notes
- Comments run from
#to end of line. - A statement ends at a newline or
;; a trailing\continues the line, and a path also continues across a newline adjacent tothen. - Labels start with an uppercase letter; variables with lowercase.
- Inside macro arguments, a
$not followed by a digit and a non-continuation\are literal text — so LaTeX like$\beta$passes through unquoted.
Formal grammar
For implementers: the same language in compact EBNF
(? optional, * repeated, | alternatives).
Show the EBNF
picture ::= ".PS" number? EOL statement-list ".PE"
statement-list ::= (statement (EOL | ";"))*
statement ::= label ":" statement | object
| assignment ("," assignment)* | direction
| "{" statement-list "}"
| "if" expr "then" "{" statement-list "}"
("else" "{" statement-list "}")?
| "for" name "=" expr "to" expr ("by" "*"? expr)? "do"
"{" statement-list "}"
| "print" (expr | string) | "copy" string
| "reset" (name ("," name)*)?
| "define" name "{" body "}" | "undef" name
| "sh" string | "command" string
| "animate" place "with" string ("for" expr)?
("at" expr | "after" place)?
| "class" place string
object ::= primitive attribute* | string attribute*
| "[" statement-list "]" attribute*
primitive ::= "box" | "circle" | "ellipse" | "line" | "arrow"
| "arc" | "spline" | "move" | "brace" | "dot"
attribute ::= ("wid"|"width"|"ht"|"height"|"rad"|"radius"
|"diam"|"diameter") expr | "same"
| direction expr? | "from" position | "to" position
| "by" position | "then" | "close" | "chop" expr?
| "->" | "<-" | "<->" | "cw" | "ccw"
| "at" position | "with" corner "at" position
| ("dashed"|"dotted") expr? | "invis" | "solid"
| "thick" expr | "thin" | "fill" expr?
| ("outlined"|"shaded"|"colored"|"color") color
| string | "above" | "below" | "ljust" | "rjust"
| "fit" | "behind" place | "class" string
| "hatch" | "crosshatch" | "hatchangle" expr
| "hatchsep" expr | ("hatchwid"|"hatchwidth") expr
| "hatchcolor" color | "gradient" color color
| "gradientangle" expr | "opacity" expr
| "bracepos" expr | "labeloffset" expr
position ::= place | "(" expr "," expr ")"
| position ("+"|"-") "(" expr "," expr ")"
| expr "between" position "and" position
| expr "of" "the" "way" "between" position "and" position
| "(" position "," position ")" | "Here"
place ::= label ("." label)* corner?
| ordinal object-kind corner? | "last" object-kind? corner?
ordinal ::= NUMBER ("st"|"nd"|"rd"|"th") "last"?
object-kind ::= primitive | "[]" | "text"
corner ::= "." ("n"|"ne"|"e"|"se"|"s"|"sw"|"w"|"nw"|"c"|"center"
| "start"|"end"|"t"|"b"|"l"|"r"|"top"|"bottom"|"left"|"right")
expr ::= NUMBER | name | place "." ("x"|"y")
| expr op expr | "-" expr | "(" expr ")"
| func1 "(" expr ")" | func2 "(" expr "," expr ")"
| "rand" "(" ")"
op ::= "+"|"-"|"*"|"/"|"%"|"^"|"=="|"!="|"<"|"<="|">"|">="|"&&"|"||"
func1 ::= "sin"|"cos"|"tan"|"asin"|"acos"|"log"|"loge"|"exp"|"expe"
| "sqrt"|"int"|"floor"|"abs"|"sign"
func2 ::= "atan2"|"max"|"min"|"pmod"
string ::= QUOTED | "sprintf" "(" QUOTED ("," expr)* ")"
| string "+" string
color ::= QUOTED | name | "rgb" "(" expr "," expr "," expr ")" | HEX0X | expr
label ::= /[A-Z][A-Za-z0-9_]*/
name ::= /[a-z][A-Za-z0-9_]*/