Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Мячина_5ЛР

.docx
Скачиваний:
0
Добавлен:
02.08.2026
Размер:
159 Кб
Скачать

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

Ордена Трудового Красного Знамени федеральное государственное бюджетное образовательное учреждение высшего образования

Московский технический университет связи и информатики

(МТУСИ)

Кафедра «Системное программирование»

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

«Проектирование лексического анализатора»

по дисциплине «Системное программное обеспечение»

Вариант 8

Выполнила:

студентка группы БФИ2203

Мячина Лада Андреевна

Проверила:

Старший преподаватель

Алексанян Диана Ашотовна

Москва, 2025 г.

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

Задание варианта 4: входной язык содержит операторы цикла типа for (…; …; …) do, разделенные символом; (точка с запятой). Операторы цикла содержат идентификаторы, знаки сравнения, =, десятичные числа с плавающей точкой (в обычной и логарифмической форме), знак присваивания (:=).

Ход работы:

Форма Бэкуса-Наура для входного языка:

<программа> ::= <оператор> (';' <оператор>)*

<оператор> ::= <цикл_for> | <комментарий>

<цикл_for> ::= 'for' '(' [<инициализация>] ';' [<условие>] ';' [<приращение>] ')' 'do'

<инициализация> ::= <присваивание>

<условие> ::= <выражение> <оператор_сравнения> <выражение>

<приращение> ::= <присваивание>

<присваивание> ::= <идентификатор> ':=' <выражение>

<выражение> ::= <идентификатор> | <римское_число>

<оператор_сравнения> ::= '<' | '>' | '='

<римское_число> ::= ('I' | 'V' | 'X')+

<идентификатор> ::= [a-zA-Z_][a-zA-Z0-9_]{0,31}

<комментарий> ::= '{' <текст_комментария> '}'

<текст_комментария> ::= [^}]*

Основной алгоритм:

  1. Инициализация - установка начальных позиций (строка=1, позиция=1)

  2. Чтение символов - последовательное чтение входного текста

  3. Пропуск пробелов - игнорирование пробелов, табуляций, переносов строк

  4. Определение типа лексемы по первому символу:

    • { - начало комментария

    • Буква или _ - идентификатор/ключевое слово/римское число

    • : - оператор присваивания

    • <, >, = - оператор сравнения

    • (, ), ; - разделители

  5. Разбор лексемы соответствующим методом

  6. Добавление в таблицу лексем

  7. Проверка ошибок и вывод сообщений

  8. Повтор до конца файла

Листинг программы для выполнения ЛР:

import re

import sys

# Типы лексем

class TokenType:

FOR = 'FOR'

DO = 'DO'

IDENTIFIER = 'IDENTIFIER'

ROMAN_NUMERAL = 'ROMAN_NUMERAL'

ASSIGN = 'ASSIGN'

COMPARISON = 'COMPARISON'

LPAREN = 'LPAREN'

RPAREN = 'RPAREN'

SEMICOLON = 'SEMICOLON'

COMMENT = 'COMMENT'

ERROR = 'ERROR'

# Класс для представления лексемы

class Token:

def __init__(self, type, value, line, position):

self.type = type

self.value = value

self.line = line

self.position = position

def __str__(self):

return f"{self.type:<15} {self.value:<10} at line {self.line}, pos {self.position}"

class Lexer:

def __init__(self, text):

self.text = text

self.pos = 0

self.line = 1

self.line_pos = 1

self.tokens = []

self.keywords = {'for': TokenType.FOR, 'do': TokenType.DO}

self.comparison_ops = {'<', '>', '='}

self.roman_symbols = {'I', 'V', 'X'}

def error(self, message):

print(f"Lexical error at line {self.line}, position {self.line_pos}: {message}")

return Token(TokenType.ERROR, message, self.line, self.line_pos)

def get_next_char(self):

if self.pos >= len(self.text):

return None

char = self.text[self.pos]

self.pos += 1

if char == '\n':

self.line += 1

self.line_pos = 1

else:

self.line_pos += 1

return char

def peek_next_char(self):

if self.pos >= len(self.text):

return None

return self.text[self.pos]

def skip_whitespace(self):

while self.pos < len(self.text) and self.text[self.pos].isspace():

self.get_next_char()

def parse_comment(self):

start_line = self.line

start_pos = self.line_pos

comment = ''

char = self.get_next_char() # Пропускаем открывающую {

while True:

if char is None:

return self.error("Unclosed comment")

if char == '}':

break

comment += char

char = self.get_next_char()

return Token(TokenType.COMMENT, comment, start_line, start_pos)

def parse_identifier_or_roman(self):

start_line = self.line

start_pos = self.line_pos

value = ''

char = self.peek_next_char()

while char is not None and (char.isalnum() or char == '_'):

value += self.get_next_char()

char = self.peek_next_char()

# Проверяем是否是罗马数字

if all(c in self.roman_symbols for c in value):

return Token(TokenType.ROMAN_NUMERAL, value, start_line, start_pos)

# Проверяем是否是ключевоеслово

elif value.lower() in self.keywords:

return Token(self.keywords[value.lower()], value, start_line, start_pos)

else:

if len(value) > 32:

self.error(f"Identifier too long: {value}")

return Token(TokenType.IDENTIFIER, value, start_line, start_pos)

def parse_assignment(self):

start_line = self.line

start_pos = self.line_pos

self.get_next_char() # Пропускаем :

next_char = self.get_next_char()

if next_char == '=':

return Token(TokenType.ASSIGN, ':=', start_line, start_pos)

else:

return self.error("Expected '=' after ':'")

def tokenize(self):

while self.pos < len(self.text):

self.skip_whitespace()

if self.pos >= len(self.text):

break

current_char = self.peek_next_char()

if current_char == '{':

token = self.parse_comment()

if token.type != TokenType.ERROR:

self.tokens.append(token)

elif current_char.isalpha() or current_char == '_':

token = self.parse_identifier_or_roman()

self.tokens.append(token)

elif current_char == ':':

token = self.parse_assignment()

self.tokens.append(token)

elif current_char in self.comparison_ops:

start_line = self.line

start_pos = self.line_pos

op = self.get_next_char()

self.tokens.append(Token(TokenType.COMPARISON, op, start_line, start_pos))

elif current_char == '(':

start_line = self.line

start_pos = self.line_pos

self.get_next_char()

self.tokens.append(Token(TokenType.LPAREN, '(', start_line, start_pos))

elif current_char == ')':

start_line = self.line

start_pos = self.line_pos

self.get_next_char()

self.tokens.append(Token(TokenType.RPAREN, ')', start_line, start_pos))

elif current_char == ';':

start_line = self.line

start_pos = self.line_pos

self.get_next_char()

self.tokens.append(Token(TokenType.SEMICOLON, ';', start_line, start_pos))

else:

token = self.error(f"Unexpected character: {current_char}")

self.tokens.append(token)

self.get_next_char()

return self.tokens

def main():

if len(sys.argv) != 2:

print("Usage: python lexer.py <input_file>")

return

try:

with open(sys.argv[1], 'r', encoding='utf-8') as f:

text = f.read()

except FileNotFoundError:

print(f"Error: File {sys.argv[1]} not found")

return

lexer = Lexer(text)

tokens = lexer.tokenize()

print("Tokens found:")

print("-" * 50)

for token in tokens:

print(token)

if __name__ == "__main__":

main()

Файл без ошибок

Файл с ошибками

Соседние файлы в предмете Системное программное обеспечение