Cached at:
08/25/26, 03:38 AM
# POP-2000, a lingua-franca POP-2 dialect
Source: [https://hitogata.neocities.org/POP-2000](https://hitogata.neocities.org/POP-2000)
> Written 2026\-08\-24
[Devine](https://wiki.xxiivv.com/site/devine_lu_linvega.html)\(of[Uxn](https://100r.co/site/uxn.html)fame\) and I have been talking a lot about[POP\-2](https://en.wikipedia.org/wiki/POP-2), a language from the 1970s originally used in the same circles as the first Lisp dialects\.
Devine had been looking into writing a new assembler for Uxn in a high\-level language to aid in bootstrapping a Uxn system, while I personally have always been interested in languages that would make for good "tiny compilers", and we came upon[POP\-2](https://en.wikipedia.org/wiki/POP-2)as something that would make for a good lingua\-franca between all of these tiny systems\.
## Tiny Compilers \(or, why I don't exactly care for concatenative programming\)
A bit of a crazy title, I know\. Don't get me wrong, I love the concatenative programming paradigm\- its way of forming new functions/constructs via juxtaposition and composition are really elegant\. But something that I tried to make clear in the paper I wrote for[ok](https://hitogata.neocities.org/ok.html)is that I don't feel particularly drawn to concatenative languages for those features\- rather, I like concatenative languages because they're*ridiculously*easy to write an interpreter/compiler for while \(often, not always\) allowing for some low\-level control\- at least, compared to the other languages that I like playing around with, like C or Odin\.
Coming from someone who originally made conlangs \(a LOT of conlangs\) before they'd even begun to touch computer programming, I care more about the langdev\-side of things than actually making software\. Specifically, when I'd work on an idea for a programming language, I typically had the following goals in mind:
- As easy as possible to implement an interpreter/compiler for a given system, ideally using basically no external tools/libraries for parsing or code generation
- Fairly "usable" \(rather vague and subjective, but effectively it "shouldn't look like an esolang", going by an "I know it when I see it" description\)
- Minimal syntax
- Minimal set of features, essentially only the bare minimum you'd need to bootstrap the compiler/interpreter \(which should be a goal basically as soon as you get the language working\)
- Some low\-level control/support for "systems programming", at least enough to where writing an operating system in the language should be feasible
- It should be hostable on a small system \(normally I'd set my minimum expectations to that of[ok](https://hitogata.neocities.org/ok.html), so ~16MiB of memory with room to spare, but[Uxn](https://100r.co/site/uxn.html)or perhaps something like a[6502](https://en.wikipedia.org/wiki/MOS_Technology_6502)would be even better\)
Concatenative languages, and languages targeting small/low\-level stack\-based VMs in general, just happen to map really well to these sorts of constraints\. I don't like concatenative languages because I think concatenation as a paradigm is inherently better, but rather, I like them because concatenation makes the implementation problem of creating a programming language*delightfully*small\. The benefits of this naturally stretch further into the classic arguments in favor of these types of systems \(i\.e\.[permacomputing](https://viznut.fi/texts-en/permacomputing.html)and whatnot\)\.
## A bit about POP\-2
If you look at the goals for language design that I outlined earlier and compare them to the goals outlined in the original[POP\-2 Papers](http://bitsavers.informatik.uni-stuttgart.de/pdf/univOfEdinburgh/POP-2_Papers_1968.pdf), they're basically identical:

Devine's[POP\-2 article](https://wiki.xxiivv.com/site/pop2.html)lays out a good overview of a POP\-2 dialect written to target Uxn, but to summarize, a minimal POP\-2 implementation supports declaring multiple variables at once with`vars x y z;`, declaring functions with`function myfunc a b;`\(followed by the function body and then an`end`\), basic`if`/`elseif`/`else`control\-flow, I/O with`=\>`, as well as looping via labels and gotos\. The*neat*thing about POP\-2 is that values manipulate an underlying stack\- from Devine's own article:
```
function sum x y;
x + y;
end
sum(5, 6) * 2;
```
Could just as easily be written*this*way, since the arguments to`sum`just get pushed onto the stack, and the value returned by`sum`also just gets pushed to the stack\- that, and encountering an operator like`\+`just looks ahead at the next element in the expression, pushes*that*to the stack, and then pops that and the next element off of the stack to add them together:
```
function sum x y;
x; + y;
end
5; 6; sum(); * 2;
```
With this inherently stack\-based nature, adding just some basic memory management, support for different\-width values for different systems, and a more universal I/O system would be all that's needed for a convenient, beginner\-friendly language that could be made to run on tons of tiny systems\- not as a replacement for those system's*existing*languages, but more as a social exercise by allowing newcomers to start off with a language that's both easy to learn and runs on tons of our small systems, while also being a language that's easy enough for*us*, the creators of these small systems, to implement a compiler for\.
## POP\-2000, a modest proposal
POP\-2000, \(or POP2K, we aren't completely set on a name yet\) is a standardized dialect of POP\-2 with the goal of adding the support for systems\-level stuff that we'd like on our small systems, while also being very clearly defined \(if you pour through the reference section of the POP\-2 papers, the grammar is defined but it's*very*hard to get through\)\.
I've been working on it basically nonstop for the past few days, while talking with Devine \(more like "pestering Devine incessantly"\) about what features should be supported or added over on the concatenative Discord server about the grammar, syntax, etc\.
I hope to have more details online soon\- again, this whole thing was nothing more than a "what\-if" less than a week ago\. I've just about completed a grammar for the language written in[EBNF](https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form)notation\. I'll create a Git repo with the "standard" soon enough \(debating not doing it on GitHub, what with the bad neglect and[relationship with ICE](https://www.vox.com/recode/2019/10/9/20906605/github-ice-contract-immigration-ice-dan-friedman)\), and as soon as that's created, I'll add it to this article\. In the meantime though, I figured I'd write about what's in the works\.
I also hope to write a kind of reference\-implementation for the language's compiler in C, initially targeting[ok](https://hitogata.neocities.org/ok.html), meaning soon our little VM is gonna have a high\-level language\!
### POP\-2000 EBNF grammar \(work\-in\-progress\)
For now, the*full grammar*I have so far in EBNF notation is as follows \(expect changes in the future\):
```
program = { element } ;
element = function
| vars
| imperative ;
function = "function" , identifier , [ params ] , ";" ,
[ function_body ] ,
"end" ;
const = "const"
vars = "vars" , var , { var } , ";" ;
var = identifier , [ ":" , ( integer | string ) ] ;
imperative = if
| ( statement_sequence , ";" ) ;
if = "if" , expression , "then" , [ body ] ,
{ "elseif" , expression , "then" , [ body ] } ,
[ "else" , [ body ] ] ,
"close" ;
body = { imperative | vars } , [ statement_sequence ] ;
statement_sequence = statement , { ";" , statement } ;
statement = goto
| labeled_statement
| expression_list ;
(* "return" is only allowed to occur WITHIN A FUNCTION BODY,
the parser should enforce this *)
goto = "goto" , identifier
| "return" ;
labeled_statement = label , { imperative } ;
label = identifier , ":" ;
expression_list = expression , { "," , expression } ;
expression = io ;
io = "=>" , primary
| assign ;
assign = "->" , primary
| apply ;
apply = "<>" , primary
| shift ;
shift = ( "<<" | ">>" ) , primary
| comparison ;
comparison = ( "<" | ">" | "=" | "!" ) , primary
| term ;
term = ( "+" | "-" ) , primary
| factor ;
factor = [ "*" | "/" | "%" ] , primary ;
primary = call
| reference
| quotation
| grouping
| index
| identifier
| literal ;
call = identifier , "(" , [ expression_list ] , ")" ;
reference = "#" , identifier ;
quotation = "@" , identifier ;
grouping = "(" , expression , ")" ;
index = "{" , expression , "}" ;
identifier = ( letter | "_" ) , { letter | digit | "_" } ;
literal = integer
| hexadecimal
| string ;
integer = digit , { digit } ;
hexadecimal = "0x" , hex_digit , { hex_digit } ;
string = "\"" , { string_char } , "\"" ;
string_char = ? any printable character except for double-quotes and backslash ?
| "\\\"" (* C-style escape for double quotes, with \" *)
| "\\" ; (* C-style escape for backslash *)
letter = "A" ... "Z"
| "a" ... "z" ;
digit = "0" ... "9" ;
hex_digit = digit
| "A" ... "F"
| "a" ... "f" ;
```