RPIC

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
.PE
start end

Picture

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

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_]*/