Называется сие творение
langry#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
const int MAX_SCRIPT_SIZE = 10240; // 10 kB
int stack[26]; // переменные от a до z (скопировано с Basic)
char scriptText[MAX_SCRIPT_SIZE];
char *pCurrentPos;
size_t findfilesize(FILE *_file)
{
fseek(_file, 0, SEEK_END);
size_t size = ftell(_file);
rewind(_file);
return size;
}
void filetostring(FILE *_file, char *_pString)
{
size_t n;
char *pBuf = _pString;
do
{
n = fread(pBuf, 1, 1024, _file);
pBuf += n;
}
while(n == 1024);
rewind(_file);
}
int prepareScript(const char *_pPathToFile, char *_pWhereToWrite)
{
FILE *fScript = fopen(_pPathToFile, "rt");
if(!fScript)
{
fprintf(stderr, "Failed to open script file '%s'\n", _pPathToFile);
return 1;
}
size_t scriptSize = findfilesize(fScript);
if(scriptSize > MAX_SCRIPT_SIZE)
{
fprintf(
stderr,
"Error: size of script '%s' exceeds maximal allowed size (%d bytes).\n",
_pPathToFile, MAX_SCRIPT_SIZE
);
fclose(fScript);
return 2;
}
//char scriptText[MAX_SCRIPT_SIZE];
filetostring(fScript, _pWhereToWrite);
fclose(fScript);
return 0;
}
size_t l_strlen(char *_pStr)
{
size_t len = 0;
while(*_pStr != '^')
{
len++;
_pStr++;
}
return len;
}
int l_print()
{
pCurrentPos++;
while(*pCurrentPos != '^')
{
switch(*pCurrentPos)
{
// Вывод переменной
case '$':
pCurrentPos++;
if(!isalpha(*pCurrentPos))
return 1;
printf("%d", stack[tolower(*pCurrentPos) - 'a']);
pCurrentPos++;
break;
// Переход на новую строку, аналог '\n'
case '\\':
putchar('\n');
pCurrentPos++;
break;
// Экран, аналог '\'
case '#':
pCurrentPos++;
putchar(*pCurrentPos);
pCurrentPos++;
break;
// Обычный вывод
default:
putchar(*pCurrentPos);
pCurrentPos++;
}
}
pCurrentPos++;
return 0;
}
int l_setvar()
{
pCurrentPos++;
if(!isalpha(*pCurrentPos))
return 1;
char buf[100] = "\0";
char var = tolower(*pCurrentPos);
pCurrentPos++;
int len = l_strlen(pCurrentPos);
strncpy(buf, pCurrentPos, len);
stack[var - 'a'] = atoi(buf);
pCurrentPos += len + 1;
return 0;
}
int l_math()
// mca+b^ -- c = a + b;
// ^
{
const int EXPR_LEN = 4;
const char MATH_OPS[] = "+-*/%";
pCurrentPos++;
// Производить действия можно только над значениями переменных
if(
l_strlen(pCurrentPos) != EXPR_LEN ||
!isalpha(*pCurrentPos) ||
!isalpha(pCurrentPos[1]) ||
!isalpha(pCurrentPos[3])
)
return 1;
char op = *(pCurrentPos + 2);
if(!strchr(MATH_OPS, op))
return op;
int a = stack[tolower(*(pCurrentPos + 1)) - 'a'];
int b = stack[tolower(*(pCurrentPos + 3)) - 'a'];
int res;
switch(op)
{
case '+':
res = a + b;
break;
case '-':
res = a - b;
break;
case '*':
res = a * b;
break;
case '/':
res = a / b;
break;
case '%':
res = a % b;
break;
default:
return 2;
}
stack[tolower(*pCurrentPos) - 'a'] = res;
pCurrentPos += EXPR_LEN + 1;
return 0;
}
int mainswitch()
{
int err;
while(*pCurrentPos != 0)
{
switch(*pCurrentPos)
{
case '}':
return 0;
case ' ': case '\t': case '\n':
pCurrentPos++;
break;
case 'p':
err = l_print();
if(err)
{
fprintf(stderr, "Print error. Char %d.\n", pCurrentPos - scriptText);
return 1;
}
break;
case 'v':
l_setvar();
break;
case 'm':
err = l_math();
switch(err)
{
// Всё ок
case 0:
break;
// Одна из переменных указана некорректно
case 1:
fprintf(stderr, "Math error: incorrect arguments. Char %d.\n", pCurrentPos - scriptText);
return 1;
// Действие указано некорректно
default:
fprintf(stderr, "Math error: '%c' is not a correct operator. Char %d.\n", err, pCurrentPos - scriptText);
return 2;
}
break;
default:
fprintf(stderr, "Error! '%c'\n", *pCurrentPos);
return 1;
}
}
return 0;
}
int main(int argc, char *argv[])
{
int err, n;
switch(argc)
{
case 1:
do
{
printf("langry: > ");
fgets(scriptText, MAX_SCRIPT_SIZE, stdin);
pCurrentPos = scriptText;
n = mainswitch();
printf("Exit status: %d.\n", n);
}
while(scriptText[0] != '}');
break;
case 2:
err = prepareScript(argv[1], scriptText);
if(err)
return -1;
pCurrentPos = scriptText;
n = mainswitch();
return n;
break;
default:
printf("Usage: langry <script>\n");
return 1;
}
}
} - завершитель программы. После него можно писать комментарии.
Все команды надо завершать знаком ^ .
p - печать.
pHELLOWORLD^
выведет на экран текст HELLOWORLD.
p$a^
выведет значение переменной a.
pI have $a things^
возможен комбинированный вывод.
\ - аналог \n
# - экран
v - ввод переменной
va400^
присваивание переменной a значения 400.
Переменные могут иметь только однобуквенное название и целочисленное значение. Ввод букв допустим, но ничего не меняет.
Запись типа va^ недопустима.
m - математические действия.
Допустимы тоько операции со значениями переменных.
Поддерживаются целочисленные операции: + - * / %
mca+b^
Присвоить переменной c результат сложения a и b.
pPreved!\^
va10^vb40^
mca*b^
p$a+$b=$c\^
}
Комментарий.
Вот такая индусская разработка.
Есть возможность пошагового выполнения команд, как в Питоне (запуск без аргументов), и передачи файла-скрипта.
Чтобы остановить пошаговое выполнение, нужно написать } .
Возможностей пока немного, но будут добавляться.
Если кому интересно, почитайте, укажите на косяки.