Главная страница
Навигация по странице:

  • Диаграмма состояний

  • Диаграммы Вирта

  • Целое : Двоичное

  • Восьмеричное: Десятичное

  • Действительное: Шестнадцатиричное

  • Числовая строка: Порядок

  • Операции группы отношения

  • Логическая константа: ANTLR

  • Лабораторная работа по предмету Конструирование компиляторов


    Скачать 0.97 Mb.
    НазваниеЛабораторная работа по предмету Конструирование компиляторов
    Дата07.11.2021
    Размер0.97 Mb.
    Формат файлаdocx
    Имя файлаOtschyot_konstruirovanie_kompilyatorov.docx
    ТипЛабораторная работа
    #265037

    ПГУТИ

    Кафедра ИВТ





    Лабораторная работа по предмету «Конструирование компиляторов»

    Выполнил: Белов Н.В.

    Проверила: Бахарева Н.Ф.

    Введение


    Компилятор — это программа, которая осуществляет перевод исходной программы в эквивалентную ей объектную программу на языке машинных команд или языке ассемблере.

    Несмотря на более чем полувековую историю вычислительной техники, формально годом рождения теории компиляторов можно считать 1957, когда появился первый компилятор языка Фортран, созданный Бэкусом и дающий достаточно эффективный объектный код. До этого времени создание компиляторов было весьма творческим процессом. Лишь появление теории формальных языков и строгих математических моделей позволило перейти от творчества к науке. Именно благодаря этому, стало возможным появление сотен новых языков программирования.

    Цель работы:

    -закрепление теоретических знаний в области теории формальных языков, грамматик, автоматов и методов трансляции;

    -формирование практических умений и навыков разработки собственного компилятора модельного языка программирования;

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

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

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


    1) В соответствии с номером варианта составить формальное описание модельного языка программирования с помощью:

    а) РБНФ;

    б) диаграмм Вирта;

    2) Написать пять содержательных примеров программ, раскрывающих особенности конструкций учебного языка программирования, отразив в этих примерах все его функциональные возможности.

    3) Составить таблицы лексем и диаграмму состояний с действиями для распознавания и формирования лексем языка.

    4) Используя генератор нисходящих компиляторов

    а) сгенерировать лексический анализатор

    б) сгенерировать синтаксический анализатор

    5) с помощью анализаторов

    а) провести лексический анализ тестового примера

    б) построить абстрактное синтаксическое дерево

    в) получить доступ к абстрактному синтаксическому дереву

    г) вывести абстрактное синтаксическое дерево в консоль




    Формальная модель задачи
    Модельный язык в расширенной форме Бэкуса — Наура


    <операции_группы_отношения>::= < > | = | < | <= | > | >=
    <операции_группы_сложения>:: = + | - | or 

    <операции_группы_умножения>::= * | / | and 

    <унарная_операция>::= not 
    <выражение>::= <операнд>{<операции_группы_отношения> <операнд>} 
    <операнд>::= <слагаемое> {<операции_группы_сложения> <слагаемое>} 
    <слагаемое>::= <множитель> {<операции_группы_умножения> <множитель>} 
    <множитель>::= <идентификатор> | <число> | <логическая_константа> | 
                       <унарная_операция>  <множитель> | (<выражение>) 
    <число>::= <целое> | <действительное> 
    <логическая_константа>::= true | false 
    <идентификатор>::= <буква> {<буква> | <цифра>} 
    <буква>::= A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T| U | V | W | X | Y | Z | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p  q | r | s | t | u | v | w | x | y | z 
    <цифра>::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 
    <целое>::= <двоичное> | <восьмеричное> | <десятичное> |  <шестнадцатеричное> 
    <двоичное>::= {/ 0 | 1 /} (B | b) 
    <восьмеричное>::= {/ 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 /} (O | o) 
    <десятичное>::= {/ <цифра> /} [D | d] 
    <шестнадцатеричное>::= <цифра> {<цифра> | A | B | C | D | E | F | a | b| c | d | e | f} (H | h) 
    <действительное>::= <числовая_строка> <порядок> | [<числовая_строка>] . <числовая_строка> [порядок] 
    <числовая_строка>::= {/ <цифра> /} 
    <порядок>::= ( E | e )[+ | -] <числовая_строка> 
    <программа> = «{» {/ (<описание> | <оператор>) ; /} «}» 

    <описание>::= dim <идентификатор> {, <идентификатор> } <тип>

    <тип>::= int | float | bool 
    <оператор>::= <составной> | <присваивания> | <условный> |  <фиксированного_цикла> | <условного_цикла> | <ввода> | <вывода> 
    <составной>::= <оператор> { ( : | перевод строки) <оператор> }

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

    <условный>::= if <выражение> then <оператор> [else <оператор>]

    <фиксированного_цикла>::= for <присваивания> to <выражение> do <оператор>

    <условного_цикла>::= while <выражение> do <оператор>

    <ввода>::= read «(»<идентификатор> {, <идентификатор> }«)»

    <вывода>::= write «(»<выражение> {, <выражение> }«)»

    Комментарии  

    {

    }

     

    Служебные слова (1):

    true

    false

    dim

    int

    float

    bool

    if

    then

    else

    for

    to

    do

    while

    read

    write

     

    Разделители (2):

    <>

    =

    <

    <=

    >

    >=

    +

    -

    or

    *

    /

    and

    not

    (

    )

    {

    }

    ;

    :

    ,

    ass




























    Диаграмма состояний



    Рис 1. Диаграмма состояний при распознавании базовых лексем



    Рис 2. Диаграмма состояний при распознавании числа



    Рис 3. Диаграмма состояний при распознавании порядка числа

    Диаграммы Вирта







    число







    Целое:


    Двоичное:



    Восьмеричное:



    Десятичное:



    Действительное:



    Шестнадцатиричное:



    Числовая строка:



    Порядок:



    Оператор:





















    Операции группы отношения:







    Логическая константа:



    ANTLR

    Для реализации модульного языка был выбран язык программирования Python3 и среда разработки PyCharm в окружении дистрибутива Debian 11.

    Для начала необходимо установить python3, pip и antlr4, выполним от администратора:

    apt install python3 pip antlr4

    Далее установим библиотеку antlr4 для python3:

    pip install antlr4-python3-runtime

    После этого создаём проект в PyCharm, в нём создаём грамматику, главный файл и слушатель.

    grammar GrammarBelovNikita;
    BOOL: 'true' | 'false';
    TYPE: 'int' | 'float' | 'bool';
    WS: [ \n\t\r]+ -> skip;

    SPACE: ' ';

    COMMA: ',';

    COLON: ':';

    SEMICOLON: ';';
    BLOCK_OPEN: '(';

    BLOCK_CLOSE: ')';
    OPERATION_RATIO: '=' | '<>' | '<' | '<=' | '>' | '>=';

    OPERATION_SUMMARY: '+' | '-' | 'or';

    OPERATION_MULTIPLE: '*' | '/' | 'and';

    OPERATION_UNARY: 'not';
    fragment NUMBER_STRING: [0-9]+;
    IDENTIFIER: [a-zA-Z]([a-zA-Z] | NUMBER_STRING)*;
    NUMBERS: INTEGER | REAL;
    INTEGER: BINARY | OCTAL | DECIMAL | HEXADECIMAL;
    BINARY: [0-1]+ ('B' | 'b');
    OCTAL: [0-7]+ ('O' | 'o');
    DECIMAL: NUMBER_STRING ('D' | 'd')?;
    HEXADECIMAL: NUMBER_STRING ([0-9] | [a-fA-F])* ('H' | 'h');
    REAL: (

    (NUMBER_STRING ORDER)

    | ((NUMBER_STRING)? '.' NUMBER_STRING (ORDER)?)

    );
    fragment ORDER: ('E' | 'e') ('+' | '-')? NUMBER_STRING;
    // ------------------
    program: '{' ((((description | operator) SEMICOLON) | multistr_comment) (' ' | '\n' | '\t' | '\r')*)+ '}';
    description: 'dim' IDENTIFIER (COMMA IDENTIFIER)* TYPE;
    operator: operator_wo_composite | composite;

    operator_wo_composite:

    assignments

    | conditional

    | fixed_cycle

    | conditional_loop

    | input_m

    | output_m;
    composite:

    operator_wo_composite ((COLON | '\n') operator_wo_composite)*;
    assignments: IDENTIFIER 'ass' expression;
    conditional: 'if' expression 'then' operator ('else' operator)?;
    fixed_cycle: 'for' assignments 'to' expression 'do' operator;
    conditional_loop: 'while' expression 'do' operator;
    expression: operand ( OPERATION_RATIO operand)*;
    operand: summand (OPERATION_SUMMARY summand)*;
    summand: multiplier (OPERATION_MULTIPLE multiplier)*;
    multiplier:

    BOOL

    | IDENTIFIER

    | NUMBERS

    | OPERATION_UNARY multiplier

    | BLOCK_OPEN expression BLOCK_CLOSE;
    input_m:

    'read' BLOCK_OPEN IDENTIFIER (COMMA IDENTIFIER)* BLOCK_CLOSE;
    output_m:

    'write' BLOCK_OPEN expression (COMMA expression)* BLOCK_CLOSE;
    multistr_comment: '{' '}'* '}';

    Листинг 1. GrammarBelovNikita.g4

    import sys

    from antlr4 import *
    from MyListner import MyGrammarListner

    from com.antlr.GrammarBelovNikitaLexer import GrammarBelovNikitaLexer

    from com.antlr.GrammarBelovNikitaParser import GrammarBelovNikitaParser
    def create_generator(argv):

    lexer = GrammarBelovNikitaLexer(FileStream('test.prog'))

    stream = CommonTokenStream(lexer)

    parser = GrammarBelovNikitaParser(stream)

    tree = parser.program()

    program = MyGrammarListner()

    walker = ParseTreeWalker()

    walker.walk(program,tree)
    if __name__ == '__main__':

    create_generator(sys.argv)

    Листинг 2. Главный файл приложения.

    import antlr4

    import regex as regex
    from com.antlr.GrammarBelovNikitaListener import GrammarBelovNikitaListener

    from com.antlr.GrammarBelovNikitaParser import GrammarBelovNikitaParser
    class MyGrammarListner(GrammarBelovNikitaListener):
    def enterProgram(self, ctx: GrammarBelovNikitaParser.ProgramContext):

    self.variables = {}

    self.stack_value = []
    def enterDescription(self, ctx: GrammarBelovNikitaParser.DescriptionContext):

    # проходимся циклом по токенам до :

    type = ctx.TYPE()

    for identifier in ctx.IDENTIFIER():

    #print(identifier.__str__() + ' (' + type.__str__() + ')')

    self.variables[identifier.__str__()] = {

    'type': type.__str__(),

    'value': 'None'

    }
    def exitDescription(self, ctx: GrammarBelovNikitaParser.DescriptionContext):

    pass
    def enterExpression(self, ctx: GrammarBelovNikitaParser.ExpressionContext):

    pass
    def exitExpression(self, ctx: GrammarBelovNikitaParser.ExpressionContext):

    pass
    def exitAssignments(self, ctx: GrammarBelovNikitaParser.AssignmentsContext):

    # Присваивание

    buf_ident = ctx.IDENTIFIER().__str__()

    if buf_ident in self.variables.keys():

    # проверяем на типы данных

    # expression - должен быть последним в наборе данных, по этому берем последнее

    expression = self.stack_value[-1]

    if self.variables[buf_ident]['type'] == expression['type']:

    self.variables[buf_ident]['value'] = expression['value']

    #print(str(buf_ident) + ' = ' + str(self.variables[buf_ident]['value']))

    elif self.variables[buf_ident]['type'] == 'int' and expression['type'] == 'float':

    self.variables[buf_ident]['type'] = 'float'

    self.variables[buf_ident]['value'] = expression['value']

    elif self.variables[buf_ident]['type'] == 'float' and expression['type'] == 'int':

    self.variables[buf_ident]['value'] = expression['value']

    else:

    print('Ошибка! Переменной ' + self.variables[buf_ident]['type'] + ' нельзя присвоить данные типа ' +

    expression['type'])

    print(str(buf_ident) + ' = ' + str(self.variables[buf_ident]['value']))
    def exitExpression(self, ctx: GrammarBelovNikitaParser.ExpressionContext):

    if ctx.OPERATION_RATIO():

    print(ctx.OPERATION_RATIO())

    return
    def exitOperand(self, ctx: GrammarBelovNikitaParser.OperandContext):

    if ctx.OPERATION_SUMMARY():

    count_move = len(ctx.OPERATION_SUMMARY())

    list_operand = list(reversed(self.stack_value[-(count_move+1):]))

    del self.stack_value[-(count_move + 1):]

    for i in range(0, len(ctx.OPERATION_SUMMARY())):

    buf_value = {'type': None, 'value': None}

    operation = str(ctx.OPERATION_SUMMARY()[i])

    left = list_operand[count_move-i]

    right = list_operand[count_move-i-1]

    if operation == '+':

    if left['type'] != 'bool' and right['type'] != 'bool':

    buf_value['value'] = left['value'] + right['value']

    # TODO

    if left['type'] == 'float' or right['type'] == 'float':

    buf_value['type'] = 'float'

    else:

    buf_value['type'] = 'integer'

    elif operation == '-':

    if left['type'] != 'bool' and right['type'] != 'bool':

    buf_value['value'] = left['value'] - right['value']

    if left['type'] == 'float' or right['type'] == 'float':

    buf_value['type'] = 'float'

    else:

    buf_value['type'] = 'integer'

    elif operation == 'or':

    if left['type'] == 'bool' and right['type'] == 'bool':

    buf_value = left['value'] | right['value']

    del list_operand[count_move - i]

    del list_operand[count_move - i - 1]

    #print('add ' + buf_value['type'] + ' ' + buf_value['value'])

    list_operand.append({'type': buf_value['type'], 'value': buf_value['value']})

    self.stack_value.append(list_operand[0])
    def exitSummand(self, ctx: GrammarBelovNikitaParser.SummandContext):

    if ctx.OPERATION_MULTIPLE():

    count_move = len(ctx.OPERATION_MULTIPLE())

    list_operand = list(reversed(self.stack_value[-(count_move + 1):]))

    del self.stack_value[-(count_move + 1):]

    for i in range(0, len(ctx.OPERATION_MULTIPLE())):

    buf_value = {'type': None, 'value': None}

    operation = str(ctx.OPERATION_MULTIPLE()[i])

    left = list_operand[count_move - i]

    right = list_operand[count_move - i - 1]

    if operation == '*':

    if left['type'] != 'bool' and right['type'] != 'bool':

    buf_value['value'] = left['value'] * right['value']

    if left['type'] == 'float' or right['type'] == 'float':

    buf_value['type'] = 'float'

    else:

    buf_value['type'] = 'int'

    elif operation == '/':

    if left['type'] != 'float' and right['type'] != 'float':

    buf_value['value'] = left['value'] / right['value']

    buf_value['type'] = 'float'

    elif operation == 'and':

    if left['type'] == 'bool' and right['type'] == 'bool':

    buf_value = left['value'] & right['value']

    del list_operand[count_move - i]

    del list_operand[count_move - i - 1]

    #print('add ' + buf_value['type'] + ' ' + buf_value['value'])

    list_operand.append({'type': buf_value['type'], 'value': buf_value['value']})

    self.stack_value.append(list_operand[0])

    #print('exit operand')

    #print('exit summand')
    def exitMultiplier(self, ctx: GrammarBelovNikitaParser.MultiplierContext):

    #print(ctx.OPERATION_UNARY())

    #Здесь необходимо записать данные о значении просто в память

    if ctx.OPERATION_UNARY():

    self.stack_value.append('not')

    elif ctx.BOOL():

    self.stack_value.append(self.get_value_with_type(ctx.BOOL().__str__()))

    elif ctx.IDENTIFIER():

    self.stack_value.append(self.variables[str(ctx.IDENTIFIER())])

    elif ctx.NUMBERS():

    self.stack_value.append(self.get_value_with_type(ctx.NUMBERS().__str__()))

    elif ctx.BLOCK_OPEN() and ctx.BLOCK_CLOSE():

    self.stack_value.append(ctx.BLOCK_OPEN().__str__())

    self.stack_value.append(ctx.BLOCK_CLOSE().__str__())

    #print('exit multiplier')
    def exitProgram(self, ctx: GrammarBelovNikitaParser.ProgramContext):

    print('Программа закончила свою работу')
    def exitOutput_m(self, ctx:GrammarBelovNikitaParser.Output_mContext):

    list_children = [x for x in ctx.children if str(x) not in ['write','(',',',')']]

    buf_k = ''

    for x in list_children:

    try:

    buf_k += str(self.get_value_with_type(x.start.text))

    except:

    buf_k += str(self.get_value_with_type(x.symbol.text))

    buf_k += '\n'

    print(buf_k)
    def get_value_with_type(self, value: str) -> dict:

    if isinstance(value, antlr4.TerminalNode):

    return

    #print('_DBG_: ' + value)

    #print(self.stack_value)

    output = {

    'type': None,

    'value': None

    }

    if value in self.variables.keys():

    return self.variables[value]

    # если bool

    if any(x in value for x in ['true', 'false']):

    output['type'] = 'bool'

    if value == 'true':

    output['value'] = True

    else:

    output['value'] = False

    # если real

    # < действительное >: := < числовая_строка > < порядок > | [ < числовая_строка >].< числовая_строка > [

    # порядок]

    elif regex.fullmatch(r'([0-9]+[eE][+-][0-9]+)|([0-9]*\.[0-9]+([eE][+-][0-9]+)?)', value):

    output['type'] = 'float'

    output['value'] = float(value)

    else:

    output['type'] = 'int'

    # двоичное

    if regex.fullmatch(r'[01]+[bB]', value):

    value = regex.split(r'[bB]', value)[0]

    output['value'] = int(value, 2)

    # восьмиричное

    elif regex.fullmatch(r'[0-7]+[oO]', value):

    value = regex.split(r'[oO]', value)[0]

    output['value'] = int(value, 8)

    # десятичное

    elif regex.fullmatch(r'[0-9]+[dD]?', value):

    value = regex.split(r'[dD]', value)[0]

    output['value'] = int(value, 10)

    # шестнадцатеричное

    elif regex.fullmatch(r'[0-9][0-9a-fA-F]+[hH]', value):

    value = regex.split(r'[hH]', value)[0]

    output['value'] = int(value, 16)

    return output

    Листинг 3. Слушатель.

    Для тестирования программы используем следующий файл:

    {

    dim intVar, i int;

    dim floatVar, f float;

    intVar ass 123 ;

    i ass 10101010b;

    floatVar ass 456;

    f ass 78.90;

    write(intVar, i, floatVar, f, 101, true);

    { lelelele

    kearkeaw }

    }

    Листинг 4. Тестовая программа модульного языка.

    intVar = 123

    i = 170

    floatVar = 456

    f = 78.9

    {'type': 'int', 'value': 123}

    {'type': 'int', 'value': 170}

    {'type': 'float', 'value': 456}

    {'type': 'float', 'value': 78.9}

    {'type': 'int', 'value': 101}

    {'type': 'bool', 'value': True}
    Программа закончила свою работу

    Листинг 5. Вывод работы тестовой программы модульного языка.


    написать администратору сайта