Table of Contents

Name

psfc - compile a simple functional language into PostScript

Synopsis

psfc [-i input] [-o output] [-s]

Description

PostScript is a general purpose programming language, mainly used for typesetting. Occasionally, however, it is useful to use PostScript for other purposes than typesetting. For example, when using the Latex "PSTricks" package to typeset graphs, the function to be typeset must be written in PostScript.

Unfortunately, PostScript is not the easiest of languages to learn. If you only have to use PostScript sparingly, and if you use PostScript only as a calculator (for instance, in the PSTricks example), you can write your program in a simple functional language instead, and use psfc to compile your program into PostScript.

For example, to define the factorial function in PostScript, we must use


/fac {
1 dict
begin
/n exch def
    n 0 eq {1 } {n n 1 sub fac mul } ifelse 
end
} def

Using psfc however, you can simply define the factorial function as


fac(n) = if n == 0 then 1 else n * fac(n - 1) endif

Options

-i
specify the input file (if unspecified, use stdin)
-o
specify the output file (if unspecified, use stdout)
-s
generate a stand-alone PostScript file. If this option is used, two extra commands will be added to the PostScript file. These commands are specific to the GhostScript interpreter for PostScript and make GhostScript output the result of the calculation to standard output and exit GhostScript when the calculation is finished.

Informal Language Description

A psfc program consists of a number of function definitions. A function definition is specified like this:


name(x, y, ..) = expr

where name is the name of the function, x, y are parameters to the function. A function can have an arbitrary number of parameters (with a maximum of 256), or none at all. If the function has no parameters, no brackets should be used. For example:


function my_const_function = ...

Important: Every psfc should have a function called main. This function will be the "top-level" function that gets evaluated by the PostScript interpreter. Function "main" should not have any parameters.

Examples

This example shows the basic rules outline above:


five = 5
f(x) = x + five
g(x,y) = x * y
main = g(f(2), 3 + 4)

The following example shows a program to calculate 5!:


fac(n) = if n == 0 then 1 else n * fac(n - 1) endif
main = fac(5)

Finally, an example that shows that function can return boolean values:


i(x) = if x == 0 or x == 1 then true else false endif
h(x) = if i(x) == true then 5 else 10 endif
main = (h(0) + h(1)) * h(2)

To compile and run any of these programs, use


psfc -i example1.pfc -o example1.ps -s
gs example1.ps

USING psfc WITH PSTricks

If you want to use psfc with the Latex PSTricks package, you should define a function "main" that calculates the y value for a particular x (the variable "x" will be made available). For example, the following simple program draws the function f(x) = x:


main = x

Note that if you compile this program for use with PSTricks, the -s parameter should not be used.

Formal Language Description

The psfc language is defined by the following context free grammar:


pfc      ::= fun_def*
fun_def  ::= IDENT fun_args ’=’ expr
fun_args ::= ’(’ IDENT (’,’ IDENT)* ’)’
expr     ::= IF cond THEN expr ELSE expr ENDIF
          |  expr ’+’ expr1
          |  expr ’-’ expr1
          |  expr1
expr1    ::= expr1 ’*’ expr2
          |  expr1 ’/’ expr2
          |  expr2
expr2    ::= VALUE
          |  IDENT args 
          |  ’(’ expr ’)’
args     ::= ’(’ expr (’,’ expr’)* ’)’
cond     ::= cond OR cond1
          |  cond1
cond1    ::= cond1 AND cond2
          | cond2
cond2    ::= expr BOOLOP expr2
          | ’(’ cond ’)’

Note the precendence order implicit in the grammar: brackets, then multiplication and division (evaluated left to right), and finally addition and subtraction (also evaluated left to right). Similarly for boolean expressions, brackets have the highest precedence level, then AND, and finally OR.

Whitespace is ignored, as are comments. Comments start with "--" and run to the end of the line. Leaves to specify the lexical tokens used in the grammar:


IDENT    ::= [a-zA-Z_][a-zA-Z_0-9]*
INT      ::= [+-]?[0-9]+(#[0-9]+)?
REAL     ::= [+-]?[0-9]*.[0-9]+(E[+-]?[0-9]+)?
VALUE    ::= INT|REAL

Author

Edsko de Vries (edsko at edsko dot net)


Table of Contents