Reference

Start here

You have the sources. This page is what to do with them - from the first program that prints a number, to the plugin built from scratch, to the engine embedded in a project you already have.

Every command here is one that runs. The parser side is compiled and executed by the build matrix on four targets; the plugin and the demo come from their own build scripts.

Pick your way in

The first program

Nothing to install, nothing to register. Two paths on the command line and a file with nine lines in it.

program Hero;

{$APPTYPE CONSOLE}

uses
  CalcUtils;

begin
  Writeln(AsInteger('2 + 2'));
end.
  1. Unpack the sources anywhere

    The library is plain Pascal: no build step, no generated headers, no package manager. Say it lives in C:\lib\pascal-mathparser.

  2. Point the compiler at two folders

    src is the parser, jit is the accelerator. The second is optional - leave it out and the interpreter answers.

  3. Compile and run

    # from the folder that holds the sample
    cd samples/docs
    
    # Delphi
    dcc64 -U"..\..\src" -NS"System;System.Win;WinApi" hero.dpr
    ./hero
    
    # Free Pascal, any platform
    fpc -MDelphi -dNOFORMS -dNOGRAPHICS -Fu"../../src/compat" -Fu"../../src" -Fi"../../src" hero.dpr
    ./hero

It prints 4. That file is samples/docs/hero.dpr in the repository, and the build matrix compiles and runs it on every target before a release, so it cannot rot.

Why the Free Pascal line carries four switches

src/compat holds stand-ins for units that exist only on Windows, and -Fi points at the include files. Without either of them the build stops - measured on Windows as well, where it fails in Parser.pas long before any GUI unit is reached.

-dNOFORMS -dNOGRAPHICS leave the GUI out. On Windows the build survives without them; outside Windows it does not, because the thread unit reaches for Forms. One set that works everywhere is worth more than two recipes, one of which the reader has to pick correctly.

It is the same set the Linux matrix uses in tests/build_parser_linux.sh, not a shortened version of it.

Delphi: into a project you already have

Two ways. The first puts the components in the palette and is what most people want; the second is three lines in the project options and leaves the IDE untouched.

With the palette

  1. Build the two runtime packages first

    packages/delphi/crosspascal_parser.dpk, then crosspascal_parserjit.dpk. Open each and use Project, Build. The design-time package requires both, and the IDE does not build them for you: installing without them stops at E2202 Required package 'crosspascal_parser' not found.

  2. Open the design-time package

    packages/delphi/crosspascal_parser_dsgn.dpk. It contains the registration unit and nothing else.

  3. Press Install

    A palette page named CrossPascal appears with the parser, the calculator, the value list, and the threads. Drop TMathParser on a form and it works from the Object Inspector.

  4. Add the library path once

    Tools, Options, Library, Library path - add src and jit. Without it the IDE finds the components but the compiler does not find the units.

Without the palette

Project, Options, Delphi Compiler, Search path: add src, and jit if you want the accelerator. Then create the parser in code as the samples do. Nothing is installed into the IDE, which is the point when the project is built on a machine you do not control.

The handle type, once

Registering your own function needs a handle variable, and its type must be TFunctionHandle from ParseTypes - not the plain NativeInt. On Delphi 12 and later the library defines its own NativeInt, the var parameter refuses the system one, and the compiler says only that no overload matches.

Lazarus: the same, with packages

  1. Open the package

    Package, Open package file, then packages/lazarus/crosspascal_parser.lpk. Compile it.

  2. Add the accelerator if you want it

    crosspascal_parserjit.lpk, same way. It depends on the first package, so open them in that order.

  3. Use in a project

    Package, Open recent, then Use, Add to project. Installing into the IDE is only needed for the palette.

Linux and FPC: no Lazarus at all

This used to require LazUtils for a single call. It no longer does: the library needs the RTL and nothing else. A console program on Ubuntu:

# one file, no project, no Lazarus
fpc -MDelphi -O2 -dNOFORMS -dNOGRAPHICS \
    -Fu~/pascal-mathparser/src/compat \
    -Fu~/pascal-mathparser/src \
    -Fu~/pascal-mathparser/jit \
    hero.dpr
./hero

The two defines switch off the parts that would otherwise pull in a widgetset: forms and graphics. A console program uses neither.

Compiling this way writes a .ppu and an .o next to every library source it touches. That is how FPC works when the units come from -Fu paths, and it is harmless on its own - but Lazarus refuses to build a package whose source folder holds compiled units, so delete them before you open crosspascal_parser.lpk, or keep the console build in a copy of the repository.

What you getWhere
The interpretereverywhere, including 32-bit and wasm
The IR executoreverywhere the JIT layer is compiled in
x86-64 machine codex86-64 only; elsewhere the tier below answers

Building GraphBuilder, the Notepad++ plugin

The plugin is the parser and the plotting engine behind a panel. It builds from either compiler.

Lazarus

# from the plugin repository
pwsh -File build-lazarus.ps1

# and put it where Notepad++ looks for plugins
pwsh -File install.ps1

This is the build that ships. It wants the parser and the plotting engine cloned beside the plugin, because the project file names them by relative path, and it wants WEBVIEW4DELPHI pointing at a checkout of that library - the script registers its Lazarus package itself.

Delphi

# from the plugin repository
pwsh -File build.ps1

# and put it where Notepad++ looks for plugins
pwsh -File install.ps1 -Delphi

The same sources through the other compiler; the switch is what tells the installer which of the two to take. It picks up the parser, the accelerator, and the plotting engine from their folders, and no packages need to be installed for it. Both scripts build x64 and only x64: that is what this plugin supports. Notepad++ itself also ships 32-bit and ARM64 builds, and neither of them will load this one.

Embedding the web version

The demo on this site is not a video and not a screenshot: it is the real parser compiled to WebAssembly, computing in your browser. The same three files drop into any page.

  1. Take three files

    parsewasm.wasm - the engine; wasmhost.js - the bridge; and the page that talks to it. They sit next to each other and are loaded as static files. No server code is involved.

  2. Serve them over http

    WebAssembly is fetched, so file:// will not do. Any static server works:

    python -m http.server 8080
  3. Or rebuild the engine yourself

    Needs the FPC cross compiler for wasm32-wasip1, built from the FPC sources. The two commands run in different folders, so each says where it starts:

    # in a checkout of the FPC sources
    make crossall crossinstall OS_TARGET=wasip1 CPU_TARGET=wasm32
    # in a checkout of this repository
    pwsh -File engine/build_wasm.ps1
What the browser cannot do

The x86-64 accelerator does not run in a sandbox: it emits machine code, and a browser executes WebAssembly instead. The demo therefore runs the interpreter, and the speed figures on this site are measured natively and stated as such.

Embedding the plotting component

The panel you see in the plugin is a component. It takes formulas as text and draws them; the parser underneath is the same one.

  1. Add the paths

    The plotting engine lives beside the parser. Add its folder to the search path along with src; on Lazarus open crosspascal_graph.lpk instead.

  2. Drop the component on a form

    With the design-time package installed it is on the CrossPascal palette page. Without it, create the component in code - it is an ordinary TCustomControl descendant.

  3. Give it formulas

    The component owns the parser, samples the curve across threads and draws the result. Redirection is what makes the threads safe: every worker gets its own copy of the script, redirected at its own variables.

On FPC the drawing goes through the LCL canvas, so a project with the plotting component does need Lazarus - unlike the parser alone, which does not.

Where to look next