Сдам Сам

ПОЛЕЗНОЕ


КАТЕГОРИИ







Методология программирования.





Методологии можно классифицировать по разным признакам.

Например, по признаку внутренней структуры:

1) функциональные (большая программа как совокупность подпрограмм);

2) объектные (программа – совокупность взаимодействующих объектов);

3) объектно-ориентированные.

Объекты, подпрограммы и программы будем называть модулями.

Методологии:

1) Нисходящая (сверху - вниз), т. е. сначала пишутся модули верхних уровней иерархии, а потом нижних.


Функционирование модуля A состоит из вызовов базовых модулей и модулей B1, B2, B3. При этом могут возникать рекурсии на верх. Легко видеть, что модули каждого уровня используют средства языка, друг друга и ранее написанные модули.

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

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

2) Восходящая (снизу-вверх)

В этом случае необходимо построить модуль A на базе модулей Z.


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

Вывод: Если создается система, имеющая подходящий аналог, то лучше использовать восходящую методологию, а в противном случае нисходящую.

3) Смешанная (реально используется на практике).

 

Компиляция формулы методом нисходящего разбора.

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

 

Program CompileFormula;

uses Crt, AComp, AStream;

var DN:string;

pst:PFStreamTxt;

c:CComp;

begin

ClrScr;

writeln('Откуда формула');

read(Dn);

new(PSt,Create(DN));

c.Init(PSt);

c.Compile;

c.Done;

dispose(Pst,Destroy);

end.

 

Unit AComp;

interface

uses AStream;

Type PComp = ^CComp;

CComp = object

public

constructor Init(PS:PFStreamTxt);

destructor Done;virtual;

procedure Compile;

private

p:PFStreamTxt;

procedure Failure(n:word);

procedure Formula;

procedure OperandP;

procedure OperandD;

procedure OperandM;

procedure OperandE;

procedure Number;

procedure Variable;

end;

 

implementation

uses crt;

 

constructor CComp.Init;

begin

p:=ps;

end;

 

destructor CComp.Done;

begin

p:=nil;

end;

 

Procedure CComp.Compile;

begin

ClrScr;

writeln('Pro.Create');

if p^.IsEnd then Failure(1);

Formula;

if not p^.IsEnd then Failure(2);

writeln('Pro.ShowResult');

writeln('Pro.Destroy');

end;

 

Procedure CComp.Formula;

{Откомпилировать самую большую не пустую формулу с данной позиции в потоке}

(* <Formula>::=<OperandP>[{+,-} <OperandP>]* *)

{Нашей задачей является перевод этого выражения на язык Pascal}

var x:char;

begin

if p^.IsEnd then Failure(11); {Формула оказалась пустой - это ошибка}

OperandP; {Вызываем обработку операнда P}

while true do {Организация бесконечного цикла}

begin

if p^.IsEnd then break; {Если поток пуст, то выходим из цикла}

x:=p^.GetChar; {берем символ из потока, по грамматике он должен быть

либо + или -, поэтому далее проверяем на соответствие этому}

case x of

'+':begin p^.skip; OperandP; writeln('Pro.Add'); end;

'-':begin p^.skip; OperandP; writeln('Pro.Sub'); end;

else break; {Если не то и не другое, то выходим из цикла - может быть

это закрывающая скобка}

end;

end;

{Если поток не пуст и оставшийся символ не закрывающая скоба, то

генерируем ошибку. Обратите внимание, что сначала необходимо

проверить поток на пустоту, а уже в следующем вложенном if.

Если написать, например, так

if not p^.IsEnd and not (p^.GetChar in [')']) then failure (12);

то можно получить сообщение об ошибке потока, т.к. сначала

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

из него будет взят символ (т.е. происходи полное вычисление логических

выражений) }

if not p^.IsEnd then

if not (p^.GetChar in [')']) then failure (12);

end;

 

Procedure CComp.OperandP;

(* <OperandP>::=<OperandD>[ / <OperandP> ] *)

var x:char;

begin

{Если поток пуст, то генерируем ошибку}

if p^.IsEnd then Failure(21);

OperandD; {Вызываем операнд D}

{Если поток оказался не пуст, то тут возможно 2 ситуации:

1) Далее идет знак /, а за ним опять операнд P

2) Далее идет лексема не имеющая никакого отношения к операнду P}

if not p^.IsEnd then

begin

x:=p^.GetChar;

if x='/' then begin p^.skip; OperandP; writeln('Pro.Div'); end;

{Если x это / - то получаем первый случай}

end;

if not p^.IsEnd then

if not (p^.GetChar in [')','+','-']) then failure (22);

{Если далее идет не)+- то это ошибка}

end;

 

Procedure CComp.OperandD;

(* <OperandD>::= <OperandM> [* <OperandM>]* *)

var x:char;

begin

if p^.IsEnd then Failure(31);

OperandM;

while true do

begin

if p^.IsEnd then break;

x:=p^.GetChar;

case x of

'*':begin p^.skip; OperandM; writeln('Pro.Mul'); end;

else break;

end;

end;

if not p^.IsEnd then

if not (p^.GetChar in [')','+','-','/']) then failure (32);

end;

 

Procedure CComp.OperandM;

var x:char;

begin

{Полностью аналогичен Formula, правда было бы рациональнее вместо

конструкции case использовать if..., но ради сохранения стиля

оставляем все как есть}

if p^.IsEnd then Failure(41);

x:=p^.GetChar;

case x of

'+':begin p^.skip; OperandM; end;

'-':begin p^.skip; OperandM; writeln('Pro.Inv'); end;

else OperandE;

end;

if not p^.IsEnd then

if not (p^.GetChar in [')','+','-','/','*']) then failure (42);

{Обратите внимание, что число знаков увеличилось из-за того что

надо проверять еще и на все предыдущие операции}

end;

 

{Для работы с операндом E потребуются дополнительно константы-цифры и

константы-буквы идентификатора}

const Digits:set of char = ['0'..'9'];

Letters:set of char = ['_','A'..'Z','a'..'z'];

 

 

Procedure CComp.OperandE;

(* <OperandE>::=<Number> | <Variable> | (<Formula>) *)

var x:char;

begin

if p^.IsEnd then Failure(51); {поток не пуст?}

{берем символ из потока}

x:=p^.Getchar;

if x in digits then Number {Если x-цифра, то считываем число}

else if x in Letters then Variable {Если x-буква, то считываем идентификатор}

else if x='(' then {если x - открывающая скобка, то...}

begin

p^.skip; Formula; {пропускаем символ, вызываем обработку формулы}

if p^.IsEnd then Failure(52) else {Если поток закончен то ошибка, иначе}

if not (p^.GetChar in [')']) then failure (53) {Считываем символ}

else p^.skip; {Если это), то все в порядке, иначе выдаем ошибку}

end else failure(54);

end;

 

Procedure CComp.Variable;

(* <Variable>::=<Letters> [ <Letters>|<Digits> ]* *)

 

var x:char;

begin

if p^.IsEnd then Failure(61);

x:=p^.GetChar;

if not (x in Letters) then Failure(62);

{Если x - не буква, то точно ошибка}

write('Pro.LoadR(',x); p^.skip;

while true do {Бесконечный цикл, в котором считывается идентификатор}

begin

if p^.IsEnd then Break;

{Если вы хотите игнорировать символы табуляции в имени идентификатора, то

комментарий ниже необходимо убрать}

{ if p^.IsAfterSpace then break;}

x:=p^.GetChar;

if x in letters+digits then

begin

writeln(x); p^.skip;

end else break;

end;

writeln(')');

if not p^.IsEnd then Failure(52) else

if not (p^.GetChar in [')','+','-','/','*']) then failure (63);

end;

 

{Можно было точно так же написать считывания числа, но мы пойдем по другому пути. Следующая процедура работает по методу конечного автомата. Это очень мощный механизм организации работы. Суть данного метода в том, что в каждый момент времени фиксируется состояние алгоритма(исполнителя). Он будет находится в этом состоянии пока не произойдет фиксированное событие, изменяющее состояние алгоритма(исполнителя). В нашем случае

это будет определенный символ (или его отсутствие).

Для нашего алгоритма число возможных состояний равно 6:

1...9. 1...9 E + 1...9

----- - ----- - - ----- -

1 2 3 4 5 6 7

1 состояние - считываются цифры (до первого нецифрового обозначения),

после чего осуществляется переход во 2 состояние

2 состояние - считывается точка(если есть) и переход в состояние 3

3 состояние - считываются цифры (до первого нецифрового обозначения),

после чего осуществляется переход во 4 состояние

4 состояние - считывается E (обозначение экспоненты) и переход в

состояние 5

5 состояние - считывается или + или - после чего переход в 6 состояние

6 состояние - считываются цифры (до первого нецифрового обозначения),

после чего осуществляется переход во 7 состояние

7 состояние - конец работы

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

}

 

procedure CIntr.Number;

 

function dig(c:char):byte;

begin

if c in digits then

dig:=ord(c)-ord('0')

else

dig:=0;

end;

 

var

x: char;

s: byte;

sign:shortint;

frc,

pow,num:double;

 

begin

if p^.IsEnd then failure(71);

x:=p^.GetChar;

if not (x in digits) then failure(72);

write('Pro.LoadR(');

s:=1;

num:=0;

pow:=0;

frc:=0.1;

sign:=1;

while s<>0 do

case s of

1: begin

write(x);

num:=num*10+dig(x);

p^.Skip;

if p^.IsEnd then s:=0

else

begin

x:=p^.GetChar;

if x='.' then s:=2

else

if x in ['e','E'] then s:=4

else if not (x in digits) then s:=0;

end;

end;

2: begin

write('.');

p^.Skip;

if p^.IsEnd then s:=0

else

begin

x:=p^.GetChar;

if x in digits then s:=3

else

if x in ['e','E'] then s:=4

else

failure(75);

end;

end;

3: begin

write(x);

num:=num+frc*dig(x);

frc:=0.1*frc;

p^.Skip;

if p^.IsEnd then s:=0

else

begin

if x in ['e','E'] then s:=4

else

if not (x in digits) then s:=0;

end;

end;

4: begin

write(x);

p^.Skip;

if p^.IsEnd then failure(76);

x:=p^.GetChar;

if x in digits then s:=6

else

if x in ['+','-'] then s:=5

else failure(77);

end;

5: begin

write(x);

if x='-' then sign:=-1;

p^.Skip;

if p^.IsEnd then failure(78);

x:=p^.GetChar;

if x in digits then s:=6

else failure(79);

end;

6: begin

write(x);

pow:=pow*10+dig(x);

p^.Skip;

if p^.IsEnd then s:=0

else

begin

x:=p^.GetChar;

if not (x in digits) then s:=0;

end;

end;

end;

writeln(')');

num:=num*exp(ln(10)*sign*pow);

pro^.LoadR(num);

if not p^.IsEnd then

if not (p^.GetChar in [')','+','-','*','/']) then failure(80);

end;

 

Procedure CComp.Failure;

{Фатальный обработчик ошибок}

begin

write('Ошибка компилятора # ',n:1,' в методе ');

case n of

1..10:writeln('Compile');

11..20:writeln('Formula');

21..30:writeln('OperandP');

31..40:writeln('OperandD');

41..50:writeln('OperandM');

51..60:writeln('OperandE');

61..70:writeln('Variable');

71..80:writeln('Number');

end;

case n of

1:writeln('Пустой текст');

11,21,31,41,51,61,71:writeln('Нет операнда');

{..и т.д.}

end;

Halt(1);

end;

 

begin

end.

 







Что делать, если нет взаимности? А теперь спустимся с небес на землю. Приземлились? Продолжаем разговор...

ЧТО И КАК ПИСАЛИ О МОДЕ В ЖУРНАЛАХ НАЧАЛА XX ВЕКА Первый номер журнала «Аполлон» за 1909 г. начинался, по сути, с программного заявления редакции журнала...

Что способствует осуществлению желаний? Стопроцентная, непоколебимая уверенность в своем...

Что будет с Землей, если ось ее сместится на 6666 км? Что будет с Землей? - задался я вопросом...





Не нашли то, что искали? Воспользуйтесь поиском гугл на сайте:


©2015- 2024 zdamsam.ru Размещенные материалы защищены законодательством РФ.