Перемноження матриць

1 / 157

# Перемноження матриць - PowerPoint PPT Presentation

Перемноження матриць. #include &quot;stdafx.h&quot; using namespace System; using namespace System::IO; int main(array&lt;System::String ^&gt; ^args) { String^s; int n,m; Console::WriteLine(&quot;Enter n=&quot;); s=Console::ReadLine(); n=Convert::ToInt32(s); Console::WriteLine(&quot;Enter m=&quot;);

I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.

## PowerPoint Slideshow about ' Перемноження матриць' - francis-floyd

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.

- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
Перемноження матриць

#include "stdafx.h"

using namespace System;

using namespace System::IO;

int main(array<System::String ^> ^args)

{

String^s;

int n,m;

Console::WriteLine("Enter n=");

n=Convert::ToInt32(s);

Console::WriteLine("Enter m=");

m=Convert::ToInt32(s);

array<double,2>^x=gcnew array<double,2>(n,m);

array<double,2>^y=gcnew array<double,2>(m,n);

array<double,2>^c=gcnew array<double,2>(n,n);

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

for(int j=0;j<m;j++)

{

x[i,j]=Convert::ToDouble(s);

Console::WriteLine("x={0}",x[i,j]);

}

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

for(int j=0;j<n;j++)

{

y[i,j]=Convert::ToDouble(s);

Console::WriteLine("y={0}",y[i,j]);

}

//sr->Close();

StreamWriter^sw=gcnew StreamWriter("D:\\AVRPROG\\VISUAL\\TestFile21.txt");

sw->AutoFlush::set(true);

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

for(int j=0;j<n;j++)

{

c[i,j]=0;

for(int k=0;k<m;k++)

c[i,j]+=x[i,k]*y[k,j];

Console::WriteLine("c={0}",c[i,j]);

if(j%n==0)

sw->Write("\n");

sw->Write(" c[{0},{1}]={2} ",i,j,c[i,j]);

}

Console::WriteLine(L"Finish");

return 0;

}

TestFile20
• 1
• 2,5
• 3
• 4
• 5
• 6,7
• 8
• 10
• 20
• 30
• 40
• 50
• 60
• 70
• 80

### Елементи компіляції

Аналіз формальних мов

Відомості про регулярні вирази та граматики
• Алфавіт – конечна множина I елементів, які наз. СИМВОЛАМИ.
• Ланцюжок (слово)- конечна послідовність символів із алфавіту I.
• Мова в алфавіті I – довільна множина ланцюжків (слів).
Дії над ланцюжками

xn- ланцюжокxповторюється n раз.

xR - ланцюжок xпишеться в зворотномунапрямку.

XY – за ланцюжком X розміщується Y.

X* - ланцюжок xповторюється в циклі НУЛЬ і більше раз.

X+- ланцюжок xповторюється в циклі ОДИН і більше раз.

| X | - довжина ланцюжка.

{ } або έабоe– пустий ланцюжок.

[X] необов’язковий ланцюжок.

Регулярні вирази і граматика
• Нехай три символи { , * | }не входять до заданого алфавіту символів I.

Ланцюжок із об’єднанняI U { , * | } наз. регулярним виразом.

Граматика G=( T, N, P, S)

T, N - алфавіти термінальних і нетермінальних символів.

P - множина правил для отримання нетермінальних символів через термінальні та інші нетермінальні символи.

S - стартовий або головний нетермінальний символ.

intx, y, z;

DVARB - >intl iden ( ‘ , ’ iden) * ’;’

PROG->(DVARB | DCONST| DFUNC) *eof

G=(T, N, P, S)

T={x, y, w, z}

N={ S, A, B }

P={A->AB, A ->x, A ->y, B->w, B->z}

L(G)={xw, yw, xz, yz}

Розширені граматики

A i - > r i, де A iналежать до N

r i – регулярні вирази із T U N.

A1 – головний.

S - >AB

A - >x|y

B - > w|z

T = { вино, пиво, каша, борщ, м’ясо, чай, кофе}

N = {ОБІД, АЛКОГОЛЬ, ЇЖА, ПИТНЕ}

ОБІД - > АЛКОГОЛЬ* ЇЖА ПИТНЕ

АЛКОГОЛЬ - >вино| пиво

ЇЖА- >борщ м’ясо| каша

ПИТНЕ - >чай |кофе

Задачі аналізу

Дано слово і граматика. Перевірити, що слово належить до мови, яка описана цією граматикою. Приклад:

Дано слово [ [ x ] ]

G=(T,N,P,S

T={ [ , ], x, +} N={A,B}

P={A->x, A->[B], B->A, B->B+A}

LA(1) – аналіз. Стратегії зверху – вниз і знизу – вверх.

A ═> [B] ═> [A] ═> [[B]] ═> [[A]] ═> [[x]]

Синтаксичні діаграми

Орієнтований граф з двома вершинами: вхідною і вихідною.

• 2) При розгалуженні дуги повинні починатися не з однакових термінальних символів.
• Проходженню дуги, поміченої термінальним символом, відповідає розпізнавання цього символу у вхідному ланцюжку і зсув на наступний символ, якщо розпізнавання відбулося. Інакше – повідомлення про помилку.
Проходженню дуги, поміченої нетермінальним символом, наприклад А, відповідає виклик відповідної функції розпізнавання ланцюжків, які виводяться з нього. Перед викликом цієї функції потрібно, щоб був прочитаний ПЕРШИЙ ТЕРМІНАЛЬНИЙ символ X, який виводять із А.
• Функція успішно аналізує ланцюжок W, якщо у відповідності до синтаксичної діаграми відбувається попадання із вхідної вершини у вихідну при прочитанні символу за символом усього ланцюжка.
Введення в компіляцію
• Транслятор – програма, яка перекладаєпрограму із вхідної мови (алгоритмічної) на еквівалентну їй об’єктну програму.
• Якщо вхідна мова високого рівня, а вихідною є машинна мова або асемблер, то такий транслятор наз. компілятором.
• Інтерпретатор– різновидність транслятора, який перекладає на мову простих проміжних команд і виконує її.
• Препроцесор перекладає із однієї мови високого рівня на іншу. Застосовується як частина компілятора.
ЛА – лексичний аналізатор. Об’єднує символи в лексеми:
• Ключові і службові слова;
• Ідентифікатори;
• Знаки операцій;
• Знаки пунктуації;
• Числа;
• Признак кінця файлу.
СА – синтаксичний аналізатор. Будує із лексем синтаксичні структури, які можуть бути складовими інших структур (константи, змінні, вирази, функції і т. п.).
• ГПК – генерація проміжного коду.
• ОК – оптимізація коду.
• ГК – генерація коду.
Мова SPL

Символи:

1) Букви: A ÷ Z, a ÷ z

2) 0 ÷ 9

3) + - * / % ( ) , ; = \n \t

Ідентифікатор – букви або букви і цифри, але першою повинна бути буква. До 40 символів.

\n , \t та пропуски не можна вживати в ідентифікаторах.

Константи – тільки цілічисла.

Змінні тільки цілого типу: глобальні і локальні.

Службові слова:begin, end, read, print, return, if, then,do, while, int, const – 11 слів.

Функції:

Ім’я (формальні параметри)

begin

локальні змінні і константи

Оператори

end

Описання констант:
• const a=12, b=4, d=- 5, s=0;
• Описання змінних:
• int x, y, z, teta ;
• Оператори закінчуються крапкою з комою. Перед end крапку з комою не ставити.
• Одна із функцій повинна бути main()
• Дані в функцію передаються лише по значенню.
• Результат повертається або через return або через глобальні змінні.
• Допускаються рекурсії.
Конструкцияif

ifвиразthenпослідовністьоператорів

end;

оператор_1;

Якщо результат обчислення виразу більше нуля, то виконується послідовність операторів за ключовим словомthen, якщо менше або дорівнює нулю ( ≤ ), то ця послідовність пропускається, і відбувається перехід до наступного за if оператора...

Конструкцияwhile

whileвиразdoпослідовність_операторів

end;

опер1;

...

Якщо результат обчислення виразу більше нуля, то виконується послідовність операторів за ключовим словом do,після чого знову обчислюється вираз. Якщо результат менше або дорівнює нулю ( ≤ ), то ця послідовність пропускається, і відбувається вихід із циклу.

Програма лексичного аналізу

Прочитати текст програми на SPL, розпізнати лексеми і занести ідентифікатори в таблицю ідентифікаторівchar TNM[400];

Ідентифікатори та їхні адреси занести в файл.

В програмі кожній лексемі відповідає ціле число. Для символів це код із таблиці ASCII. Для ключових слів цілі числа задаються за допомогою перераховуваних констант( enum).
• enum {BEGINL=257, ENDL, READL, PRITL, RETRL, IFL, THENL, WHILEL, DOL, CONSTL, INTL, IDEN, NUMB};
• Признак кінця файлу в stdio.h
• #define EOF -1
Програма лексичного аналізу

#include<stdio.h>

#include<stdlib.h>

#include<ctype.h>

#include<conio.h>

#include<alloc.h>

#include<string.h>

/*Кодилексем ключових слів мови SPL*/

enum { BEGINL=257, ENDL, IFL, THENL,

PRITL, INTL, CONSTL, IDEN, NUMB };

int nst=0; //номер рядка в тексті на SPL

int lex;// лексема (ціле число)

int lval; //значення лексеми (для констант це число, а для ідентифікаторів – їхніадреси в таблиціchar TNM[400])

char nch=\'\n\'; // символ, який читається із тексту програми на SPL

FILE*PF,*padres;//файл із текстом програми на SPL і файл для результатів

void get(void);

void number(void);

void word(void);

void main( int ac,char*av[ ] )

{

clrscr( );

if(!ac)

{

puts(“Немає файлу із програмою");

exit(1);

}

PF=fopen(av[1],"r");

if(!PF)

puts("Файл не відкривається");

else

get( );// Виклик функції для отримання лексеми

}

void get()

{

while(nch!=EOF)

{

while(isspace(nch))

{

if( nch= = \'\n‘ )

nst++;

nch = getc(PF);

}

If ( isdigit ( nch ) )

number( );

else

if( isalpha ( nch ) )

word();

else

if(nch= =\'(‘ || nch= =\')‘ || nch= =\',‘ || nch= = \';‘ ||nch== ‘=\'

||nch= =\'+‘ ||nch= =\'-‘ ||nch= =\'*‘ || nch==\'/‘ || nch= =‘%‘)

{

lex=nch;

nch=getc(PF);

}

}

if(nch= =EOF)

lex=EOF;

else

puts("Hедопустимийсимвол");

return;

}

void number()

{

for( lval=0; isdigit( nch ); nch= getc(PF))

lval=lval*10+nch - \'0\';

lex= NUMB;

return;

}

void word( )

{

int cdl [ ]={BEGINL,ENDL,IFL,THENL,WHILEL,DOL,

char*serv [ ]={"begin", "end", "if", "then“, "while",

“do", "return", “read", "print", "int", "const“ };

int i;

char tx[40];

char*p;

for(p=tx; isdigit(nch) || isalpha(nch); nch=getc(PF))

*( p++ ) = nch;

*p=\'\0\';

for( i=0; i<11; i++)

if( strcmp ( tx, serv [ i ] ) == 0)

{

lex=cdl [ i ];

return;

}

lex=IDEN;

lval= (int) add ( tx );

printf("Адреса для %s =%p\n",tx,lval);

return;

}

char TNM[400];//таблиця ідентифікаторів char*ptn=TNM; //покажчик на перший вільний елемент в таблиці TNM[400 ]

//*******************************************

{

char*p;

for(p=TNM;p<ptn;p+=strlen(p)+1)

if(strcmp(p,nm)==0)

return p;

if((ptn+=strlen(nm)+1)>TNM+400)

{

puts("Переповнення таблиці ідентифікаторів");

exit( 1 );

}

return ( strcpy ( p, nm ) );

}

Повний синтаксис мови SPL
• Алфавіт термінальних символів – лексеми.
• Нетермінальні символи:
• PROG, DFUNC, DCONST, DVARB, CONS, PARAM, BODY, STML, STAT, EXPR, TERM, FACT, FCTL.
Регулярні вирази

PROG - >(DCONST |DVARB| DFUNC )*  eof

DCONST -> constl  CONS (‘,’ CONS) *  ‘;’

CONS - >iden ‘=’ [‘+’ | ’-’] numb

DVARB -> intl  iden (‘,’ iden)* ’;’

DFUNC -> iden  PARAM  BODY

PARAM -> ’(‘  [ iden (‘,’ iden)* ]  ‘)’

BODY->beginl (DVARB| DCONST)* STML endl

STML - > STAT (‘;’ STAT)*

STAT- >iden ‘=’ EXPR |

pritl EXPR |

retrl EXPR |

ifl EXPR thenl STML endl |whilel EXPR dol STML endl

//*************************************************

EXPR- >[‘+’ | ‘-’] TERM ((‘+’ | ‘-’) TERM)*

TERM - > FACT((‘*’|’/’|’%’) FACT)*

FACT- > ’(’ EXPR ‘)’ | numb | iden [‘(’ [FCTL] ’)’]

FCTL - > EXPR (‘,’EXPR)*

Синтаксичні діаграми і функції

розпізнавання ланцюжків для

нетермінальнихсимволів

void exam (int lx)

{

if (lex!=lx)

{

printf (“Не співпадають лексеми

lex=%i та lx=%i в nst=%i \n”, lex, lx, nst );

exit (1);

}

get ( );

return;

}

Замість while (nch!=EOF)

{ …

} в програмі тільки лексичного аналізу

Тепер треба запрограмувати

if (nch = = EOF)

{

lex = EOF;

return;

}

Нетермінальний символ PROG

PROG - > (DCONST  |DVARB |  DFUNC )*  eof

void prog( )

{

while (lex!=EOF)

{

switch (lex)

{

case IDEN: dfunc( ); break;

case INTL: dvarb( ); break;

case CONSTL: dconst( ); break;

default:

printf(“Помилка в nst=%i лексема lex=%i \n”, nst, lex);

}

}

return;

}

void dconst( )

{

// Немає “свіжої” лексеми

// потрібно викликати get( );

do

{

get( );

cons( );

} while (lex = = ‘,’);

exam (‘;’);

return;

}

//“Свіжа” лексема є

void cons( )

{

exam (IDEN);

exam (‘=’);

if (lex = = ‘+’ || lex = = ‘-‘)

get( );

exam (NUMB);

return;

}

Треба спочатку прочитати лексему

void dvarb( )

{

do

{

get( );

exam(IDEN);

} while(lex = = ‘,’);

exam(‘;’);

return;

}

Треба спочатку прочитати лексему

void dfunc( )

{

get( );

param( );

body( );

return;

}

void param( )

{

exam (‘(‘);

if (lex ! = ’)’ )

{

exam (IDEN);

while (lex = = ’,’)

{

get( );

exam (IDEN);

}

}

exam (‘)’);

return;

}

void body( )

{

exam (BEGINL);

while(lex = = INTL || lex = = CONSTL)

if (lex = = INTL) dvarb( );

else

dconst( );

stml( );

exam(ENDL);

return;

}

void stml( )

{

stat( );

while (lex = = ‘;’)

{

get( );

stat( );

}

return;

}

STAT -> iden ‘=’EXPR |

pritl EXPR |

retrl EXPR |

iflEXPR thenl STML endl |

whilel EXPR dol STML endl

void stat( )

{

switch (lex)

{

case IDEN: get( ); exam (‘=’); expr( ); break;

case READL: get( ); exam (IDEN); break;

case PRITL: get( ); expr( ); break;

case RETRL: get( ); expr( ); break;

case IFL: get( ); expr( ); exam(THENL); stml( ); exam(ENDL); break;

case WHILEL: get( ); expr( ); exam(DOL); stml( ); exam(ENDL); break;

default:

printf(“Синтакс. помилка в stat в nst=%i \n”, nst);

}

return;

}

EXPR - > [‘+’ | ‘-’]TERM ((‘+’ | ‘-’) TERM)*

void expr( )

{

if (lex = = ‘+’ || lex = = ‘-‘)

get( );

term( );

while (lex = = ‘+’ || lex = = ‘-‘)

{

get( );

term( );

}

return;

}

void term()

{

fact();

while(lex==\'*\'|| lex == \'/\'||lex==\'%\')

{

get();

fact();

}

return;

}

FACT - >(’EXPR ‘)’ | numb | iden [‘(’ [FCTL] ’)’]

void fact( )

{

switch(lex)

{

case \'(\': get(); expr(); exam(\')\'); break;

case IDEN: get(); if ( lex==\'(‘ )

{

get();

if ( lex != \')‘ ) fctl( );

exam ( \')‘ );

}

break;

case NUMB: get ( ); break;

default: puts(“Помилка в FACT");

}

return; }

void fctl()

{

expr();

while(lex==\',\')

{

get();

expr();

}

return;

}

Інтерпретація

SPL – програма це послідовність проміжних команд, які послідовно заносяться в таблицю команд.

typedef struct

{

int cod; // кодкоманди ( що робити)

int opd; //операнд ( із чим щось робити )

} cmd;

cmd TCD[300]; // таблиця команд

int tc=0; // лічильник команд

Стекова пам’ятьint st [ 500 ]

1) st[0], st[1],…..st[n] – глобальні змінні. Їхня кількість автоматично заноситься в глобальну змінну

int cgv = 0;

2)Далі - фактичні параметри ф-ції main().

3) Кількість фактичних параметрів

ф-ції main().

4)Адреса повернення (АПОВ) (для main() це число -2 )

5) Адреса активації (ААК)

( для main() це число -1 )

6) Локальні змінні для main().

1)Далі - фактичні параметри ф-ції, наприклад, p0().

2) Кількість фактичних параметрів

ф-ції p0().

3)Адреса повернення для p0().

4) Адреса активації (ААК) дляp0().

ААК в програмі має ідентифікаторsp.

5) Вище від sp розміщуються локальні змінні для p0().

Вершина стеку має ідентифікаторt

Зсув в стеку для глобальних змінних

k= 0,1,2,…cgv.Адреса st[k].

Адреси в стеку для фактичних і локальних параметрів st[sp+k].

Для локальних k=1,2,3,…clv.

Для глобальних k=- ( n+2 ),….-3

n – кількість фактичних параметрів.

f ( x , y , z )

begin

int a,b;

.……….

………..

end

st[sp-5] – дляx

st[sp-4] – дляy

st[sp-3] – дляz

st[sp+1] – дляa

st[sp+2] – дляb

Робота із таблицями

1) char TNM [ 400] - табл. ідентифікаторів

2) cmd TCD [300] - табл. команд.

3) typedef struct

{

char * name;//ім’я об’єкта

int what;//1- const, 2- глоб. 3- локал.

int val; //знач. для const або зміщенняk

} odc;

odc TOB[100]; // таблиця об’єктів

odc*pto =TOB; odc*ptol=TOB;//покажчики на перший вільний елемент в таблиці для глоб. i локальних змінних

int out=1; // out =1 – глоб. out=0 – локальна.

4)typedef struct

{

char* name;//ім’я функції

int isd;// описана (1) чи ні (0)

int cpt;//кількість параметрів

int start;//точка входу в табл. команд

}fnd;

fnd TFN[30];//таблиця функцій

fnd* ptf =TFN;// покажчик на перший вільний елемент в TFN[ ].

Команди SPL
• enum { OPR, LIT, LDE, LDI, STE, STI, CAL, INI, JMP, JMC };
• OPR 1 – число із stdinзаноситься в вершину стека;
• OPR 2 – число із вершини стека - в stdoutдля виведення на екран;

OPR 3,4,5,6,7 – операції +, -, *, /, %

Перший операнд в t-1, а другий в t . Результат - в t .

OPR 8 – зміна знака у числа в вершині стеку;
• OPR 9 – повернення результату , який знаходиться в вершині стеку, в викликаючу функцію( return);
• OPR 10 – зупинка програми.
• LIT a – занесення const aв вершину стека t (load into t);
• LDE a – занесення в tглобальної змінної із зміщенням a в стеку(load exetrnal to st[a]) ;
LDI a - занесення в tлокальної змінної із зміщенням a в стеку(load internal to st [sp + a]) ;
• STE a – число із вершини стеку присвоюється глобальній змінній, розміщеній в стеку із зміщенням a (set external to st [a]);
• STI a – число із вершини стеку присвоюється локальній змінній, розміщеній в стеку із зміщенням a (set internal to st [sp + a] );
CAL a – виклик функції із точкою входу aв таблиці команд cmdTCD[300];

INI a – виділення пам’яті (збільшення адреси вершини стека на а елементів);

JMP a – безумовна передача управління на команду номер а в таблиці команд;

JMC a – умовна передача управлінняна команду номер а в таблиці команд, якщо число в вершині стеку

t≤ 0. Число в tзникає!

Створення SPL- програми
• Вирази переводяться в зворотній польський вид, коли a+bвиглядає як
• <a><b>+
• Для занесення в стек використана функція void push(int a)
• Для занесення команди в таблицю команд використана функція
• int gen(int co,int op)

Функція занесення в стек

void push(int a)

{

If ( t >= 499 )

{

puts("Переповнення стеку st");

exit(0);

}

st[+ + t ] = a;

return;

}

Функція занесення команд в таблицю команд cmd TCD[300]

int gen(int co,int op)

{

if( tc >= 300)

{

puts("Переповнення TCD");

exit(1);

}

TCD[tc].cod=co;

TCD[tc].opd=op;

return tc++;//звернути увагу на ++

}

1) Занесення константи val:

{ LIT val } – команда SPL;

gen(LIT, val); - функція занесення цієї команди в таблицю командTCD[300];

push ( val ); - функція в програмі інтерпретатора, яка виконує цю команду.

2) { LDE a }

gen ( LDE a );

push ( st [ a ] ); – глобальна змінна по адресі st [a] заноситься в вершину стека.

3) { LDI a }

gen ( LDI,a );

push ( st [ sp+a] ); – локальна змінна по адресі st [ sp+a]заноситься в вершину стека t.

4) read e; - оператор мовою SPL

{ OPR 1} { STE a} –прочитана глобальна змінна;

{ OPR 1} { STI a} – прочитана локальна змінна.

5) print e;оператор мовою SPL

<e> { OPR 2} виведення на екран

6) return e;

<e> { OPR 9}

7) e = - e;

<e> { OPR 8}

8) e1 op e2

<e1 ><e2> { OPRop}, де op= 3, 4, 5, 6, 7

відповідно для + - * / %.

9) Виклик функціїf (e1 , e2 , ….. en ) , ізточкою входу а в таблиці команд TCD

<e1><e2>….<en> { LIT n } { CAL a}

10) Описання функції з точкою входу а

F ( p1, p2 , ….. pm )

begin

Локальні змінні і константи

Оператори S

end

a : { INI m} < S > { OPR 10}

if e then s end

< e > { JMC k } <s> k , де k - перша команда після послідовності операторів s.

12) while e do s end

lb : <e> { JMC k} <s> {JMP lb} k

main ( x, y )

begin

int c;

c = x – y / c ;

if c then return c

end

Заповнення таблиці команд
• Заповнення відбувається розширеними функціями:

body(); stat(); expr(); term(); fact();

• Використовуються глобальні змінні:

int cgv=0;//кількість глобальних змін.

int clv=0;//кількість локальних змінних

int tc=0;//лічильник занесених команд в таблицю команд.

int out=1;//признак глобальна (1) чи локальна (0) змінна

Функція занесення команд в таблицюкоманд cmd TCD[300]

int gen ( int co,int op)

{

if( tc >= 300)

{

puts("Переповнення TCD");

exit(1);

}

TCD[tc].cod=co;

TCD[tc].opd=op;

return tc++;

}

int body()

{

int st;//адреса точки входу в TCD[]

exam(BEGINL); clv=0;

while(lex==CONSTL || lex==INTL)

if( lex==CONSTL) dconst();

else dvarb(); // тут можезмінитисяclv

st=gen(INI,clv);

stml();

exam(ENDL);

gen(OPR,10);

return st;//повертає адресу точки входу

}

Пошук елемента даних nm в таблиці об’єктів TOB[ ]

odc*findob(char*nm)

{

odc*p;

for(p=pto-1;p>=TOB; p--)

if(strcmp(nm,p->name)==0)

return p;

printf("Не описано %s \n“, nm );

return p;

}

void stat ()

{

odc*p;

int t1, t2;

switch(lex)

{

case IFL: get(); expr(); exam(THENL); t1=gen(JMC,0);

stml(); exam(ENDL); TCD[t1].opd=tc; break;

case WHILEL: get(); t1=tc; expr( ); exam (DOL); t2=gen(JMC,0);stml();gen(JMP,t1);TCD[t2].opd=tc;exam(ENDL);break;

case RETRL:get();expr();gen(OPR,9);break; case PRITL:get();expr();gen(OPR,2);break;

case READL: get( ); p = findob ( (char*) lval ); gen(OPR,1);

if(p->what==1) puts("lval незмінна");

gen(p->what==2?STE:STI,p->val);

exam(IDEN);break;

case IDEN:p=findob((char*)lval);get();exam(\'=\');expr();

if(p->what==1) puts("p->name незмінна");

gen(p->what==2?STE:STI,p->val);

break;

default:

printf(«Помилкав stat()nst=%i lex=%i \n“, nst, lex);

}

return;}

void expr()

{

int neg=( lex== \'-‘ );

If ( lex==\'+‘ || lex==\'-‘ ) get();

term();

If ( neg ) gen(OPR,8);

while(lex==\'+‘ || lex==\'-\')

{

neg = lex == \'-‘ ? 4 : 3;

get();

term(); gen(OPR,neg);

}

return;

}

void term()

{

int op;

fact();

while( lex== \'*‘ || lex == \'/‘ || lex == \'%‘ )

{

op= lex==\'*\'? 5: lex== \'/’ ? 6: 7;

get();

fact();

gen(OPR,op);

}

return;

}

void fact()

{

char*nm; int cp; odc*p; fnd*pl;

switch(lex)

{

case IDEN: nm= (char*) lval; get();

if ( lex==\'(‘ )

{

get(); cp= ( lex==\')‘ ? 0: fctl ( ) ); exam( \')‘ );

pl=eval (nm, cp); gen (LIT, cp);

cp= gen (CAL, pl->start);

if( !pl-> isd ) pl->start=cp;

}

else

{

p= findob (nm);

gen (p->what==1?LIT: (p->what==2?LDE:LDI),

p->val);

}

break;

case \'(\': get (); expr (); exam ( \')‘ ); break;

case NUMB: gen( LIT, lval ); get (); break;

default:

printf(“ Errorinfact. nst=%i lex=%i\n“,nst,lex);

}

return;

}

int fctl()

{

int cf =1; // 1-й вираз

expr();

while(lex==\',\')

{

get();

expr();

cf++;

}

return cf; //повернення кількості виразів

}

Заповнення таблиці об’єктів

void newob (char*name, int wt, int vl );

name – ім’я об’єкта;

wt – признак: 1- const, 2- глоб. 3- локал.

vl - знач. для const або зміщення k для змінної.

Виклик із:cons(); dvarb(); param();

Викликається післяget() перед

exam(IDEN); exam(NUMB);

void newob(char*nm,int wt,int vl)

{

odc* pe, *p;

pe = out ? TOB: ptol;

for ( p = pto-1; p> =pe; p-- )

{

if(strcmp (nm, p->name )==0 )

{

puts("Описанадвічі"); exit(0);

}

}

if(pto>=TOB+100){puts("Переповнення TOB");exit(0);}

pto->name=nm;pto->what=wt;pto->val=vl;pto++; // Звернути увагу на ++

return;}

void cons()

{

char*nm= (char*)lval; int s;

exam(IDEN);

exam(\'=\');

s=( lex==\'-\') ? -1 : 1;

if( lex==\'+‘ || lex== \'-‘ )

get();

newob(nm,1,s*lval);puts("Занесенооб’єкт");

exam(NUMB);

return;

}

void dvarb()

{

do

{

get();

newob((char*)lval,(out?2:3), (out ? cgv++ : ++clv));

exam(IDEN);

}while(lex==\',\');

exam(\';\');

return;

}

void dfunc()

{

int cp,st;char*nm=(char*)lval;

get();

out=0;

cp=param ();

st=body();

out=1;

pto=ptol;

defin (nm, cp, st);

return;

}

int param(){

odc*p;int cp=0;

exam( \'(‘ );

if(lex!=‘)‘)

{

newob((char*)lval,3,++cp);

exam(IDEN);

while(lex==\',‘)

{

get();

newob((char*)lval,3,++cp);

exam(IDEN);

}}

exam(‘)‘);

for(p=ptol;p<pto;p++)

p->val- =cp+3;

return cp;

}

Від ptol, (відкіля почали заноситися фактичні параметри), до pto відбувається зсув зміщень на (cp+3) із врахуванням специфіки їхнього розміщення в стеку:

- (n+2) , …. -3, -2 , -1 , 0

st[ sp -2 ] - кількість параметрів;

st[ sp -1 ] - адреса повернення;

st[ sp] - ААК - адреса активації.

newfn()-занесення в TFN элемента

fnd*newfn(char*nm,int df,int cp,int ps)

{

if(ptf>=TFN+30)

{

puts("Переповнення TFN");

exit(0);

}

ptf->name=nm;ptf->start=ps;

ptf->isd=df;ptf->cpt=cp;

return ptf++;

}

/*findfn-пошукфункціїnmвтаблиці TFN*/

fnd*findfn(char*nm)

{

fnd*p;

for(p=ptf-1;p>=TFN;p--)

If(strcmp(p->name,nm)==0)

return p;

return NULL;

}

/*eval()-викликфункціїnmізcpаргументами*//*eval()-викликфункціїnmізcpаргументами*/

fnd*eval ( char*nm, int cp)

{

fnd*p;

if( !(p=findfn (nm))) return newfn(nm,0,cp,-1);

if(p->cpt==cp) return p;

printf("Кількість параметрів для %s не співпадає“, nm);exit(1);

return NULL;

}

/*defin()-описання функції nm; cp-параметри,

{

fnd*p;

int c1,c2;

p=findfn(nm);

if(p)

{

if(p->isd)

{

printf(”%s oписанадвічі\n”, nm);

exit(1);

}

if(p->cpt!=cp)

{

printf(« Не сходиться кількість парам. для %s \n“, nm);

exit(1);

}

p->isd=1;

for(c1=p->start; c1!=-1; c1=c2 )

{

с2=TCD[c1].opd;

}

} //відповідна для if (p)

return;

}

/*fmain()-пошук main и неописаних функцій*/

fnd*fmain()

{

static char nm[]="main“;

fnd*pm=NULL;

fnd*p;

for(p=ptf–1;p>=TFN;p--)

{

if( !p - > isd )

{

puts("Функція не описана p->name");

exit(0);

}

if(strcmp(nm,p->name)==0)pm=p;

}

if(pm) return pm;

puts("Немає main");

return}

void prog()

{

fnd*p;

while(lex!=EOF)

{

switch(lex)

{

case CONSTL:dconst();break;

case INTL:dvarb();break;

case IDEN:dfunc();break;

default:puts("Ошибкасинтаксиса");

}

}

p=fmain();

return;

}

red()

{

int v,c;

do

{

puts("Введітьчисло");

fflush(stdin);

c=getchar();

}while(isspace(c));

if(!Isdigit(c))

puts(«Помилка при введенні");

for(v=0;isdigit(c);c=getchar())

v=v*10+c-\'0\';

ungetc(c,stdin);

return v;

}

void interp()

{

int i;

t=-1;

printf("SPL:інтерпретація");

for(i=0;i<cgv;i++)

push(0);

if(cpnm)

{

printf("%d>",cpnm);

fflush(stdin);

for(i=0;i<cpnm;i++)

push(red( ));

}

push(cpnm);

push(-2);

push(-1);

sp=t;

do

{

comman();

p++;

} while (p>=0);

if( p== -1)

printf ("st [%d] = %d \n ", t, st[ t ] );

}

/*Виконання команди*/

comman()

{

int a=TCD[p].opd;

switch(TCD[p].cod)

{

case OPR:operat(a);break;

case LIT:push(a);break;

case LDE:push(st[a]);break;

case LDI:push(st[sp+a]);break;

case STE:st[a]=st[t--];break;

case STI:st[sp+a]=st[t--];break;

case CAL:push(p);push(sp);sp=t;p=a-1;break;

case INI:

{

int i;

for(i=0;i<a;i++)

push(0);

}

break;

case JMP:p=a-1;break;

case JMC:if(st[t--]<=0)p=a-1;

}

return;

}

/*operat-виконання операції a над вершиною стеку*/

void operat(int a)

{

int j=t-1;

switch(a)

{

case 1:printf("1>“);

fflush(stdout);

push(red( ) );break;

case 2: printf (“ %d \n ", st[ t - - ]); break;

case 3: st [ j ] + = st [ t - - ]; break;

case 4: st [ j ] - = st [ t - - ]; break;

case 5: st [ j ] * = st [ t - - ]; break;

case 6: if (st [t]==0)

puts(“ /: ділитель = 0“ );

st [ j ] / = st [ t - - ]; break;

case 7: if (st [ t ] <=0 )

puts("%%:ділитель =0");

st [ j ] % = st [ t - - ]; break;

case 8: st [ t ] = - st [ t ]; break;

case 9: j = st [sp-2]; st [sp- j - 2]= st[t];

t = sp- j- 2; p=st [sp - 1]; sp= st [ sp ]; break;

case 10:p=-3;

}

return;

}

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

Створити програму - інтерпретатор для модифікованої мови SPL, в якій добавлена операція піднесення в другу степінь

exp(a,b)

begin int z;

z=1;

while b do

if b%2 then z=z*a end;

a=a*a;b=b/2

end;

return z

end

main()

begin int x,y,z;

print exp(x,y);

z=x ^;

print z;

end

void get()

{

if(nch==EOF)

{

lex=EOF;

return;

}

while(isspace(nch))

{

if(nch==\'\n\')

nst++;

nch=getc(PF);

}

if(isdigit(nch))

number();

else

if(isalpha(nch))

word();

else

if(nch==\'(\'||nch==\')\'||nch==\',\'||nch==\';\'||nch==\'=\'

||nch==\'+\'||nch==\'-\'||nch==\'*\'||nch==\'/\'||nch==\'%\'||nch==\'^\')

{

lex=nch;

nch=getc(PF);

}

else

if(nch==EOF)

lex=EOF;

else

puts("Hедопустимый символ");

return;

}

void term()

{

int op;

fact();

while(lex==\'*\'||lex==\'/\'||lex==\'%\'||lex==\'^\')

{

op=lex==\'*\'?5:lex==\'/\'?6:lex==\'%\'?7:11;

get();

if(op!=11)

fact();

gen(OPR,op);

}

return;

}

void operat(int a)

{

int j=t-1,kk;

switch(a)

{

case 1:printf("1>");

fflush(stdout);push(red());break;

case 2:printf("%d\n",st[t--]);break;

case 3:st[j]+=st[t--];break;

case 4:st[j]-=st[t--];break;

case 5:st[j]*=st[t--];break;

case 6:if(st[t]==0) puts("/:делитель =0");

st[j]/=st[t--];break;

case 7:if(st[t]<=0) puts("%%:делитель =0");

st[j]%=st[t--];break;

case 8:st[t]=-st[t];break;

case 9:for(kk=0;kk<25;kk++)

fprintf(ptc,"tc[%i]=%d \n",kk,st[kk]);

j=st[sp-2];st[sp-j-2]=st[t];

t=sp-j-2;p=st[sp-1];sp=st[sp];break;

case 10:p=-3;

case 11:st[t]*=st[t];

}

return;

}

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

Створити програму - інтерпретатор для модифікованої мови SPL, в якійусі ключові слова на російській мові.

Крім того, добавлені дві операції: піднесення у квадрат і збільшення числа (increment) на два.

exp(a ,b)

начало

целый z;

z=1;

пока b делать

если b%2 тогда z=z*a конец;

а=a*a; b=b/2

конец

main()

начало

целый x,y;

читать x;

читать y;

печать exp(x,y);

печать x^;

печать [email protected];

конец

/*Кодылексемязыка SPL*/

NUMB,IDEN};

int isalpharus(char c);

int isspace1(char c);

int isdigit1(char c);

void get()

{

while(lex!=EOF)

{

while(isspace1(nch))

{

if(nch==\'\n\')

nst++;

nch=getc(PF);

}

if(isdigit1(nch))

number();

if(isalpharus(nch))

word();

else

if(nch==\'(\'||nch==\')\'||nch==\',\'||nch==\';\'||nch==\'=\'

||nch==\'+\'||nch==\'-\'||nch==\'*\'||nch==\'/\'||nch==\'%\'|| nch==\'^\'|| nch==\'@\')

{

lex=nch;

nch=getc(PF);

}

else

if(nch==EOF)

lex=EOF;

else

printf("Hедопустимыйсимвол nch=%c nst=%i\n",nch,nst);

return;

}

void word()

{

static char*serv[]={"если","пока","возврат","печать",

"читать","начало","конец","целый","константа",

"тогда","делать"};

ENDL,INTL, CONSTL,THENL,DOL};

int i;

char tx[40];

char*p;

for(p=tx;isdigit1(nch)||isalpharus(nch);nch=getc(PF))

*(p++)=nch;

*p=\'\0\';

int isalpharus(char c)

{

int v;

if(isalpha(c)||c==\'а\'||c==\'б\'||c==\'в\'||c==\'г\'||c==\'д\'||c==\'е\'||c==\'ж\'||c==\'з\'||c==\'д\'||c==\'е\'||c==\'ж\'||c==\'з\'||c==\'и\'||c==\'й\'||c==\'к\'||c==\'л\'

||c==\'м\'||c==\'н\'||c==\'о\'||c==\'п\'||c==\'р\'||c==\'с\'||c==\'т\'||c==\'у\'

||c==\'ф\'||c==\'х\'||c==\'ц\'||c==\'ч\'||c==\'ш\'||c==\'щ\'

||c==\'ы\'||c==\'э\'||c==\'ю\'||c==\'я\'||c==\'ь\')

v=8;

else

v=0;

return v;

}

int isspace1(char c)

{

int v;

if(c==‘ \ ‘ ||c==‘ \n ‘ ||c==\'\ t‘ ||c==‘ \f \')

v=1;

else

v=0;

return v;

}

int isdigit1(char c)

{

int v;

if(c==\'0\'||c==\'1\'||c==\'2\'||c==\'3\'||c==\'4\'||c==\'5\'||c==\'6\'||c==\'7\'||c==\'8\'||c==\'9\')

v=2;

else

v=0;

return v;

}

void term()

{

int op;

fact();

while(lex==\'*\'||lex==\'/\'||lex==\'%\'||lex==\'^\'||lex==\'@\')

{

op=lex==\'*\'?5:lex==\'/\'?6:lex==\'%\'?7:lex==\'^\'?11:12;

get();

if(op!=11 && op!=12)

{

fact();

}

gen(OPR,op);

}

return;

}

void operat(int a)

{

int j=t-1;

switch(a)

{

case 1:printf("1>");

fflush(stdout);push(red());break;

case 2:printf("%d\n",st[t--]);break;

case 3:st[j]+=st[t--];break;

case 4:st[j]-=st[t--];break;

case 5:st[j]*=st[t--];break;

case 6:if(st[t]==0) puts("/:делитель =0");

st[j]/=st[t--];break;

case 7:if(st[t]<=0) puts("%%:делитель =0");

st[j]%=st[t--];break;

case 8:st[t]=-st[t];break;

case 9:j=st[sp-2];st[sp-j-2]=st[t];

t=sp-j-2;p=st[sp-1];sp=st[sp];break;

case 10:p=-3;

case 11: st[t] *= st[t]; break;

case 12: st[t] += 2; break;

}

return;

}