Algorithms, Blockchain and Cloud

PIBAS Interpreter (Javascript)


PIBAS is simple, it only has 2 possible operations: string assignment (e.g. A=’abc’) and printing (e.g. ?A). It supports only one function which is similar to the substr in Javascript but even simpler. The $(a, b, c) returns the substring of string var begining at its index (based-1) and length c. To make it simpler, is the string variable name from ‘A’ to ‘Z’, and are just integers.

To understand better, two examples are given.

?"Hello, "+'World!'

and

A='World, Hello!';?$(A,8,5);?", ";B=$(A,1,5)+'!';?B

Both print Hello, World! 

The full description can be found on Timus Online Judge, Problem 1230 [Introspective Program]

The task is to write a program, that outputs its source to standard output. For example, the following C is the so-called Quine, which takes no input and print its source to the output. In computing literature, it is also referred to as self-replicating programs, self-reproducing programs, and self-copying programs.

char *f = "char *f = %c%s%c; void main(){printf(f, 34, f, 34, 10);%c"
void main()
{
printf(f, 34, f, 34, 10);
}

The Javascript and Python implementation of the above simple PIBAS language can be found on github [here] and [here], respectively.

The online Javascript page is built at https://rot47.net/pibas.interpreter.html

The following gives the code.

// PIBAS Interpreter
// http://acm.timus.ru/problem.aspx?space=1&num=1230
// https://helloacm.com

// in case charAt is not defined.
if (!String.prototype.chatAt) {
	String.prototype.chatAt = function(idx) {
		return this.substr(idx, 1);
	}
}

var PIBAS = function(src) {
	// define string vars, 26 possible vars
	var __vars__ = new Array(26);
	
	// throw an error in parsing
	function __err__(src, msg, pos) {		
		throw src + ":" + pos + ":" + msg;
	}
	
	// get the expression value e.g. after = or ?
	function __gets__(src) {
		var tmp = '';
		var k = src.length;
		var i = 0;
		var s = 0;
		var d = 0;
		var last = 0;
		var sgn = 1;
		while (i < k) {
			var c = src.charAt(i);
			if ((c == '"') && (s == 0)) {
				if (d == 0) {
					d = 1;
					last = i + 1;
				}
				else if (sgn == 1) {
					tmp += src.substring(last, i);
					sgn = 0;
					d = 0;
				}
				else if (sgn == 0) {
					__err__(src, "Missing + ", i);
				}
				else {
					__err__(src, "Extra + ", i);
				}
			}
			else if ((c == "'") && (d == 0)) {
				if (s == 0) {
					s = 1;
					last = i + 1;
				}
				else if (sgn == 1) {
					tmp += src.substring(last, i);
					sgn = 0;
					s = 0;
				 }
				else if (sgn == 0) {
					__err__(src, "Missing +", i);
				}
				else {
					__err__(src, "Extra +", i);
				}
			}
			else if ((c == '$') && (s == 0) && (d == 0)) {
				if (sgn == 1) {
					if (i + 7 >= k) {
						__err__(src, "Invalid $ pattern", i);
					}
					else if (src.chatAt(i + 1) != '(') {
						__err__(src, "Missing (", i);
					}
					else {
						i += 2;
						var j = i;
						var tt = -1;
						while (j < k) {
							if (src.chatAt(j) == ')') {
								tt = j;
								break;
							}
							j ++;
						} 
						if (tt == -1) {
							__err__(src, "Missing )", i);
						}
						else {
							var xx = src.substring(i, tt);
							var yy = xx.split(",");
							if (yy.length == 3) {
								var zz = yy[0].charAt(0);
								if ((yy[0].length == 1) && (zz >= 'A') && (zz <= 'Z')) {
									sgn = 0;
									var idx = parseInt(yy[1]) - 1;
									var lll = parseInt(yy[2]);
									tmp += __vars__[yy[0].charCodeAt(0) - 65].substring(idx, idx + lll);
									i = tt;
								}
								else {
									__err__(src, "Invalid string var " + yy[0], i);
								}
							}
							else {
								__err__(src, "Invalid $, require 3 parts: ", i);
							}
						}
					}
				}
				else if (sgn == 0) {
					__err__(src, "Missing +", i);
				}
				else {
					__err__(src, "Extra +", i);
				}
			}
			else if ((c == '+') && (s == 0) && (d == 0)) {
				if (sgn > 0) {
					__err__(src, "Too many string +", i);
				}
				else {
					sgn = 1;
				}
			}
			else if ((c >= 'A') && (c <= 'Z') && (s == 0) && (d == 0)) {
				if (sgn == 1) {
					tmp += __vars__[c 1="-" 2="65" language=".charCodeAt(0)"][/c];
					sgn = 0;
				}
				else if (sgn == 0) {
					__err__(src, "Missing +", i);
				}
				else {
					__err__(src, "Extra +", i);
				}
			}
			else if ((s == 0) && (d == 0)) {
				__err__(src, "Invalid Char: " + c, i);
			} 
			i ++;
		}  
		return tmp;  
	}
  
	function __parse__(src) {
		var k = src.length;
		var i = 0;
		var s = "";
		while (i < k) {
			var c = src.chatAt(i);
			if ((c >= 'A') && (c <= 'Z')) {  // string assignment
				if ((i + 1 < k) && (src.charAt(i + 1) == '=')) {
					__vars__[c 1="-" 2="65" language=".charCodeAt(0)"][/c] = __gets__(src.substr(i + 2));
					break;
				}
				else {
					__err__(src, "Missing assignment", i);
				}
			}
			else if (c == '?') { // print the string expression
				s += __gets__(src.substr(i + 1));
				break;
			}
			else {
				__err__(src, "Invalid Char " + c, i);
			}
			i ++;
		}
		return s;
	}

	function parse(src) {
		var k = src.length;
		var i = 0;
		var s = 0;
		var d = 0;
		var last = 0;
		var out = "";
		// separate the statement by semi-comma
		while (i < k) {
			var c = src.chatAt(i);
			if (c == ';') {
				if ((s == 0) && (d == 0)) {
					out += __parse__(src.substring(last, i));
					last = i + 1;
				}
			}
			else if ((c == '"') && (s == 0)) {
				if (d == 1) {
					d = 0;
				}
				else {
					d = 1;
				}
			}
			else if ((c == "'") && (d == 0)) {
				if (s == 1) {
					s = 0;
				}
				else {
					s = 1;
				}
			}
			i ++;
		}
		if (last != k) {
			if ((s == 0) && (d == 0)) {
				out += __parse__(src.substr(last));
			}
			else {
				__err__(src, "Unclosed string constant", k - 1);
			}
		}
		return out;
	}
	return parse(src);
};

The idea of implementation is to separate the statement first, those semi-comma within string constants should be taken care of. The $ function should be considered in the string-assignment together with string concat '+'. The print function ? can be checked in parallel with the string assignment '='.
The compressed Javascript code can be downloaded here, which saves the user's bandwidth.

References

[1] Quine on Wiki
--EOF (The Ultimate Computing & Technology Blog) --

965 words
Last Post: Codeforces: B. Roadside Trees (Simplified Edition)
Next Post: Codeforces: 268A. Games

The Permanent URL is: PIBAS Interpreter (Javascript) (AMP Version)

Exit mobile version