Представленное здесь определение языка Small-C является подмножеством второго издания K&R языка C, специально разработанного для использования в курсе проектирования компиляторов бакалавриата.

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

Например, некоторые из изменений, которые можно (или нужно) внести в грамматику:

  1. Разрешить объявление более одной функции в исходном файле (!).
  2. Включите тип void для объявлений процедур.
  3. Иметь одну основную функцию, которая должна вызываться при запуске программы. Эта функция должна иметь тип void.
  4. Поддержка рекурсии.
  5. Добавьте типы символов и массивов.

Терминальные символы (токены)

Целое число

Последовательность цифр, обозначающая целое число в диапазоне -32768..32767. Это должно храниться в представлении с дополнением до двух. Может быть расширен для поддержки 32- или 64-битных целых чисел.

Идентификатор

Последовательность букв, цифр и символов подчеркивания, которая может начинаться только с символов подчеркивания или букв, не длиннее 16 символов.

Зарезервированные слова

break continue else if int return while readint writeint

Специальные символы

+ — * / % ! ? : = , < > ( ) { } || && ==

Комментарии должны начинаться с «/*» и заканчиваться на «*/» и могут содержать любой допустимый символ, включая новую строку. Комментарии не должны быть вложенными или выходить за конец исходного файла.

Два соседних терминальных символа должны быть разделены одним или несколькими комментариями, пробелами или символами новой строки, если только один из других символов не является специальным символом. Комментарии, пробелы и новые строки не имеют синтаксической ценности.

Встроенная библиотека ввода/вывода

Чтобы избежать необходимости реализации библиотеки времени выполнения для ввода-вывода, я включил два зарезервированных ключевых слова для создания целочисленных функций чтения и записи, которые можно генерировать непосредственно из модуля объектного кода.

Синтаксис Small-C

Это синтаксис Small-C, описанный в EBNF:

smallc_program ::= type_specifier id ‘(‘ param_decl_list ‘)’ compound_stmt
Type_specifier ::= int | char
Param_decl_list ::= parameter_decl (‘,’ parameter_decl )*
Param_decl ::= type_specifier id
Compound_stmt ::= ‘{‘ (var_decl* stmt*)? ‘}’
Var_decl ::= type_specifier var_decl_list ‘;’
Var_decl_list ::= variable_id ( ‘,’ variable_id)*
Variable_id ::= id ( ‘=’ expr )?
Stmt ::= compound_stmt | cond_stmt | while_stmt | break ‘;’ | continue ‘;’ | return expr ‘;’ | readint ‘(‘ id ‘)’ ‘;’ |
 writeint ‘(‘ expr ‘)’ ‘;’
Cond_stmt ::= if ‘(‘ expr ‘)’ stmt (else stmt)?
While_stmt ::= while ‘(‘ expr ‘)’ stmt
Expr ::= id ‘=’ expr | condition
Condition ::= disjunction | disjunction ‘?’ expr ‘:’ condition
Disjunction ::= conjunction | disjunction ‘||’ conjunction
Conjunction ::= comparison | conjunction ‘&&’ comparison
Comparison ::= relation | relation ‘==’ relation
Relation ::= sum | sum (‘<’ | ‘>’) sum
Sum ::= sum ‘+’ term | sum ‘-’ term | term
Term ::= term ‘*’ factor | term ‘/’ factor | term ‘%’ factor | factor
Factor ::= ‘!’ factor | ‘-’ factor | primary
Primary ::= num | charconst | id | ‘(‘ expr ‘)’

Дополнительные правила

  1. Ни один идентификатор не может быть объявлен более одного раза в одной и той же области видимости.
  2. Ни один идентификатор не может быть использован без предварительного объявления.
  3. Исходная программа должна иметь основную процедуру без параметров.
  4. Количество и тип аргументов в вызовах функций должны совпадать с объявлением функции.
  5. Оператор return не должен возвращать значение, если только оно не содержится внутри функции, объявленной для возврата значения.
  6. Выражение в операторе возврата должно быть того же типа, что и тип возвращаемого значения функции, в которой оно содержится.
  7. Сообщение о лексических, синтаксических и семантических ошибках.

Этапы доставки

  1. Лексический анализатор, созданный с помощью таких инструментов, как Flex, JLex, ANTLR.
  2. Парсер, созданный с помощью таких инструментов, как Bison, CUP, ANTLR.
  3. Генерация промежуточного кода (тройки или четверки, например, предложенные в книге Dragon).
  4. Объектный код, обычной целью может быть архитектура MIPS, но можно использовать и x86, для более авантюрных настроений.

Примечание. Предыдущая версия этой работы была опубликована в http://maestros.unitec.edu/~efutch/small-c__english_version_.html, но обновлена ​​здесь для улучшения возможностей редактирования и публикации.