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 a begining at its index b (based-1) and length c. To make it simpler, a is the string variable name from ‘A’ to ‘Z’, b and c 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) --
Last Post: Codeforces: B. Roadside Trees (Simplified Edition)
Next Post: Codeforces: 268A. Games