Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ТАФЯ. Лабораторная работа 5.docx
Скачиваний:
0
Добавлен:
15.04.2026
Размер:
45.42 Кб
Скачать

МИНИСТЕРСТВО ЦИФРОВОГО РАЗВИТИЯ,

СВЯЗИ И МАССОВЫХ КОММУНИКАЦИЙ РОССИЙСКОЙ ФЕДЕРАЦИИ

Федеральное государственное бюджетное образовательное учреждение высшего образования «Санкт-Петербургский государственный университет

телекоммуникаций им. проф. М. А. Бонч-Бруевича»

(СПбГУТ)

Факультет инфокоммуникационных сетей и систем

Кафедра программной инженерии и вычислительной техники

Лабораторная работа №5

по дисциплине «Теория алгоритмов и формальных языков»

студенты гр. ИКПИ-93

_______________

Смирнов Д.А.

Тюришев М.А.

Цыганков М.А.

Козлов Н.С.

ассистент каф. ПИиВТ

_______________

Марочкина А. В.

Санкт-Петербург

2022

Постановка задачи

Создать упрощенный вариант лексического анализатора кода на произвольном языке программирования. (Выбран язык C90.)

Ход работы

Код разработанной программы на языке Python приведен в таблице 1.

Таблица 1. Код разработанной программы

main.py

import collections import re import string import sys import traceback

from typing import Union, Tuple, List, Set, Dict, Pattern

class C90Language:

"""Класс языка C90: лексика"""

# ========================================== Для лексического анализа

# поля, описывающие шаблоны лексем токенов в виде регулярных выражений multi_line_comment = re.compile(r'/\*.*?\*/', re.S) single_line_comment = re.compile(r'//.*')

integer = re.compile(r"[+-]?(0[0-7]+|0X[0-9A-F]+|\d+)U?L{,2}(?![0-9A-Z.])", re.IGNORECASE)

float = re.compile(r"[+-]?(\d+(\.\d*)?(E[+-]?\d+)?|\.\d+(E[+-]?\d+)?)[FL]?(?![0-9A-Z.])", re.IGNORECASE) space = re.compile(r"\s+") character = re.compile(

r"L?\'(\\(['\"?\\abfnrtv]|[0-7]{,3}|x[0-9a-fA-F]{,2}|u[0-9a-fA-F]{,4}|U[0-9a-fA-F]{,8})|[^\\'])\'"

)

string = re.compile(r'L?\".*?\"')

identifier = re.compile(r'[a-zA-Z_][a-zA-Z0-9_]*')

preprocessor_directive = re.compile(r'#.*') # обычно обрабатываются препроцессором до лексического анализа # будем пропускать директивы препроцессора

keywords = { # множество ключевых слов языка

'auto', 'break', 'case', 'char', 'const', 'continue', 'default', 'do', 'double', 'else', 'enum',

'extern', 'float', 'for', 'goto', 'if', 'int', 'long', 'register', 'return', 'short', 'signed', 'sizeof', 'static', 'struct', 'switch', 'typedef', 'union', 'unsigned', 'void', 'volatile', 'while'

}

@staticmethod

def get_lexical_fsm() -> Dict[str, Union[str, dict,

Tuple[str, Pattern],

List[Tuple[str, Pattern]]]]:

"""Возвращает лексику языка в виде конечного автомата"""

# ----- ручное задание конечного автомата

fsm = {

':': '<colon>', ';': '<semicolon>', ',': '<comma>', '~': '<tilde>',

'(': '<open-bracket>', ')': '<close-bracket>',

'[': '<open-square-bracket>', ']': '<close-square-bracket>',

'{': '<open-curly-bracket>', '}': '<close-curly-bracket>',

'>>': '<right-shift>', '>=': '<greater-than-or-equal-to>', '>': '<greater-than>',

'<<': '<left-shift>', '<=': '<less-than-or-equal-to>', '<': '<less-than>',

'--': '<decrement>', '-=': '<minus-equals>', '->': '<pointer-access>', '-': '<minus>',

'++': '<increment>', '+=': '<plus-equals>', '+': '<plus>',

'.': '<dot>', '...': '<ellipsis>',

'&&': '<logical-and>', '&=': '<binary-and-equals>', '&': '<binary-and>',

'||': '<logical-or>', '|=': '<binary-or-equals>', '|': '<binary-or>',

'^=': '<binary-xor-equals>', '^': '<binary-xor>',

'*=': '<mul-equals>', '*': '<multiply-or-pointer>',

'/*': ('<multi-line-comment>', C90Language.multi_line_comment),

'//': ('<single-line-comment>', C90Language.single_line_comment),

'/=': '<div-equals>', '/': '<divide>',

'%=': '<modulus-equals>', '%': '<modulus>', '==': '<equal-to>', '=': '<assignment>',

'!=': '<not-equals>', '!': '<logical-not>',

'#': ('<preprocessor-directive>', C90Language.preprocessor_directive),

"'": ('<character-constant>', C90Language.character),

'"': ('<string>', C90Language.string),

"L'": ('<character-constant>', C90Language.character),

'L"': ('<string>', C90Language.string)

} for digit in string.digits: fsm[digit] = [('<integer-constant>', C90Language.integer), ('<floating-constant>', C90Language.float)] for letter in string.ascii_letters + '_': fsm[letter] = ('<identifier>', C90Language.identifier) for space in string.whitespace: fsm[space] = ('<whitespace>', C90Language.space)

# ----- алгоритм преобразования структуры в конечный автомат

# -1- удаляем вложенность

q = collections.deque([('', fsm)]) # очередь: (lexeme, token) fsm = dict() # новый конечный автомат while q: # пока очередь не пуста

lexeme, token = q.popleft() # получаем из очереди очередной узел if isinstance(token, dict): # если token -- это промежуточный подузел

for lex, tok in token.items(): # проходим по каждому подузлу промежуточного подузла

q.append((lexeme + lex, tok)) # добавляем в очередь, пример: ('-' + '=', '<minus-equals>') else: # если token -- это конечный подузел

if fsm.get(lexeme, token) != token: # если уже есть запись по fsm[lexeme], не равная token raise ULexicalFSMError(f'Invalid: {fsm[lexeme]} != {token} [{fsm}]') fsm[lexeme] = token # если записи по fsm[lexeme] нет или есть, но равна token

# -2- формируем вложенность

for lexeme, token in list(fsm.items()): # проходим по каждому подузлу lexeme_len = len(lexeme) # длина лексемы (например, len('-=') -> 2) if lexeme_len > 1: # если длина лексемы больше 1 current = fsm # current указывает на текущий узел i = 0 # индекс текущего символа в lexeme

while i < lexeme_len: # пока индекс < длины лексемы ch = lexeme[i] # получаем i символ

if i == lexeme_len - 1: # если i == последнему индексу # если уже есть запись по current[ch], не равная token if current.get(ch, token) != token:

raise ULexicalFSMError(f'Invalid: {current[ch]} != {token} [{current}]') current[ch] = token # если записи по current[ch] нет или есть, но равна token elif ch in current: # если i < последний индекс и символ лексемы есть в current if isinstance(current[ch], dict): # если current[ch] -- это промежуточный узел current = current[ch] # переходим в него else: # иначе

i += 1 # переходим к следующему символу

if i == lexeme_len - 1: # если символов не осталось, записываем как str/tuple

current[ch] = {lexeme[i]: token, '': current[ch]} else: # иначе записываем как dict и переходим в него d = dict()

current[ch] = {lexeme[i]: d, '': current[ch]} current = d

else: # если i < последний индекс и символ лексемы отсутствует в current if i >= lexeme_len - 1: # если символов не осталось, записываем как str/tuple current[ch] = token

else: # иначе записываем как dict и переходим в него d = dict() current[ch] = d current = d

i += 1 # переходим к следующему символу

fsm.pop(lexeme) # удаляем соответствие lexeme (длина > 1) -> token return fsm

@staticmethod def get_keywords() -> Set[str]:

"""Возвращает множество ключевых слов языка""" return set(C90Language.keywords)

class ULexicalError(ValueError):

"""Исключение возникает из-за лексической ошибки"""

def __init__(self, **kwargs): self.params = {k: repr(v) if isinstance(v, str) else v for k, v in kwargs.items() if isinstance(v, (int, float)) or v} super().__init__()

def __str__(self): return '[' + ' | '.join(f"{name}: {p}" for name, p in self.params.items()) + ']'

class ULexicalFSMError(TypeError):

"""Исключение возникает из-за ошибки в описании лексики языка в виде конечного автомата""" pass # не требует реализации; функциональность = TypeError

def lexical_analyzer(lexical_fsm: Dict[str, Union[str, dict,

Tuple[str, Pattern],

List[Tuple[str, Pattern]]]], keywords: Union[List[str], Set[str]], code: str) -> List[Tuple[str, str]]:

"""

Лексер анализирует код согласно лексике языка и возвращает список токенов и лексем, либо выбрасывает исключение

:param lexical_fsm: лексика языка в виде конечного автомата

:param keywords: список/множество ключевых слов языка

:param code: код для лексического анализа

:return: список токенов и лексем; например, [..., ('<identifier>', 'Animal'), ...] """

# проверка lexical_fsm -- лексики языка в виде конечного автомата q = collections.deque(lexical_fsm.items()) # очередь для проверки while q:

tuple_item = q.popleft()

if not isinstance(tuple_item, tuple): # tuple ключ:значение

raise ULexicalFSMError(f"Invalid type: {tuple_item} [{type(tuple_item)}] (must be tuple)") key, value = tuple_item

if not isinstance(key, str): # ключ должен быть строкой

raise ULexicalFSMError(f"Invalid type: {repr(key)} [{type(key)}] (must be str)") if len(key) > 1: # длина ключа должна быть <= 1

raise ULexicalFSMError(f"Length of string must be <= 1, got {repr(key)} with len = {len(key)}") if not isinstance(value, (str, tuple, list, dict)): # значение может быть только str / tuple / list / dict raise ULexicalFSMError(f"Invalid type: {value} [{type(value)}] (must be str / tuple / list / dict)") if isinstance(value, (tuple, list)): # если значение tuple / list tuples = [value] if isinstance(value, tuple) else value # создаем list if len(tuples) == 0: # длина списка должна быть > 0

raise ULexicalFSMError(f"Number of values in list must be >= 1, got: {tuples}") for tuple_item in tuples: # для каждого кортежа в списке if len(tuple_item) != 2: # длина кортежа должна быть == 2

raise ULexicalFSMError(f'Number of values in tuple must be 2, got: {tuple_item}') key, value = tuple_item

if not isinstance(key, str): # ключ должен быть str

raise ULexicalFSMError(f"Invalid type: {repr(key)} [{type(key)}] (must be str)") if not isinstance(value, Pattern): # значение должно быть Pattern [re.compile(...)] raise ULexicalFSMError(f"Invalid type: {repr(value)} [{type(value)}] (must be Pattern)") elif isinstance(value, dict): # в случае словаря -- добавляем его элементы в очередь q.extend(value.items())

# лексический анализ

tokens_and_lexemes = [] # список токенов и лексем current_state = lexical_fsm # текущее состояние

p, i, n = 0, 0, len(code) # предыдущий индекс, текущий индекс и длина code token, lexeme = '', '' # токен и лексема line = 1 # текущий номер строки кода

while i < n: # пока текущий индекс < длины code

r = current_state.get(code[i]) # переходим к следующему состоянию конечного автомата if r is None: # если следующего состояния нет, то смотрим состояние "по умолчанию" r = current_state.get('') # пробуем перейти в него

i -= 1 # был считан один лишний символ (по индексу i), поэтому отнимаем 1 if r is None: # если нужной ветки нет, то получена неверная лексема i += 1 # увеличиваем на 1, чтобы получить индекс неверной лексемы prev_n = code[:i].rfind('\n') + 1 # начало строки next_n = code[i:].find('\n') + i # конец строки

raise ULexicalError(code_startswith=code[prev_n if prev_n != -1 else i:next_n if next_n != -1 else i + 1], symbol=code[i], line=line) if isinstance(r, str): # если символ-атом i += 1 # переход к следующему символу token = r

lexeme = repr(code[p:i])[1:-1] p = i # обновляем предыдущий индекс

line += code[p:i].count('\n') # обновляем номер текущей строки elif isinstance(r, (tuple, list)): # если регулярное выражение if not isinstance(r, list): r = [r]

for attempt, t in enumerate(r, 1): # r заведомо не пустой token, token_regexp = t

match = re.match(token_regexp, code[p:]) # поиск по регулярному выражению if not match and attempt == len(r): # если неудачный поиск на последней попытке

pos = code[p:].find('\n')

startswith = code[p:(p + pos + 1 if pos != -1 else None)]

raise ULexicalError(code_startswith=startswith, line=line, regexp=token_regexp) elif not match: # если неудачный поиск на текущей попытке, то переход к следующей continue

match_len = match.span(0)[1] # если поиск удачный, получаем число найденных символов i = p + match_len # обновляем текущую позицию lexeme = code[p:i]

p = i # обновляем предыдущий индекс

if lexeme in keywords: # если лексема есть в множестве ключевых слов языка token = lexeme

line += lexeme.count('\n') # обновляем номер текущей строки break

else: # если несколько веток (dict)

i += 1 # один символ был считан, поэтому добавляем 1 current_state = r # переходим к следующему состоянию continue

tokens_and_lexemes.append((token, lexeme)) # добавляем токен и лексему current_state = lexical_fsm # текущее состояние -- начальное состояние return tokens_and_lexemes

def main(code): def print_center(*, message, width, is_start=True, end='\n'): """Печатает текст в центре согласно общей ширине width""" print('=' * width * bool(is_start), message.center(width, '='),

'=' * width * (not bool(is_start)), sep='\n', end=end)

# инициализация

lexical_fsm = C90Language.get_lexical_fsm() # лексика языка в виде конечного автомата keywords = C90Language.get_keywords() # множество ключевых слов языка

maximum_left_indent = max(map(len, re.findall(r'\'([\w\-<>]+)\'', str(lexical_fsm)))) # макс. длина токена format_function = ('{:>' + str(maximum_left_indent) + '} |\'{}\'|').format # функция для форматирования

# лексический анализ

print_center(message=' Lexical analysis ', width=maximum_left_indent * 2, is_start=True, end='') try:

tokens_and_lexemes = lexical_analyzer(lexical_fsm=lexical_fsm, keywords=keywords, code=code) print(*(format_function(token, repr(lexeme)[1:-1]) for token, lexeme in tokens_and_lexemes), sep='\n', end='')

print_center(message=' Success ', width=maximum_left_indent * 2, is_start=False, end='\n\n') except ULexicalError as e: print('LexicalError:', e, end='')

print_center(message=' Error ', width=maximum_left_indent * 2, is_start=False, end='\n\n') return except Exception:

print(traceback.format_exc(), end='')

print_center(message=' Error ', width=maximum_left_indent * 2, is_start=False, end='\n\n') return

if __name__ == "__main__": if len(sys.argv) > 1:

try: with open(sys.argv[-1], 'r') as fp:

main(fp.read()) except Exception as e:

print(*e.args, sep=', ') else: print(f'python3.6 main.py <filename>')

Содержимое файла для лексического анализа приведено в таблице 2.

Таблица 2. Содержимое файла для лексического анализа

file.c

// Single line comment

/*

Multi line comment block

*/

#include <stdio.h>

#include <stdlib.h> #include <wchar.h>

static enum Enum { VAR_1 = 0, VAR_2, VAR_3 = 0, VAR_4, VAR_5 = 0, VAR_6 } some_enum1, some_enum2; const volatile int global_var = 1 + 1 << sizeof(char), another_var = 2 * global_var; static struct Animal { int animal_int : 32;

const void * volatile animal_reference;

} some_animal1, some_animal2; int main(int _, ...) {

int * const r = (int*) malloc(sizeof(int) * 5), k = (2 >> 1) + (1 << 1) - 1 * 1.0e-5/1e+20; wprintf(L"%d", ((0 <= 0 < 2 > 0 >= 0) == 1 != 0));

((((k += 1) -= 1) *= 1) /= 1 % 2) %= 2;

++k; k++; --k; k--;

((k &= 1 || 1 | 1 & 5 && 5) |= ~k ^ k) ^= !k; do {

for (k = 0; k < 5; ++k) {

wprintf(L"\nHello, world\n");

}

while (++k < 10) continue;

} while (0);

fputwc(L'\n', stdout); free(r); return 0;

}

python .\main5.py .\file.c

====================================================

================= Lexical analysis =================

<single-line-comment> |'// Single line comment'|

<whitespace> |'\n'|

<multi-line-comment> |'/*\nMulti line comment block\n*/'|

<whitespace> |'\n'|

<preprocessor-directive> |'#include <stdio.h>'|

<whitespace> |'\n'|

<preprocessor-directive> |'#include <stdlib.h>'|

<whitespace> |'\n'|

<preprocessor-directive> |'#include <wchar.h>'|

<whitespace> |'\n'|

static |'static'|

<whitespace> |' '|

enum |'enum'|

<whitespace> |' '|

<identifier> |'Enum'|

<whitespace> |' '|

<open-curly-bracket> |'{'|

<whitespace> |' '|

<identifier> |'VAR_1'|

<whitespace> |' '|

<assignment> |'='|

<whitespace> |' '|

<integer-constant> |'0'|

<comma> |','|

<whitespace> |' '|

<identifier> |'VAR_2'|

<comma> |','|

<whitespace> |' '|

<identifier> |'VAR_3'|

<whitespace> |' '|

<assignment> |'='|

<whitespace> |' '|

<integer-constant> |'0'|

<comma> |','|

<whitespace> |' '|

<identifier> |'VAR_4'|

<comma> |','|

<whitespace> |' '|

<identifier> |'VAR_5'|

<whitespace> |' '|

<assignment> |'='|

<whitespace> |' '|

<integer-constant> |'0'|

<comma> |','|

<whitespace> |' '|

<identifier> |'VAR_6'|

<whitespace> |' '|

<close-curly-bracket> |'}'|

<whitespace> |' '|

<identifier> |'some_enum1'|

<comma> |','|

<whitespace> |' '|

<identifier> |'some_enum2'|

<semicolon> |';'|

<whitespace> |'\n'|

const |'const'|

<whitespace> |' '|

volatile |'volatile'|

<whitespace> |' '|

int |'int'|

<whitespace> |' '|

<identifier> |'global_var'|

<whitespace> |' '|

<assignment> |'='|

<whitespace> |' '|

<integer-constant> |'1'|

<whitespace> |' '|

<plus> |'+'|

<whitespace> |' '|

<integer-constant> |'1'|

<whitespace> |' '|

<left-shift> |'<<'|

<whitespace> |' '|

sizeof |'sizeof'|

<open-bracket> |'('|

char |'char'|

<close-bracket> |')'|

<comma> |','|

<whitespace> |' '|

<identifier> |'another_var'|

<whitespace> |' '|

<assignment> |'='|

<whitespace> |' '|

<integer-constant> |'2'|

<whitespace> |' '|

<multiply-or-pointer> |'*'|

<whitespace> |' '|

<identifier> |'global_var'|

<semicolon> |';'|

<whitespace> |'\n'|

static |'static'|

<whitespace> |' '|

struct |'struct'|

<whitespace> |' '|

<identifier> |'Animal'|

<whitespace> |' '|

<open-curly-bracket> |'{'|

<whitespace> |'\n '|

int |'int'|

<whitespace> |' '|

<identifier> |'animal_int'|

<whitespace> |' '|

<colon> |':'|

<whitespace> |' '|

<integer-constant> |'32'|

<semicolon> |';'|

<whitespace> |'\n '|

const |'const'|

<whitespace> |' '|

void |'void'|

<whitespace> |' '|

<multiply-or-pointer> |'*'|

<whitespace> |' '|

volatile |'volatile'|

<whitespace> |' '|

<identifier> |'animal_reference'|

<semicolon> |';'|

<whitespace> |'\n'|

<close-curly-bracket> |'}'|

<whitespace> |' '|

<identifier> |'some_animal1'|

<comma> |','|

<whitespace> |' '|

<identifier> |'some_animal2'|

<semicolon> |';'|

<whitespace> |'\n'|

int |'int'|

<whitespace> |' '|

<identifier> |'main'|

<open-bracket> |'('|

int |'int'|

<whitespace> |' '|

<identifier> |'_'|

<comma> |','|

<whitespace> |' '|

<ellipsis> |'...'|

<close-bracket> |')'|

<whitespace> |' '|

<open-curly-bracket> |'{'|

<whitespace> |'\n '|

int |'int'|

<whitespace> |' '|

<multiply-or-pointer> |'*'|

<whitespace> |' '|

const |'const'|

<whitespace> |' '|

<identifier> |'r'|

<whitespace> |' '|

<assignment> |'='|

<whitespace> |' '|

<open-bracket> |'('|

int |'int'|

<multiply-or-pointer> |'*'|

<close-bracket> |')'|

<whitespace> |' '|

<identifier> |'malloc'|

<open-bracket> |'('|

sizeof |'sizeof'|

<open-bracket> |'('|

int |'int'|

<close-bracket> |')'|

<whitespace> |' '|

<multiply-or-pointer> |'*'|

<whitespace> |' '|

<integer-constant> |'5'|

<close-bracket> |')'|

<comma> |','|

<whitespace> |' '|

<identifier> |'k'|

<whitespace> |' '|

<assignment> |'='|

<whitespace> |' '|

<open-bracket> |'('|

<integer-constant> |'2'|

<whitespace> |' '|

<right-shift> |'>>'|

<whitespace> |' '|

<integer-constant> |'1'|

<close-bracket> |')'|

<whitespace> |' '|

<plus> |'+'|

<whitespace> |' '|

<open-bracket> |'('|

<integer-constant> |'1'|

<whitespace> |' '|

<left-shift> |'<<'|

<whitespace> |' '|

<integer-constant> |'1'|

<close-bracket> |')'|

<whitespace> |' '|

<minus> |'-'|

<whitespace> |' '|

<integer-constant> |'1'|

<whitespace> |' '|

<multiply-or-pointer> |'*'|

<whitespace> |' '|

<floating-constant> |'1.0e-5'|

<divide> |'/'|

<floating-constant> |'1e+20'|

<semicolon> |';'|

<whitespace> |'\n '|

<identifier> |'wprintf'|

<open-bracket> |'('|

<string> |'L"%d"'|

<comma> |','|

<whitespace> |' '|

<open-bracket> |'('|

<open-bracket> |'('|

<integer-constant> |'0'|

<whitespace> |' '|

<less-than-or-equal-to> |'<='|

<whitespace> |' '|

<integer-constant> |'0'|

<whitespace> |' '|

<less-than> |'<'|

<whitespace> |' '|

<integer-constant> |'2'|

<whitespace> |' '|

<greater-than> |'>'|

<whitespace> |' '|

<integer-constant> |'0'|

<whitespace> |' '|

<greater-than-or-equal-to> |'>='|

<whitespace> |' '|

<integer-constant> |'0'|

<close-bracket> |')'|

<whitespace> |' '|

<equal-to> |'=='|

<whitespace> |' '|

<integer-constant> |'1'|

<whitespace> |' '|

<not-equals> |'!='|

<whitespace> |' '|

<integer-constant> |'0'|

<close-bracket> |')'|

<close-bracket> |')'|

<semicolon> |';'|

<whitespace> |'\n '|

<open-bracket> |'('|

<open-bracket> |'('|

<open-bracket> |'('|

<open-bracket> |'('|

<identifier> |'k'|

<whitespace> |' '|

<plus-equals> |'+='|

<whitespace> |' '|

<integer-constant> |'1'|

<close-bracket> |')'|

<whitespace> |' '|

<minus-equals> |'-='|

<whitespace> |' '|

<integer-constant> |'1'|

<close-bracket> |')'|

<whitespace> |' '|

<mul-equals> |'*='|

<whitespace> |' '|

<integer-constant> |'1'|

<close-bracket> |')'|

<whitespace> |' '|

<div-equals> |'/='|

<whitespace> |' '|

<integer-constant> |'1'|

<whitespace> |' '|

<modulus> |'%'|

<whitespace> |' '|

<integer-constant> |'2'|

<close-bracket> |')'|

<whitespace> |' '|

<modulus-equals> |'%='|

<whitespace> |' '|

<integer-constant> |'2'|

<semicolon> |';'|

<whitespace> |'\n '|

<increment> |'++'|

<identifier> |'k'|

<semicolon> |';'|

<whitespace> |' '|

<identifier> |'k'|

<increment> |'++'|

<semicolon> |';'|

<whitespace> |' '|

<decrement> |'--'|

<identifier> |'k'|

<semicolon> |';'|

<whitespace> |' '|

<identifier> |'k'|

<decrement> |'--'|

<semicolon> |';'|

<whitespace> |'\n '|

<open-bracket> |'('|

<open-bracket> |'('|

<identifier> |'k'|

<whitespace> |' '|

<binary-and-equals> |'&='|

<whitespace> |' '|

<integer-constant> |'1'|

<whitespace> |' '|

<logical-or> |'||'|

<whitespace> |' '|

<integer-constant> |'1'|

<whitespace> |' '|

<binary-or> |'|'|

<whitespace> |' '|

<integer-constant> |'1'|

<whitespace> |' '|

<binary-and> |'&'|

<whitespace> |' '|

<integer-constant> |'5'|

<whitespace> |' '|

<logical-and> |'&&'|

<whitespace> |' '|

<integer-constant> |'5'|

<close-bracket> |')'|

<whitespace> |' '|

<binary-or-equals> |'|='|

<whitespace> |' '|

<tilde> |'~'|

<identifier> |'k'|

<whitespace> |' '|

<binary-xor> |'^'|

<whitespace> |' '|

<identifier> |'k'|

<close-bracket> |')'|

<whitespace> |' '|

<binary-xor-equals> |'^='|

<whitespace> |' '|

<logical-not> |'!'|

<identifier> |'k'|

<semicolon> |';'|

<whitespace> |'\n '|

do |'do'|

<whitespace> |' '|

<open-curly-bracket> |'{'|

<whitespace> |'\n '|

for |'for'|

<whitespace> |' '|

<open-bracket> |'('|

<identifier> |'k'|

<whitespace> |' '|

<assignment> |'='|

<whitespace> |' '|

<integer-constant> |'0'|

<semicolon> |';'|

<whitespace> |' '|

<identifier> |'k'|

<whitespace> |' '|

<less-than> |'<'|

<whitespace> |' '|

<integer-constant> |'5'|

<semicolon> |';'|

<whitespace> |' '|

<increment> |'++'|

<identifier> |'k'|

<close-bracket> |')'|

<whitespace> |' '|

<open-curly-bracket> |'{'|

<whitespace> |'\n '|

<identifier> |'wprintf'|

<open-bracket> |'('|

<string> |'L"\\nHello, world\\n"'|

<close-bracket> |')'|

<semicolon> |';'|

<whitespace> |'\n '|

<close-curly-bracket> |'}'|

<whitespace> |'\n '|

while |'while'|

<whitespace> |' '|

<open-bracket> |'('|

<increment> |'++'|

<identifier> |'k'|

<whitespace> |' '|

<less-than> |'<'|

<whitespace> |' '|

<integer-constant> |'10'|

<whitespace> |'\n '|

return |'return'|

<whitespace> |' '|

<integer-constant> |'0'|

<semicolon> |';'|

<whitespace> |'\n'|

<close-curly-bracket> |'}'|

===================== Success ======================

====================================================