Курсовая работа: Конструирование модели лексического и синтаксического анализа

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

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

1.2 Анализ предметной области

Входящая последовательность - исходный код программы (рис. 1). В коде присутствуют массивы String Char, Int, Float, а так же указатели и ссылки “*”. Программа, работающая по исходному коду, в качестве результата выводит сначала размер массива после выводит массив рандомных чисел от 0 до 10 (рис. 2). В ходе лексического анализа должны быть выделены лексемы каждого класса, в том числе ключевых слов. Также в ходе анализа должны быть обнаружены ошибки в написании лексем, если таковые имеются. Синтаксический анализ на основе грамматики проверит правильность написания с точки зрения синтаксиса.

#include <iostream>

#include <string>

#include <ctime>

using namespace std;

void opF(int* ar, int* gogo) {

*gogo += *ar;

}

int main()

{

srand(time(NULL));

int m = 0;

int arr[5] = { 3,4,2 };

string mas ="awd";

for (int i = 0; i <2; i++)

{

opF(& arr[i], &m);

}

float *m1 = new float[m];

for (int y = 0; y < m; y++) {

m1[y] = rand() % 10;

cout <<"_"<<m1[y];

}

}

2. Конструирование модели лексического анализа

2.1 Лексический анализ

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

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

2.2 Построение конечного автомата

Граф конечного автомата представлен в п. 2.3, рис. 1

Конечный автомат (КА) демонстрирует работу лексического анализатора по считыванию входной последовательности символов. Считывание начинается в состоянии S0 и продолжается по соответствующему пути в зависимости от считанного символа. Входящим символом автомата считается последний считанный символ. При считывании определённого символа (первой буквы ключевого слова, цифры или прочего) автомат из состояния S0 переходит в соответствующее состояние.

Конечный автомат состоит из пяти компонентов следующего вида:

А = (X, S, F, S0, д), где:

- X - конечное непустое множество входных символов;

- S - конечное непустое множество состояний;

- F - множество выделенных заключительных состояний;

- S0 - начальное состояние;

- д - функция перехода конечного автомата (X*S > S).

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

X: ( 0..9, a..z, A..Z,

операторы - {+, -, *, /, %, =, !, ++,--,+=,-=,*=, << , >>},

сравнения - {>, <,<=,>=,==,!=,||,&&},

пунктуации - {;, (, ), [, ], {, }, “.”, “,”, “})

F: {S1, S2, S301, S305, S100, S101}

S: (S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19, S20, S21, S22, S23, S24, S25, S26, S27, S28, S29, S30, S31, S32, S33, S34, S35, S36, S37, S38, S39, S40, S41, S42, S43, S47, S48, S49, S50, S60, S61, S62, S63, S64, S65, S66, S67, S68, S69, S70, S71, S100, S101, S200, S300, S301, S302, S305, S400, S401)

д: функция переходов конечного автомата представлена в таблице (табл. 1):

Таблица 1. Функция д

(S2, a..z, A..Z) >S2

(S3..S99, a..z, A..Z )>S200

(S3..S99,пунктуация )>S0

(S3..S99,операторы )>S300

(S, c )> S3

(S3, o)> S34

(S20, a)> S21

(S41, a)> S42

(S0, b)> S6

(S3, i)> S43

(S21, t)> S1

(S42, i)> S43

(S0, e)> S11

(S3, a)> S69

(S22, t)> S23

(S43, n)> S1

(S0, i)> S16

(S4, a)> S5

(S22, w)> S64

(S47, e)> S48

(S0, f)> S18

(S5, r)> S1

(S22, y)> S36

(S47, a)> S49

(S0, s)> S22

(S6, o)> S7

(S23, r)> S24

(S48, w)> S1

(S0, v)> S31

(S7, o)> S7

(S24, i)> S25

(S49, m)> S50

(S0, m)> S41

(S7, l)> S1

(S25, n)> S26

(S49, m)> S50

(S0, d)> S56

(S6, r)> S8

(S26, g)> S1

(S50, e)> S51

(S0, r)> S61

(S8, e)> S9

(S27, l)> S28

(S51, s)> S52

(S0, n)> 47

(S9, a)> S10

(S28, u)> S29

(S52, p)> S53

(S0, a..z, A..Z)>S2

(S10, k)> S1

(S29, d)> S30

(S53, a)> S54

(S0,0..9)> S100

(S11, n)> S12

(S29, d)> S1

(S54, c)> S55

(S0, “(“ )> S400

(S12, d)> S13

(S30, e)> S1

(S55, e)> S1

(S0, “)” )> S400

(S13, l)> S1

(S31, o)> S32

(S56, o)> S57

(S0, { )> S400

(S11, l)> S14

(S32, i)> S33

(S57, u)> S58

(S0, })> S400

(S14, s)> S15

(S33, d)> S1

(S58, b)> S59

(S0, [ )> S400

(S15, e)> S1

(S34, u)> S35

(S59, l)> S60

(S0, ])> S400

(S16, n)> S17

(S35, t)> S1

(S60, e)> S1

(S0, ;)> S400

(S17, t)> S1

(S36, s)> S37

(S61, a)> S62

(S0,”:”)>S400

(S17, c)> S27

(S37, t)> S38

(S62, n)> S63

(S0,”,”)> S400

(S18, l)> S19

(S38, e)> S39

(S63, d)> S1

(S0, “.”)> S400

(S18, o)> S40

(S39, m)> S1

(S64, i)> S65

(S3,v)> S4

(S19, o)> S20

(S40, r)> S1

(S65, t)> S66

(S300, *=)>S301

(S0, !)> S300

(S0, <)> S300

(S66, c)> S67

(S300, >>)> S301

(S0, &)> S300

(S0, +) > S300

(S300, <<)> S301

(S0, >)> S300

(S0, -)> S300

(S300, ++)> S301

(S0, 0..9)> S100

(S0, *)> S300

(S300, --)> S301

(S100, 0..9)> S100

(S0, =)> S300

(S300, +=)> S301

(S100, “.”)> S101

(S0, /)> S300

(S300, -=)> S301

(S101, 0..9)> S101

(S1, /)> S300

2.3 Построение регулярной грамматики по конечному автомату

Грамматика - это способ описания, задания языка. Это система правил, описывающая множество последовательностей символов некоего алфавита. Регулярная грамматика (РГ) эквивалентна конечным автоматам, поэтому по конечному автомату можно получить регулярную грамматику. Алгоритм преобразования:

По конечному автомату A = (X, S, F, S0, д) можно построить регулярную грамматику G = < N, T, P, S >, где:

T = X - конечное непустое множество терминальных символов.

N = S - конечное непустое множество нетерминальных символов

S - стартовый символ грамматики;

P - конечное множество правил грамматики - продукции.

Множество правил подстановки Р строится таким образом: каждой команде автомата (Si, a) > Sj ставится в соответствие правило подстановки Si > а Sj, если Sj ? S, либо Si > а , если Sj ? F, где F- заключительное состояние.

Построение регулярной грамматики по описанному конечному автомату:

По приведённому выше конечному автомату была сформирована следующая регулярная грамматика:

G = (N, T, S, P)

T: ( 0..9, a..z, A..Z, +, -, *, /, %, =, !, ++,--,+=,-=,*=, << , >>,>, <,<=,>=,==,!=,||,&&,;, (, ), [, ], {, }, “.”, “,”, “)

N:

S0 - начало считывания лексемы

S3…S99 - посимвольное считывание ключевого слова

S400, S401 - пунктуация

S3…S45 - cin

S3…S35 - cout

S3…S5 - char

S3…S68 - case

S6…S10 - break

S6…S8 - bool

S11…S15 - else

S11…S13 - endl

S18…S21 - float

S18…S40 - for

S56…S60 -double

S16…S31 - include

S16…S17 - int

S47…S48 - new

S47…S55 - namespace

S22…S39 - system

S22…S26 - string

S22…S67 - switch

S31…S33 -void

S41…S43 -main

S61…S63 - rand

S1 -проверка ключевых слов на правильность написания, добавление их в таблицу

S200 -проверка написания идентификатора и добавление его в таблицу

S300 - начало распознавания лексемы оператора

S300 - начало распознавания лексемы оператора “+,-,=,*,&,/,<,>,!”, добавление лексемы в таблицу

S301 - распознавания лексемы оператора, добавление лексемы в таблицу

“++,--,+=,-=,*=, <=,>=,==,!=,||,&&”

S302 - ошибка в написании оператора

S100 - распознавание лексемы целочисленной константы, запись её в таблицу. Ошибки в написании лексемы

S101 - распознавание лексемы константы с плавающей запятой, запись её в таблицу. Ошибки в написании лексемы

S:S0

P: Множество продукций представлено в таблице (табл. 2).

Таблица 2. Множество продукций

S0> c

S300> +=

S13> l S1

S36> s

S0> b

S300> -=

S11> l

S37> t

S0> e

S0>! S300

S14> s

S38> e

S0> i

S0> & S300

S15> e S1

S39> m

S0> f

S0> > S300

S16> n

S40> r S1

S0> s

S0> 0..9

S17> t S1

S41> a

S0> v

S100> 0..9

S17> c

S42> i

S0> m

S100>. S101

S18> l

S43> n S1

S0> d

S101> 0..9 S101

S18> o

S47> e

S0> r

S0> + S301

S19> o

S47> a

S0> n

S0> - S301

S20> a

S48> w S1

S0>(a..z, A..Z)

S0> * S300

S21> t S1

S49> m

S0> (0..9)

S0> = S300

S22> t

S50> e

S0>( S400

S0> /S300

S22> w

S51> s

S0>) S400

S3> o

S22> y

S52> p

S0>{ S400

S3> v

S23> r

S53> a

S0>} S400

S3> i

S24> i

S54> c

S0>[ S400

S3> a

S25> n

S55> e S1

S0>] S400

S4> a

S26> g S1

S56> o

S0>; S400

S5>r S1

S27> l

S57> u

S0>: S400

S6> o

S28> u

S58> b

S0>, S400

S7> o

S29> d

S59> l

S0>. S400

S7> l S1

S29> d S1

S60> e S1

S0> < S300

S7> r

S30> у S1

S61> a

S300>*=

S8> e

S31> o

S62> n

S300> -=

S9> a

S32> i

S63> d S1

S300> +=

S10> k S1

S33> d S1

S64> i

S300> ++ S301

S11> n S12

S34> u S35

S65> t

S300> -- S301

S12> d S13

S35> е S1

S66> c

S0> > S300

S0> & S300

S0> * S300

S0> ! S300

Таблица 3. Совмещенная таблица продукций и переходов

КА

РГ

КА

РГ

(S0, c )> S3

S0> c S3

(S13, l)> S1

S13> l S1

(S0, b)> S6

S0> b S6

(S11, l)> S14

S11> l S14

(S0, e)> S11

S0> e S11

(S14, s)> S15

S14> s S15

(S0, i)> S16

S0> i S16

(S15, e)> S1

S15> e S1

(S0, f)> S18

S0> f S18

(S16, n)> S17

S16> n S17

(S0, s)> S22

S0> s S22

(S17, t)> S1

S17> t S1

(S0, v)> S31

S0> v S31

(S17, c)> S27

S17> c S27

(S0, m)> S41

S0> m S41

(S18, l)> S19

S18> l S19

(S0, d)> S56

S0> d S56

(S18, o)> S40

S18> o S40

(S0, r)> S61

S0> r S61

(S19, o)> S20

S19> o S20

(S0, n)> S47

S0> n S47

(S20, a)> S21

S20> a S21

(S0,a..z,A..Z)>S2

S0>(a..z,A..ZS2

(S21, t)> S1

S21> t S1

(S0,0..9)> S100

S0> (0..9) S100

(S22, t)> S23

S22> t S23

(S0, “(“ )> S400

S0>(

(S22, w)> S64

S22> w S64

(S0, “)” )> S400

S0>)

(S22, y)> S36

S22> y S36

(S0, { )> S400

S0>{

(S23, r)> S24

S23> r S24

(S0, })> S400

S0>}

(S24, i)> S25

S24> i S25

(S0, [ )> S400

S0>[

(S25, n)> S26

S25> n S26

(S0, ])> S400

S0>]

(S26, g)> S1

S26> g S1

(S0, ;)> S400

S0>;

(S27, l)> S28

S27> l S28

(S0,”:”)>S400

S0>:

(S28, u)> S29

S28> u S29

(S0,”,”)> S400

S0>,

(S29, d)> S30

S29> d S30

(S0, “.”)> S400

S0>.

(S29, d)> S1

S29> d S1

(S0, <)> S300

S0> < S300

(S30, e)> S1

S30> у S1

(S300, *=)> S301

S300>*=

(S31, o)> S32

S31> o S32

(S300, -=)> S301

S300> -=

(S32, i)> S33

S32> i S33

(S300, +=)> S301

S300> +=

(S33, d)> S1

S33> d S1

(S300, ++)> S301

S300> ++

(S34, u)> S35

S34> г S35

(S300, --)> S301

S300> --

(S35, t)> S1

S35> е S1

(S300, +=)> S301

S300> +=

(S36, s)> S37

S36> s S37

(S300, -=)> S301

S300> -=

(S37, t)> S38

S37> t S38

(S0, !)> S300

S0>! S300

(S38, e)> S39

S38> e S39

(S0, &)> S300

S0> & S300

(S39, m)> S1

S39> m S1

(S0, >)> S300

S0> > S300

(S40, r)> S1

S40> r S1

(S0, 0..9)> S100

S0> 0..9

(S41, a)> S42

S41> a S42

(S100, 0..9)> S100

S100> 0..9

(S42, i)> S43

S42> i S43

(S100, “.”)> S101

S100>. S101

(S43, n)> S1

S43> n S1

(S101,0..9)> S101

S101> 0..9

S101

(S47, e)> S48

S47> e S48

(S0, +) > S300

S0> + S300

(S47, a)> S49

S47> a S49

(S0, -)> S300

S0> - S300

(S48, w)> S1

S48> w S1

(S0, *)> S300

S0> * S300

(S49, m)> S50

S49> m S50

(S0, =)> S300

S0> = S300

(S50, e)> S51

S50> e S51

(S0, /)> S300

S0> /S300

(S51, s)> S52

S51> s S52

(S0, > )> S300

S0> > S300

(S0, ! )> S300

S0> ! S300

(S0, & )> S300

S0> & S300

(S0, < )> S300

S0> < S300

(S3, o)> S34

S3> o S34

(S52, p)> S53

S52> p S53

(S3,v)> S4

S3> v S4

(S53, a)> S54

S53> a S54

(S3, i)> S43

S3> i S43

(S54, c)> S55

S54> c S55

(S3, a)> S69

S3> a S69

(S55, e)> S1

S55> e S1

(S4, a)> S5

S4> a S5

(S56, o)> S57

S56> o S57

(S5, r)> S1

S5>r S1

(S57, u)> S58

S57> u S58

(S6, o)> S7

S6> o S7

(S58, b)> S59

S58> b S59

(S7, o)> S7

S7> o S7

(S59, l)> S60

S59> l S60

(S7, l)> S1

S7> l S1

(S60, e)> S1

S60> e S1

(S6, r)> S8

S7> r S8

(S61, a)> S62

S61> a S62

(S8, e)> S9

S8> e S9

(S62, n)> S63

S62> n S63

(S9, a)> S10

S9> a S10

(S63, d)> S1

S63> d S1

(S10, k)> S1

S10> k S1

(S64, i)> S65

S64> i S65

(S11, n)> S12

S11> n S12

(S65, t)> S66

S65> t S66

(S12, d)> S13

S12> d S13

(S66, c)> S67

S66> c S67

3. Построение лексического анализатора

3.1 Определение лексического анализатора

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

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

* применение лексического анализатора упрощает работу с текстом исходной программы на этапе синтаксического разбора и сокращает объем обрабатываемой информации;

* для выделения и разбора лексем применяется простая и эффективная техника анализа, в то время как на этапе синтаксического анализа используются достаточно сложные алгоритмы разбора;

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

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

Таким образом, можно выделить следующие основные функции лексического анализатора:

• исключение из текста исходной программы комментариев;

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

• выделение лексем следующих типов: идентификаторов, строковых, символьных и числовых, констант, ключевых (служебных) слов входного языка, знаков операций и разделителей;

• выявление ошибок в написании лексем, сообщение об ошибках (с указанием позиции и типа ошибки).

3.2 Моделирование работы лексического анализатора

На вход, в текстовую область, подаётся входная последовательность - обрабатываемый код. Анализатор должен удалить из кода все комментарии - как однострочные, так и многострочные. Также анализатор должен исключить из текста программы незначащие пробелы, символы-табуляции и пустые строки (рис. 1). Параллельно с этим производится выделение лексем с последующим распределением по таблицам соответствующих классов.

Источник: https://otherreferats.allbest.ru/download/1282040/