# Write an interpreter for my new esoteric language PointerLang

I designed a language in which pointer arithmetic is the main tool of programming.

Here are some examples.

(print 0 to 8)
=9[>1=9-*-1.>-1-1]

(print 1 to 10 with spaces in between, character literal extension used)
=1[.>1=10-*-1[>1=' '!>-2+1;-2];1]='\n'!

(compute the factorial of 10)
=10>1=*-1-1[>-1**1>1-1]>-1.

(print "hi")
=104!=105!

(print "hi" with extension for arrays)
={104,105,0}[!>1]

(print "Hello, world!" with extension for C-style string literals)
="Hello, world!"[!>1]


## Language Specification

The language definition is very simple. You will understand very easily if you have experience with C, but I will not assume so.

Every program in PointerLang has the pointer, in short, P. You can think it as a hidden single global variable, which you can control by using commands. P initially points to the beginning of the array. Every element in the array has the type int which is a 32-bit signed integer.

For C programmers

int32_t *P = malloc(1000);


In PointerLang, there are commands and arguments. An argument is an int which must come after a command. All commands are executed from left to right unless specified otherwise. The following is the list of commands. A stands for argument. A command without A means it does not take an argument. A command with A must take an argument. Inside the parentheses is the equivalent C expression.

• =A : assign A at P (*P = A)
• +A : add A at P (*P += A)
• -A : subtract A at P (*P -= A)
• *A : multiply by A at P (*P *= A)
• /A : divide by A at P (*P /= A)
• >A : move P by A (P += A)
• . : print the integer at P (printf("%d", *P))
• ! : print the integer at P as ASCII (printf("%c", (char)*P))
• [ : if the value at P is 0 go to the command after the next ] (while (*P) {)
• ] : go to the previous [ that is the matching pair (})
• ;A : if A is positive, go to the command after the Ath ] coming next; if A is negative, go to the Ath [ coming before; if A is 0, do nothing.

An integer literal is an argument.

The following two are special arguments that take an argument.

• -A : evaluated as an argument having the same absolute value as A and the opposite sign of A; unary minus
• *A : move P by A, evaluate the value at P, move P by -A (P[A])

All comments in PointerLang are between parentheses (comment).

## Example Program

This program which counts from 1 to 10 is a good example to complete your understanding.

(print 1 to 10 with spaces in between)
=1[.>1=10-*-1[>1=32!>-2+1;-2];1]=10!


Be careful when you interpret -*-1. - is the command and *-1 is the argument. An integer literal effectively indicates the end of a command-argument pair.

It can be translated to C with 1-to-1 correspondence as

int main(void) {
int32_t *P = malloc(1000);
*P = 1; // =1
l:
while (*P) { // [
printf("%d", *P); // .
P += 1; // > 1
*P = 10; // =10
*P -= P[-1]; // -*-1
while (*P) { // [
P += 1; // >1
*P = 32; // =32
printf("%c", (char)*P); // !
P += -2; // >-2
*P += 1; // +1
goto l; // ;-2
} // ]
break; // ;1
} // ]
*P = 10; // =10
printf("%c", (char)*P); // !
return 0;
}


Extensions can be applied to this language such as character literals, arrays, string literals etc, but you don't have to implement them, for simplicity.

## The Challenge

You have to implement the core features detailed in the Language Specification section and the NOTEs below. Give it a try with your favourite programming language, writing the shortest program possible.

NOTE1: The size of the array is undefined. But it should be big enough to solve most problems.

NOTE2: Integer overflow is undefined.

NOTE3: The specification only defines the result or effect of certain language constructs. For example, you don't have to exactly follow the steps in the definition of the argument *.

NOTE4: Any characters that are not commands, arguments, or comments Whitespaces are ignored. =104!=105! is as same as = 1 0 4! = 1 05 ! for example.

NOTE5: Comments are not nested. ((comment)) is a syntax error.

NOTE6: I've made a breaking change to fix a hole in my language. The ~ command is now unused and ; always takes an argument.

NOTE7: Every integer literal is decimal.

• Is it just me or is this basically brainfuck? – Claudiu Jun 26 '15 at 12:47
• can we assume all statements passed are valid? ie all braces are closed – Levi Jul 10 '15 at 14:38
• Are you sure the first example =9[>1=9-*-1.>-1-1] prints 0 to 9? After it ptints 8 because P[0]=1 it then subtracts 1 just before the end of the loop which makes P[0]=0 and then when it starts the loop again it should exit because P[0]=0 so the example should only print 0 to 8. Or am I just really confused? – Jerry Jeremiah Aug 6 '15 at 1:55
• @JerryJeremiah hmm.. sure it seems like my mistake, will fix now. – xiver77 Aug 6 '15 at 5:59

# gcc (with warnings) - 470 (if line ending count as 1)

#define L strtol(I++,&I,10)
#define A*I=='*'?I++,P[L]:L
#define F(a,b)!=a||i;i=*I==b?i+1:*I==a?i-1:i);
#define J(x) for(i=x;*I++F(']','[')
#define K for(--I,i=0;*--I F('[',']')
#define C break;case
X[999],*P=X;main(i,a)char**a;{char*I=a[1];while(*I)switch(*I++){C'(':while(*I++!=')');C'.':printf("%d",*P);C'!':printf("%c",(char*)*P);C'[':if(!*P)J(1)C']':K C'=':*P=A;C'+':*P+=A;C'-':*P-=A;C'*':*P*=A;C'/':*P/=A;C'>':P+=A;C';':for(int c=A;c;c+=c<0?1:-1)if(c>0)J(0)else K}}


and the slightly less golfed version:

#include <stdio.h>
#include <stdlib.h>
#define L strtol(I++,&I,10)
#define A *I=='*'?I++,P[L]:L
int X[999],*P=X;
int main(int i, char *a[])
{
char* I=a[1];
while(*I)
{
switch(*I++)
{
case '(': while(*I++!=')'); break;
case '.': printf("%d",*P); break;
case '!': printf("%c",(char*)*P); break;
case '[': if(!*P)
for(i=1;*I++!=']'||i;)
{
if(*I=='[')
i+=1;
if(*I==']')
i-=1;
}
break;
case ']': for(--I,i=0;*--I !='['||i;)
{
if(*I==']')
i+=1;
if(*I=='[')
i-=1;
}
break;
case '=': *P=A; break;
case '+': *P+=A; break;
case '-': *P-=A; break;
case '*': *P*=A; break;
case '/': *P/=A; break;
case '>': P+=A; break;
case ';': for(int c=A; c; c+=c<0?1:-1)
{
if(c>0)
for(i=0;*I++!=']'||i;)
{
if(*I=='[')
i+=1;
if(*I==']')
i-=1;
}
else
for(--I,i=0;*--I !='['||i;)
{
if(*I==']')
i+=1;
if(*I=='[')
i-=1;
}
}
}
}
return 0;
}