Спецификация языка ABC

(версия 1.06 от 24.04.2008)

В настоящем документе описаны язык машины ABC и его семантика. Машина ABC получает при запуске фразу на языке ABC и, возможно, одну или несколько последовательностей десятичных цифр. Результатом её работы является одна или несколько последовательностей десятичных цифр. Более подробную информацию о машине ABC можно найти в разделе 1.2. Спецификация машины ABC, а об имеющихся её реализациях – в разделе 2. Реализации.

Синтаксис языка ABC

Ниже приведена грамматика языка ABC. Имена в языке регистронезависимы. Пробельный литерал языка <SP> обязателен в конструкции <PrintOp>, во всех остальных случаях он игнорируется.

<Program>    ::   [<NL>] <Line> [<NL>] [<NL> Program]
<Line>       ::   <StopOp>
                | <PrintOp>
                | <NamedCalc>                            
<NamedCalc>  ::   <Name> "=" <Calc>                      
<StopOp>     ::   "stop"
<PrintOp>    ::   "print" <SP> <Calc>
<Calc>       ::   <DigitList>
                | <Calc> <OP> <Calc>
                | "(" <Calc> ")"
                | <Name>
                | <Name> "(" [<CalcList>] ")"            
<CalcList>   ::   <Calc> ["," <CalcList>]                
<OP>         ::   "+" | "-" | "*" | "/" | "%"
<Name>       ::   <Letter> [<SymbolList>]
<SymbolList> ::   <Symbol> [<SymbolList>]
<Symbol>     ::   <Letter> | <Digit>
<Letter>     ::   "_" | "a" | ... | "z" | "A" | ... | "Z"
<DigitList>  ::   <Digit> [<DigitList>]
<Digit>      ::   "0" | ... | "9"
<NL>         ::   ["\r"] "\n" [<NL>]
<SP>         ::   " "  [<SP>]
                | "\t" [<SP>]

Режимы машины ABC

Машина ABC способна работать в 3 различных режимах. Режимы с большим номером включают в себя всю функциональность режимов с меньшими номерами и добавляют, в свою очередь, новые синтаксические конструкции. В приведенной выше грамматике жёлтым и зелёным цветами подсвечены синтаксические конструкции, добавленные во 2 и 3 режимах работы машины, соответственно.

Семантика языка ABC

При выполнении вычислений машина ABC рассматривает последовательности десятичных цифр как целые неотрицательные числа (верхний предел может быть ограничен в конкретной реализации). Выполняемые операции арифметичны. В частности, если при вычитании в обычной арифметике получается число меньшее 0, то машина ABC приводит результат к нулю.

1 + 2  -> 3
2 - 1  -> 1
1 - 2  -> 0
3 * 4  -> 12
15 / 6 -> 2
15 % 6 -> 3

Память машины ABC организована как стек, в котором размещаются параметры. Ограничения на размер стека параметров накладываются в конкретных реализациях. В дальнейшем будем пользоваться следующим форматом записи текущего состояния стека:

(a1, a2, ... , aN)
Стек содержит N элементов, a1 – вершина стека.
(a1, a2, ... )
Количество элементов в стеке неважно, но известно,
что наверху стека находятся указанные элементы a1 и a2.

На стеке определены 3 операции:

Машина ABC читает программу построчно сверху вниз. В режиме 1 разрешено использование выражений <PrintOp> и <StopOp>. Ключевое слово языка "print" заставляет машину ABC выполнить заданное в этой же строке вычисление и вывести его результат на экран. Все <PrintOp>'ы, встреченные после первой инструкции "stop", игнорируются.

print 10 - 2
stop
print 2 - 10
Напечатается 8.

Все имена в вычислении являются его параметрами и их значения считываются из единого стека параметров. Порядок, в котором параметры вычисления лежат в стеке, задается их порядком следования в выражении.

print b - a + 10
Заданое вычисление берет из стека 2 аргумента (b - верхний,
а - нижний) и вычисляет их разность, увеличенную на 10. 
При состоянии стека (4, 7, ... ) будет напечатано 10,
а при состоянии (7, 4, ... ) - 13.

Нумерация параметров вычисления независима от нумерации параметров в других вычислениях.

Программа
print b - a 
print a - b
при состоянии стека (7, 4, ...) напечатает две тройки.

Второй режим позволяет присваивать вычислениям имена, при этом сами вычисления не выполняются до тех пор, пока не окажутся востребованными в команде print. Имена вычислений образуют глобальное пространство имён, и это требует отдельного прохода при парсинге программы ABC. Если одно имя определяется несколько раз, то все определения, кроме первого, игнорируются.

print d + b
a = 1 - 1
d = a + b
В этом примере a и d – имена вычислений, b - параметр.
При состоянии стека (2, ...) машина ABC напечатает 4.

a = b + 1
b = a + 1
print a
В данном примере переменные a и b являются циклически зависимыми, машина
ABC при вычислении выражения вернёт ошибку (невозможно вычислить значения
циклически зависимых переменных).

В третьем режиме добавляется возможность функционального вызова именованных вычислений. В этом случае машина ABC добавляет в стек параметры вызова справа налево, запускает вычисление, а после его завершения, снимает параметры вызова со стека.

a = b + c
print a(1,2) - a
При вычислении выражения "a(1,2) - a" машина ABC сначала складывает в стек
параметров значения 1 и 2 (сначала в стек кладётся 2, а затем 1), вызывает
вычисление "a", далее снимает положенные ранее параметры, опять вызывает
вычисление "a" и печатает разницу полученных результатов. Таким образом,
при состоянии стека (1, 1, ...) машина напечатает 1.

В этом режиме можно использовать рекурсивные вычисления, но полезно помнить, что для корректной работы любая рекурсия должна содержать условие выхода. В этом поможет особое свойство оператора "*": если правый операнд равен 0, то левый операнд не вычисляется, а результат операции принимается равным 0.

f = f(t-1) * t + (1 - t)
print f(10)
Программа напечатает факториал 10.

Исключительные ситуации

Не всегда синтаксически корректные программы на языке ABC корректно завершаются. Ниже приведён список возможных ошибок исполнения программ, написанных на языке ABC:

*  – Возникает в зависимости от реализации виртуальной машины.
** – Появляется во 2-ом режиме, при попытке посчитать значение
     вычисления, имеющего циклическую зависимость от самого себя.