0
Upcoming SlideShare
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Standard text messaging rates apply

# Software Unit Testing Case Study:

253

Published on

0 Likes
Statistics
Notes
• Full Name
Comment goes here.

Are you sure you want to Yes No
Your message goes here
• Be the first to comment

• Be the first to like this

Views
Total Views
253
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
8
0
Likes
0
Embeds 0
No embeds

No notes for slide
• The problem with Principle 2 is that it produces the longest schedule . In practice, we apply: Principle 2’: A module, M, may be unit tested (with subordinate stubs) when the probability that an interface change will occur to some module upon which M depends falls below a given threshold, 
• Schedule the design of independent use cases to run in parallel. For each use case: (a) identify the participating classes (b) Identify the controlling method and its interface (c) Identify the immediately subordinate methods and associated classes (d) Design the interface to subordinate methods (e) Design the details of subordinate methods by identifying the dependent classes and methods Repeat until all methods have been designed. Conduct unit testing of methods in the reverse order of their detailed design. Schedule unit testing at the earliest possible time. Schedule unit testing of dependent methods at the earliest time after completing the unit testing of all required methods.
• Figure (a) illustrates a typical module in a functional architecture - the module encapsulates a particular system function. This module manages the control flow among three related computations X,Y and Z applied to three data types A, B, and C. Figure (b) illustrates the OO architecture equivalent to figure (a). In this architecture, the data types A,B, and C become object classes Class-A, Class-B, and Class-C, respectively. The services defined for these classes represent the parts of computations X,Y and Z that directly related to one of the given types. Finally, there is typically a “control object” that initiates and/or manages the flow of messages necessary to realize the original functionality. In a pure OO system, control flow management is usually distributed among one or more “active” objects. Even so, the pragmatics of efficiency usually dictate the need for some central “executive” that manages and coordinates the overall flow of messages and control flow among objects.
• This figure shows the functional dependencies among services of different object classes. These dependencies are manifested when a service of some object A (perhaps the self service) sends a message to request a service of object C, which sends a message to object D, etc. Each system function or use-case scenario is realized by one or more of these “functional threads.” So, from the perspective of system integration and testing, the identification and isolation of these threads is important, for they will serve as the basis for developing test plans, procedures, and data. As depicted in the diagram above, three functional threads can be identified: (1) A.1, B.1 (2) A.2, D.2, E.1 (3) A.3, C.1 (B.2, D.1, E.2; D.3) Because of the importance of these functional threads for testing, they also become the focus of design and implementation. In fact, all design, coding, and testing activities should be structured and schedule around functional threads. Once the functional threads have been constructed, a few simple principles can be applied to develop a schedule for detailed design, coding, unit testing, and integration testing. These are illustrated on ensuing slides.
• This figure shows the functional dependencies among services of different object classes. These dependencies are manifested when a service of some object A (perhaps the self service) sends a message to request a service of object C, which sends a message to object D, etc. Each system function or use-case scenario is realized by one or more of these “functional threads.” So, from the perspective of system integration and testing, the identification and isolation of these threads is important, for they will serve as the basis for developing test plans, procedures, and data. As depicted in the diagram above, three functional threads can be identified: (1) A.1, B.1 (2) A.2, D.2, E.1 (3) A.3, C.1 (B.2, D.1, E.2; D.3) Because of the importance of these functional threads for testing, they also become the focus of design and implementation. In fact, all design, coding, and testing activities should be structured and schedule around functional threads. Once the functional threads have been constructed, a few simple principles can be applied to develop a schedule for detailed design, coding, unit testing, and integration testing. These are illustrated on ensuing slides.
• This figure shows the functional dependencies among services of different object classes. These dependencies are manifested when a service of some object A (perhaps the self service) sends a message to request a service of object C, which sends a message to object D, etc. Each system function or use-case scenario is realized by one or more of these “functional threads.” So, from the perspective of system integration and testing, the identification and isolation of these threads is important, for they will serve as the basis for developing test plans, procedures, and data. As depicted in the diagram above, three functional threads can be identified: (1) A.1, B.1 (2) A.2, D.2, E.1 (3) A.3, C.1 (B.2, D.1, E.2; D.3) Because of the importance of these functional threads for testing, they also become the focus of design and implementation. In fact, all design, coding, and testing activities should be structured and schedule around functional threads. Once the functional threads have been constructed, a few simple principles can be applied to develop a schedule for detailed design, coding, unit testing, and integration testing. These are illustrated on ensuing slides.
• ### Transcript

• 1. Software Unit Testing Case Study: Money Class Conversation Simulation COP 4331 OO Processes for Software Development Dr. David A. Workman School of EE and Computer Science October 2, 2006
• 2. Hierarchical View of Design main A::One() A::Two() A::Three() B::One() C::One() B::Two() D::One() E::Two() E::One() D::Three() D::Two() Use Case #1 Use Case #3 Use Case #2
• 3. Design & Testing Principles A D B C Principle 1: Design should be performed “top-down” for each functional thread defined by a Use Case; that is, the interface and detailed design of a module should follow the design of all modules that functionally depend on it. Rationale: By performing interface and detailed design top-down, we ensure that all requirements flow from dependent modules toward the modules they depend on. This principle attempts to postpone detailed design decisions until all functional requirements for a module are known. Principle 2: Coding and Unit Testing should be performed “bottom-up” for a functional thread; that is, the unit testing of a module should precede the unit testing of all modules that functionally depend on it. Rationale: By performing unit testing bottom-up, we ensure that all subordinate modules have been verified before verifying the module that depends on them. This principle attempts to localize and limit the scope and propagation of changes resulting from unit testing.
• 4. Design & Testing Schedules Development Layers for Detailed Design and Coding Development Layers for Unit Testing See Notes Effort Time Development Schedule Build #1 (Integration Test 1) Build #2 (Integration Test 2) Build #3 (System Test)
• 5. Design & Test Example: Discrete Event Simulator ©Dr. David A. Workman School of EE and Computer Science University of Central Florida March 29, 2007
• 6. Use Case Diagram: Simulator Simulation System Construct World Specify Input Simulate World Output World Objects Report Simulation Data Initialize Simulation Specify Output Simulation Input File Simulation Log File Simulation User
• 7. Simulation Architecture
• 8. Simulation Architecture: Design Template The Passive layer contains all classes that model problem data and inanimate objects of the simulated world. Agents make direct calls on passive objects, but must account for the simulation time consumed when doing so. Passive objects make direct calls to each other, if necessary. Passive objects may be passed from one Agent to another as part of a instance of some Message subclass. This layer contains all the derived subclasses of Message. These classes are used to pass data for servicing interaction events between Agents. Only recipient Agent classes know the content and use of instances of these classes. Methods of Agents receiving messages optionally take parameters which are instances of one (or more) of the Passive classes and return an instance of class Message or one of its sub-classes. Instances of the root class Message carry no data and denote signals that require some action on the part of the receiver Agent. Virtual World Message Players Agent Event 2 Passive Class Layer Message Layer Agent Layer (Active Objects) Interface and Control Layer EventMgr * 1 Other Subclasses All Active Objects * * All Passive Classes/Objects * * * This layer consists of all active object classes. Active objects must be instances of some subclass of abstract class Agent . The simulation progresses as a result of Events created and serviced by Agents. An Event has four components: a Sender agent, a Recvr agent, an instance of some Message subclass, and an event time. When one Agent wishes to interact with another, it must do so by creating an Event that defines a “future” time at which the interaction will occur. The message component defines an action to the Recevr agent and possibly data necessary to complete the action. SimModels Classes SimMgmt Classes
• 9. Simulation Architecture: Student Conversation Conversation Message Players Agent Event 2 Passive Class Layer Message Layer Agent Layer (Active Objects) Interface and Control Layer EventMgr * 1 AnswerMsg * * Question Student Answer QuestionMsg SimModels Classes SimMgmt Classes
• 10. Design Graph: 1 0: Main() 4 Reusable Methods 9 New Methods Class Conversation 1: Conversation() Class Agent 2: Agent() 3: operator>>() 4: Get() Class Student 5: Student() 6: Extract() 7: Get() 1 5 6 3 2 7 4 Use Case 1
• 11. Design Graph: 2 0: Main() 5 Reusable Methods 9 New Methods Class Conversation 1: Conversation() 8: Initialize() Class Agent 2: Agent() 3: operator>>() 4: Get() 11: NameOf() 21: ~Agent() Class Student 5: Student() 6: Extract() 7: Get() 13: Initialize() 16: AcceptQuest() 8 20 Class Players 9: Players() 12: setAgent() 14: getAgent() 15: getOther() 20: ~Players() Class Message 10: Message() 9 2 12 13 11 14 15 16 Class SpeakMsg 17: SpeakMsg() 17 10 Class Event 18: Event() 18 Class EventMgr -3 : EventMgr() 19: postEvent() 19 21 Use Case 2
• 12. Design Graph: 3 0: Main() Class Conversation 1: Conversation() 8: Initialize() 22: Insert() Class Agent 2: Agent() 3: operator>>() 4: Get() 11: NameOf() 21: ~Agent() 23: oper<<() 26: Put() Class Student 5: Student() 6: Extract() 7: Get() 13: Initialize() 16: AcceptQuest() 24: Insert() 25: Put Class Players 9: Players() 12: setAgent() 14: getAgent() 15: getOther() 20: ~Players() Class Message 10: Message() Class SpeakMsg 17: SpeakMsg() Class Event 18: Event() Class EventMgr -3: EventMgr() 19: postEvent() 25 24 22 23 26 2 Reusable Methods 3 New Methods Use Case 3
• 13. Design Graph: 4 0: Main() 2 Class Conversation 1: Conversation() 8: Initialize() 22: Insert() 44: Simulate() Class Agent 2: Agent() 3: operator>>() 4: Get() 11: NameOf() 21: ~Agent() 23: oper<<() 26: Put() Class Student 5: Student() 6: Extract() 7: Get() 13: Initialize() 16: AcceptQuest() 24: Insert() 25: Put() 37: Dispatch() 39: doQuestion() 40: AcceptAnswr() 41: doAnswer() Class Players 9: Players() 12: setAgent() 14: getAgent() 15: getOther() 20: ~Players() Class Message 10: Message() 30: Oper<<() 31: Insert() 32: Put() 42: ~Message() Class SpeakMsg 17: SpeakMsg() 33: Insert() 34: Put() 38: getHandlr() Class Event 18: Event() 29: oper<<() 35: getRecvr() 36: getMsg() 43: ~Event() Class EventMgr -3: EventMgr() 19: postEvent() 27: moreEvents() 28: getNextEvent() 17 27 28 29 23 24 25 26 30 32 31 33 34 36 35 40 39 38 37 41 10 18 19 42 44 10 Reusable Methods 8 New Methods 43 Use Case 4
• 14. Design Graph: 2 0: Main() Class Conversation 1: Conversation() 8: Initialize() 22: Insert() 44: Simulate() 45: WrapUp() 46: ~Conversation() Class Agent 2: Agent() 3: operator>>() 4: Get() 11: NameOf() 21: ~Agent() 23: oper<<() 26: Put() Class Student 5: Student() 6: Extract() 7: Get() 13: Initialize() 16: AcceptQuest() 24: Insert() 25: Put() 37: Dispatch() 39: doQuestion() 40: AcceptAnswr() 41: doAnswer() 47: ~Student() Class Players 9: Players() 12: setAgent() 14: getAgent() 15: getOther() 20: ~Players() Class Message 10: Message() 30: Oper<<() 31: Insert() 32: Put() 42: ~Message() Class SpeakMsg 17: SpeakMsg() 33: Insert() 34: Put() 38: getHandlr() Class EventMgr -3: EventMgr() 19: postEvent() 27: moreEvents() 28: getNextEvent() 48: ~EventMgr() 46 45 47 Class Event 18: Event() 29: oper<<() 35: getRecvr() 36: getMsg() 43: ~Event() 1 Reusable Methods 3 New Methods Use Case 5 21 Reusable 27 New ---------------- 48 Total Methods 4 Reusable 4 New --------------- 8 Total Classes
• 15. Scheduling Development Schedule Use Case 1 Use Case 3 Use Case 5 Use Case 4 Use Case 2 0: Main() 1 5 6 3 2 7 4 8 20 9 2 12 13 11 14 15 16 17 10 18 19 21 25 24 22 23 26 17 27 28 29 23 24 25 26 30 32 31 33 34 36 35 40 39 38 37 41 10 18 19 42 44 43 46 45 47
• 16. Money Class Money(fin) Extract(fin) Get(fin) Money() Money(char,int,int) getSign() getDollars() getCents() boolean operators() * binary operators() toInt(Money) toMoney(int) * Insert(fout) Put(fout) operator>>(fin) operator<<(fout) TokenError 1 1 1 1 1 1 1 2 2 2 2 2 3 3 3 3 4 4 4 4 Initially make public Money Char sign Int dollars Int cents Money(); Money(ifstream&); Money(char,int,int); getSign():char getDollars():int; getCents():int; operator-() :Money; operator-(Money):Money; operator+(Money):Money; operator==(Money):bool; operator<(Money):bool; operator>(Money):bool; operator<=(Money):bool ; operator>=(Money):bool; Extract(ifstream&)=>TokenError Insert(ostream&); operator>>(ifstream&,Money&) operator<<(ostream&,Money&) #Get(ifstream&) #Put(ostream&); -toInt(Money):int -toMoney(int):Money
• 17. Money Class Test Driver 1 #include &quot;IOMgmt.h&quot; using namespace IOMgmt; #include &quot;Money.h&quot; int main() { InMgr finMgr(&quot;Enter Input File ( Test1 ):&quot;); ifstream& fin = finMgr.getStream(); OutMgr foutMgr(&quot;Enter Output File( Test1 ):&quot;); ostream& fout = foutMgr.getStream(); int num_cases; char sign; int dollars, cents; fin >> num_cases; for(int I = 1; I <= num_cases; I++) { fin >> sign >> dollars >> cents; fout << &quot;Case #&quot; << num_cases – I + 1 << endl; fout << &quot;Input Data: &quot; << sign << dollars << cents << endl; Money M1(sign,dollars,cents); int M1cents = toInt(M1); Money M2 = toMoney(M1cents); char Sign = M2.getSign(); int Dollars = M2.getDollars(); int Cents = M2.getCents(); fout << &quot;M1cents: &quot; << M1cents << endl; fout << &quot;Sign = &quot; << Sign << &quot;, Dollars= &quot; << Dollars << &quot;, Cents= &quot; << Cents << endl; }//for }//main-1
• 18. Money Class Test Driver 2 #include &quot;IOMgmt.h&quot; using namespace IOMgmt; #include &quot;Money.h&quot; int main() { InMgr finMgr(&quot;Enter Input File( Test2 ):&quot;); ifstream& fin = finMgr.getStream(); OutMgr foutMgr(&quot;Enter Output File( Test2 ):&quot;); ostream& fout = foutMgr.getStream(); int num_cases; char sign1, sign2; int dollars1, cents1, dollars2, cents2; fin >> num_cases; for(int I = 1; I <= num_cases; I++) { fin >> sign1 >> dollars1 >> cents1 >> sign2 >> dollars2 >> cents2; Money M1(sign1,dollars1,cents1), M2(sign2,dollars2,cents2); fout << &quot;Case #&quot; << I << endl; fout << &quot;Input Data (M1): &quot; << sign1 << dollars1 << cents1 << endl; fout << &quot;Input Data (M2): &quot; << sign2 << dollars2 << cents2 << endl; bool Reql, Rneq, Rless, Rgtr, Rleq, Rgeq; Reql = M1 == M2; Rneq = M1 != M2; Rless = M1 < M2; Rgtr = M1 > M2; Rleq = M1 <= M2; Rgeq = M1 >= M2; fout << &quot;(==) &quot; << Reql << &quot; (!=) &quot; << Rneq << //etc. Money Sum, Diff, Neg; Sum = M1 + M2; Diff = M1 – M2; Neg = -M1; fout << &quot;Sum = &quot; << Sum << &quot;, Diff = &quot; << Diff << &quot;, Neg(M1) = &quot; << Neg << endl; fout << &quot;M1 = &quot; << M1 << &quot;, M2 = &quot; << M2 << endl; }//for }//main-2
• 19. Money Class Test Driver 3 #include &quot;IOMgmt.h&quot; using namespace IOMgmt; #include &quot;Money.h&quot; int main() { InMgr finMgr(&quot;Enter Input File( Test3 ):&quot;); ifstream& fin = finMgr.getStream(); OutMgr foutMgr(&quot;Enter Output File( Test3 ):&quot;); ostream& fout = foutMgr.getStream(); int num_cases; fin >> num_cases; for(int I = 1; I <= num_cases; I++) { Money M; try{ fout << &quot;Case# &quot; << I; fin >> M; fout << &quot;: Money = &quot; << M << endl; }//try catch(TokenError &e){ fout << &quot;: &quot; << e.getMsg() << endl; }//catch }//for }//main-3
• 20. Testing Agent Behaviors Once the constructors, Insert, Put, Extract and Get methods have been written and tested, the way is clear to test simulation initialization and execution behaviors. There are a couple of techniques that can be used to test specific Events and consequently specific Agent behaviors. class Conversation { //Virtual World public: Conversation(); ~Conversation(); void Initialize(); void Simulate(); void WrapUp(); void Put(); private int debugOption; //new simulation input paramter int numStudents; int numEvents; int lastEvent; AGENTPTR *students; //dynamic array of Agent* MSGPTR players; //pointer to Players message. void ExtractEvent(); //private method(s) for testing };//Conversation
• 21. Testing Agent Behaviors Void Conversation::Conversation() { //parses image of virtual world object, Conversation. //if debugOpt = ON, then it calls ExtractEvent() } void Conversation::ExtractEvent() { //private method of Conversation //Has visibility to any data the Conversation constructor can see. //Parses the desired image of Event(s) for debugging purposes // Posts the constructed Event(s) to theEventMgr. } SimModels.cpp
• 22. Testing Agent Behaviors class Message {//concrete base class public: Message(int Handler,string Description); virtual ~Message() { } //destructor int getHandler() const { return handler;} //inspector friend ostream& operator<<(ostream &fout, Message &anyMsg) throw(IOError); friend ifstream& operator>>(ifstream& &fin, Message &anyMsg) throw(IOError, TokenError); //new protected: virtual void Insert(); virtual void Put (); virtual void Extract() throw(TokenError); //new virtual void Get() throw(TokenError); //new private: int handler; string description; };//Message class SpeakMsg : public Message { // Inherits from Message public: SpeakMsg(int Handler, string Description, string Speak); ~SpeakMsg() { } string getContent() const { return content; } protected: virtual void Insert(); virtual void Put(); virtual void Extract() throw(TokenError); //reads default program input stream virtual void Get() throw(TokenError); //reads default program input stream private: string content; }; //SpeakMsg
• 23. Testing Agent Behaviors Conversation{ debugopt: OFF #students: 2 Student{ name: Betty questdelay: 5 ansrdelay: 2 }Student Student{ name: Bart questdelay: 3 ansrdelay: 4 }Student }Conversation Conversation{ debugopt: ON #students: 2 Student{ name: Betty questdelay: 5 ansrdelay: 2 }Student Student{ name: Bart questdelay: 3 ansrdelay: 4 }Student debug{ #events: 1 Event{ time: ttt sendr: Bart recvr: Betty msg: SpeakMsg{ handler: 3 description: Testing content: How_Are_You? }SpeakMsg }Event }debug }Conversation
• 24. Applications of the Theory Automata and Regular Expressions to Programming and Software Testing Presentation by © Dr. David A. Workman School of EE & CS University of Central Florida March 3, 2003
• 25. Outline <ul><li>A Little History of Programming </li></ul><ul><li>A Little Review of Theory (COT 4210) </li></ul><ul><li>An Example Applying Theory to Practice </li></ul><ul><li>Summary and Conclusion </li></ul>
• 26. A Little History of Programming <ul><li>“ Flow Diagram, turing machines and languages with only two formation rules.” by Bohm and Jacopini, CACM Vol. 9, No. 5 (May 1966) </li></ul><ul><ul><li>Proved that all algorithms could be expressed using sequential execution assignment statements, conditional logic using if-then-else statements, and iteration using while statements. </li></ul></ul><ul><li>“ Goto Statements considered harmful,” by Edsgar Dijkstra , C ACM, Vol. 11, No. 3, March 1968, pp. 147-148. </li></ul><ul><ul><li>Contributions to the specification of ALGOL, 1957 – 60. </li></ul></ul><ul><ul><li>Cooperating Sequential Processes, 1966 </li></ul></ul><ul><ul><li>The THE Operating System, 1968 </li></ul></ul><ul><li>ACM/A.M. Turing Award Citation, February 5, 1999: </li></ul><ul><ul><li>“ Edsger Dijkstra was a principal contributor in the late 1950's to the development of the ALGOL, a high level programming language which has become a model of clarity and mathematical rigor. He is one of the principal exponents of the science and art of programming languages in general, and has greatly contributed to our understanding of their structure, representation, and implementation. His fifteen years of publications extend from theoretical articles on graph theory to basic manuals, expository texts, and philosophical contemplations in the field of programming languages. “ </li></ul></ul>
• 27. A Little Review of Theory <ul><li>Definition 1. A Deterministic Finite Automata (DFA) is a 5-tuple, M = (Q,  ,  , q 0 , A), where Q is a finite set of states,  denotes the input alphabet , q0 denotes the unique start state , A a finite, possibly empty set of Accept states , and the behavior of M is specified by its transition (computation) function  : Q   Q. </li></ul>We typically specify the behavior of a DFA, its d function, in the form of a State Transition Diagram such as the one shown below as an example. 1 5 4 3 2 start a b a a a a b b b b
• 28. A Little Review of Theory <ul><li>Definition 2. The Language Accepted by a DFA, is denoted L(M), and is given by L(M) = { x  * |   (q 0 , x)  A } </li></ul><ul><li>where the function ,   : Q   *  Q, is an extension of the transition function to strings over the input alphabet. </li></ul>What is L(M) for the DFA, M, given below??? L(M) = { a, ab, abaaaaba, aaaaaaba, …. } 1 5 4 3 2 start a b a a a a b b b b
• 29. A Little More Theory <ul><li>Definition 3. The Language of Regular Expression, E (  ), over alphabet  , is the set of strings over alphabet  ’ =   {  ,  ,  ,  ,  , ( , ) } given by the inductive definition: Basis:   {  ,  }  E (  ) . Inductive Rules: assume e, f  E (  ), then each of the following is a member of E (  ), [1] (e)* [2] (e  f) [3] (e  f) </li></ul>Definition 4. The Language defined by Regular Expression, e, is denoted L[e] and is defined recursively below. Basis: L[  ] =  (the empty set), and for e    {  }, L[ e ] = { e }. Inductive Rules: e, f, g  E (  ), [1] if e = (f)*, then L[e] = L[f]* (Kleene-star operation) [2] if e = (f  g), then L[e] = L[f]L[g] (Language concatenation) [3] if e = (f  g), then L[e] = L[f]  L[g] (Language union) Example. E ( {a,b} ) = {  ,  , a, b, (  )*, (  )*, (a)*, (b)*, (    ), (a  a), (b   ), (  +  ), (a +a), (b +  ), … (((a(ba))+(  )*)+(  ((  +  ))*))… } Example. L[ (((a(ba))+(  )*)+(  ((  +  ))*)) ] = {aba,  }
• 30. A Little Review of Theory <ul><li>What is the significance (relevance) of DFAs (and their theory) ? </li></ul><ul><li>What is the significance of Regular Expressions (RE)? </li></ul><ul><li>How do these mathematical abstractions apply to programming? </li></ul><ul><li>SOME ANSWERS </li></ul><ul><ul><li>DFAs are algorithmic abstractions </li></ul></ul><ul><ul><li>DFAs and REs can be used to model the lexical analysis function of real compilers </li></ul></ul><ul><ul><li>DFA’s recognize Regular languages </li></ul></ul><ul><ul><li>RE’s also define Regular Languages </li></ul></ul><ul><li>??? “Ho Hum, Yawn” </li></ul>This could be You!!!
• 31. Example Method (C++) <ul><li>void Server::Work() </li></ul><ul><li>{ </li></ul><ul><li>ifstream input; // input file stream </li></ul><ul><li>ofstream output; // output file stream </li></ul><ul><li>Tray tray; </li></ul><ul><li>cout << &quot;McDonald's Implementation in C++&quot; << endl; </li></ul><ul><li>cout << &quot;by XXXXXXXXXX and YYYYYYYYYYY&quot; << endl; </li></ul><ul><li>cout << endl; </li></ul><ul><li>while(1) { </li></ul><ul><li> string szInputFileName; </li></ul><ul><li> cout << &quot;Please enter the name of the input file: &quot;; </li></ul><ul><li> cin >> szInputFileName; </li></ul><ul><li> input.open(szInputFileName.c_str()); </li></ul><ul><li> if( !input ) alpha: { cerr << endl << &quot;No file named &quot; << szInputFileName << &quot; found.&quot; << endl; } </li></ul><ul><li> else break; </li></ul><ul><li>} </li></ul><ul><li>} //Server:: Work </li></ul>Insert Segment A (from next slide 1 2 3 5 4 6 16 A Basic Block of code is a sequence of declaration , assignment , and method call statements, that may optionally end with a goto or contional goto statement.
• 32. Example Method (C++) FoodItems *pFood; while(!input.eof()) { char szMarker[4]; input >> szMarker; strupper(szMarker); if(strcmp(szMarker, &quot;\$D&quot;) == 0) pFood = new Drinks; // drink else if(strcmp(szMarker, &quot;\$S&quot;) == 0) pFood = new Sandwiches; // sandwich else if(strcmp(szMarker, &quot;&quot;) == 0) continue; // blank line; skip else throw InputException(&quot;Unknown type found &quot; + string(szMarker)); pFood->Get(input); tray.Add_Item(pFood); } //while Segment A 6 7 8 9 10 11 12 13 14 15
• 33. Example Method (C++) 1 2 8 6 5 3 10 15 12 17 Exception exit Normal exit System exit 9 11 14 F T F F F F T T T T Notes: This is an example of a program flow graph, the subject of Bohm and Jacopini’s theorem. Even though this algorithm was written using a “structured style”, the flow graph is not completely structured in the purest sense since there are multiple method exits due to exceptions. 16 7 4 13
• 34. Example Method (C++) 1 2 8 6 5 3 10 15 12 Exception exit Normal exit 9 11 14 F T F F F F T T T T Note: We have modified the structured version to violate the principles of structured design ( 13 => 5 ). To Re-Structure we apply the theory of DFAs and REs as follows: (1) All conditional nodes become “states” in a DFA. (2) Transitions between states are labeled with the sequential computation that connects any pair of conditional nodes. (3) Unique transition sequences become “letters” in the DFA alphabet. ! 16 7 4 13
• 35. Example Method (C++) a = 123 b = (4T)523 c = (4F)6 d = (7T)8 e = (9T)(10)(15) f = (9F) g = (11T)(12)(15) h = (11F) i = (13T523) j = (13F) k = (7F) start Exception exit Normal exit 9 11 14 a b c k d e f g h j i E 4 = a + E 4 b + E 13 i E 7 = E 4 c + E 9 e + E 11 g E 9 = E 7 d E 11 = E 9 f E 13 = E 11 h E 14 = E 13 j E 16 = E 7 k Define the following “alphabet” Set up a system of Regular Equations Solution for Paths = E 16 + E 14 E 16 = ab*c[d ( e + f (g + hib*c)) ]*k E 14 = ab*c[d ( e + f (g + hib*c)) ]*dfhj Paths = ab*c[d ( e + f (g + hib*c)) ]* (k+dfhj) 16 7 4 13
• 36. Expression => Code { boolean X; 1;3; //a (2 = true) while( 4 ) { 5; 3 } //b* 6; //c X := true; // Boolean variable for exception handling while ( X and 7 ) { //7T 8; //d if( 9 ) { //9T 10; 15 //e } else { //9F = f if( 11 ) { //11T 12;15 //g else{ //h if( 13 ) { //13T 5; 3 //i while( 4 ) { 5; 3} //b* 6; //c = (4F)6 } else X = false; //13F = exception condition }//11 - else }//9 - else }// while(7 and X) if( not X ) throw(exception); //j = abnormal end } //k = normal end Equivalent Structured Code a = 123 b = (4T)523 c = (4F)6 d = (7T)8 e = (9T)(10)(15) f = (9F) g = (11T)(12)(15) h = (11F) i = (13T523) j = (13F) k = (7F) Solution for Paths = E 16 + E 14 E 16 = ab*c[d ( e + f (g + hib*c)) ]*k E 14 = ab*c[d ( e + f (g + hib*c)) ]*dfhj Paths = ab*c[d ( e + f (g + hib*c)) ]* (k+dfhj)
• 37. Summary & Conclusion <ul><li>Summary (What are the main points?) </li></ul><ul><ul><li>DFAs and REs are more than just (equivalent) mathematical specifications for Regular Languages and algorithms for lexical analysis, they are useful for modeling algorithms of any kind and complexity. </li></ul></ul><ul><ul><li>Using algorithms for equivalence between DFAs and REs we were able to see why Bohm and Jacopini’s theorem is true, and why Dijkstra so strongly endorced the principles of structured programming. </li></ul></ul><ul><li>Conclusion (What have we learned?) </li></ul><ul><ul><li>The “marriage” between Theory and Practice is not “on the rocks”, this couple is not “legally separated” or “divorced” with “irreconcilable differences,” they are a harmonious couple, inextricably entwined, cooperating and complementing each other. What mathematics has brought together, let no computer scientist put asunder! </li></ul></ul>
• 38. Applications of the Theory Automata and Regular Expressions to Programming COT 4810: Topics in Computer Science Spring 2003 Presentation by © Dr. David A. Workman School of EE & CS University of Central Florida March 3, 2003
• 39. Outline <ul><li>A Little History of Programming </li></ul><ul><li>A Little Review of Theory (COT 4210) </li></ul><ul><li>An Example Applying Theory to Practice </li></ul><ul><li>Summary and Conclusion </li></ul>
• 40. A Little History of Programming <ul><li>“ Flow Diagram, turing machines and languages with only two formation rules.” by Bohm and Jacopini, CACM Vol. 9, No. 5 (May 1966) </li></ul><ul><ul><li>Proved that all algorithms could be expressed using sequential execution assignment statements, conditional logic using if-then-else statements, and iteration using while statements. </li></ul></ul><ul><li>“ Goto Statements considered harmful,” by Edsgar Dijkstra , C ACM, Vol. 11, No. 3, March 1968, pp. 147-148. </li></ul><ul><ul><li>Contributions to the specification of ALGOL, 1957 – 60. </li></ul></ul><ul><ul><li>Cooperating Sequential Processes, 1966 </li></ul></ul><ul><ul><li>The THE Operating System, 1968 </li></ul></ul><ul><li>ACM/A.M. Turing Award Citation, February 5, 1999: </li></ul><ul><ul><li>“ Edsger Dijkstra was a principal contributor in the late 1950's to the development of the ALGOL, a high level programming language which has become a model of clarity and mathematical rigor. He is one of the principal exponents of the science and art of programming languages in general, and has greatly contributed to our understanding of their structure, representation, and implementation. His fifteen years of publications extend from theoretical articles on graph theory to basic manuals, expository texts, and philosophical contemplations in the field of programming languages. “ </li></ul></ul>
• 41. A Little Review of Theory <ul><li>Definition 1. A Deterministic Finite Automata (DFA) is a 5-tuple, M = (Q,  ,  , q 0 , A), where Q is a finite set of states,  denotes the input alphabet , q0 denotes the unique start state , A a finite, possibly empty set of Accept states , and the behavior of M is specified by its transition (computation) function  : Q   Q. </li></ul>We typically specify the behavior of a DFA, its d function, in the form of a State Transition Diagram such as the one shown below as an example. 1 5 4 3 2 start a b a a a a b b b b
• 42. A Little Review of Theory <ul><li>Definition 2. The Language Accepted by a DFA, is denoted L(M), and is given by L(M) = { x  * |   (q 0 , x)  A } </li></ul><ul><li>where the function ,   : Q   *  Q, is an extension of the transition function to strings over the input alphabet. </li></ul>What is L(M) for the DFA, M, given below??? L(M) = { a, ab, abaaaaba, aaaaaaba, …. } 1 5 4 3 2 start a b a a a a b b b b
• 43. A Little More Theory <ul><li>Definition 3. The Language of Regular Expression, E (  ), over alphabet  , is the set of strings over alphabet  ’ =   {  ,  ,  ,  ,  , ( , ) } given by the inductive definition: Basis:   {  ,  }  E (  ) . Inductive Rules: assume e, f  E (  ), then each of the following is a member of E (  ), [1] (e)* [2] (e  f) [3] (e  f) </li></ul>Definition 4. The Language defined by Regular Expression, e, is denoted L[e] and is defined recursively below. Basis: L[  ] =  (the empty set), and for e    {  }, L[ e ] = { e }. Inductive Rules: e, f, g  E (  ), [1] if e = (f)*, then L[e] = L[f]* (Kleene-star operation) [2] if e = (f  g), then L[e] = L[f]L[g] (Language concatenation) [3] if e = (f  g), then L[e] = L[f]  L[g] (Language union) Example. E ( {a,b} ) = {  ,  , a, b, (  )*, (  )*, (a)*, (b)*, (    ), (a  a), (b   ), (  +  ), (a +a), (b +  ), … (((a(ba))+(  )*)+(  ((  +  ))*))… } Example. L[ (((a(ba))+(  )*)+(  ((  +  ))*)) ] = {aba,  }
• 44. A Little Review of Theory <ul><li>What is the significance (relevance) of DFAs (and their theory) ? </li></ul><ul><li>What is the significance of Regular Expressions (RE)? </li></ul><ul><li>How do these mathematical abstractions apply to programming? </li></ul><ul><li>SOME ANSWERS </li></ul><ul><ul><li>DFAs are algorithmic abstractions </li></ul></ul><ul><ul><li>DFAs and REs can be used to model the lexical analysis function of real compilers </li></ul></ul><ul><ul><li>DFA’s recognize Regular languages </li></ul></ul><ul><ul><li>RE’s also define Regular Languages </li></ul></ul><ul><li>??? “Ho Hum, Yawn” </li></ul>This could be You!!!
• 45. Example Method (C++) <ul><li>void Server::Work() </li></ul><ul><li>{ </li></ul><ul><li>ifstream input; // input file stream </li></ul><ul><li>ofstream output; // output file stream </li></ul><ul><li>Tray tray; </li></ul><ul><li>cout << &quot;McDonald's Implementation in C++&quot; << endl; </li></ul><ul><li>cout << &quot;by XXXXXXXXXX and YYYYYYYYYYY&quot; << endl; </li></ul><ul><li>cout << endl; </li></ul><ul><li>while(1) { </li></ul><ul><li> string szInputFileName; </li></ul><ul><li> cout << &quot;Please enter the name of the input file: &quot;; </li></ul><ul><li> cin >> szInputFileName; </li></ul><ul><li> input.open(szInputFileName.c_str()); </li></ul><ul><li> if( !input ) alpha: { cerr << endl << &quot;No file named &quot; << szInputFileName << &quot; found.&quot; << endl; } </li></ul><ul><li> else break; </li></ul><ul><li>} </li></ul><ul><li>} //Server:: Work </li></ul>Insert Segment A (from next slide 1 2 3 5 4 6 16 A Basic Block of code is a sequence of declaration , assignment , and method call statements, that may optionally end with a goto or contional goto statement.
• 46. Example Method (C++) FoodItems *pFood; while(!input.eof()) { char szMarker[4]; input >> szMarker; strupper(szMarker); if(strcmp(szMarker, &quot;\$D&quot;) == 0) pFood = new Drinks; // drink else if(strcmp(szMarker, &quot;\$S&quot;) == 0) pFood = new Sandwiches; // sandwich else if(strcmp(szMarker, &quot;&quot;) == 0) continue; // blank line; skip else throw InputException(&quot;Unknown type found &quot; + string(szMarker)); pFood->Get(input); tray.Add_Item(pFood); } //while Segment A 6 7 8 9 10 11 12 13 14 15
• 47. Example Method (C++) 1 2 8 6 5 3 10 15 12 17 Exception exit Normal exit System exit 9 11 14 F T F F F F T T T T Notes: This is an example of a program flow graph, the subject of Bohm and Jacopini’s theorem. Even though this algorithm was written using a “structured style”, the flow graph is not completely structured in the purest sense since there are multiple method exits due to exceptions. 16 7 4 13
• 48. Example Method (C++) 1 2 8 6 5 3 10 15 12 Exception exit Normal exit 9 11 14 F T F F F F T T T T Notes: We have modified the structure version to make it violate the principles of structured design ( 13 => 5 ). To Re-Structure we apply the theory of DFAs and REs as follows: (1) All conditional nodes become “states” in a DFA. (2) Transitions between states are labeled with the sequential computation that connects any pair of conditional nodes. (3) Unique transition sequences become “letters” in the DFA alphabet. ! 16 7 4 13
• 49. Example Method (C++) a = 123 b = (4T)523 c = (4F)6 d = (7T)8 e = (9T)(10)(15) f = (9F) g = (11T)(12)(15) h = (11F) i = (13T523) j = (13F) k = (7F) start Exception exit Normal exit 9 11 14 a b c k d e f g h j i E 4 = a + E 4 b + E 13 i E 7 = E 4 c + E 9 e + E 11 g E 9 = E 7 d E 11 = E 9 f E 13 = E 11 h E 14 = E 13 j E 16 = E 7 k Define the following “alphabet” Set up a system of Regular Equations Solution for Paths = E 16 + E 14 E 16 = ab*c[d ( e + f (g + hib*c)) ]*k E 14 = ab*c[d ( e + f (g + hib*c)) ]*dfhj Paths = ab*c[d ( e + f (g + hib*c)) ]* (k+dfhj) 16 7 4 13
• 50. Expression => Code { boolean X; 1;3; //a (2 = true) while( 4 ) { 5; 3 } //b* 6; //c X := true; // Boolean variable for exception handling while ( X and 7 ) { //7T 8; //d if( 9 ) { //9T 10; 15 //e } else { //9F = f if( 11 ) { //11T 12;15 //g else{ //h if( 13 ) { //13T 5; 3 //i while( 4 ) { 5; 3} //b* 6; //c = (4F)6 } else X = false; //13F = exception condition }//11 - else }//9 - else }// while(7 and X) if( not X ) throw(exception); //j = abnormal end } //k = normal end Equivalent Structured Code a = 123 b = (4T)523 c = (4F)6 d = (7T)8 e = (9T)(10)(15) f = (9F) g = (11T)(12)(15) h = (11F) i = (13T523) j = (13F) k = (7F) Solution for Paths = E 16 + E 14 E 16 = ab*c[d ( e + f (g + hib*c)) ]*k E 14 = ab*c[d ( e + f (g + hib*c)) ]*dfhj Paths = ab*c[d ( e + f (g + hib*c)) ]* (k+dfhj)
• 51. Summary & Conclusion <ul><li>Summary (What are the main points?) </li></ul><ul><ul><li>DFAs and REs are more than just (equivalent) mathematical specifications for Regular Languages and algorithms for lexical analysis, they are useful for modeling algorithms of any kind and complexity. </li></ul></ul><ul><ul><li>Using algorithms for equivalence between DFAs and REs we were able to see why Bohm and Jacopini’s theorem is true, and why Dijkstra so strongly endorced the principles of structured programming. </li></ul></ul><ul><li>Conclusion (What have we learned?) </li></ul><ul><ul><li>The “marriage” between Theory and Practice is not “on the rocks”, this couple is not “legally separated” or “divorced” with “irreconcilable differences,” they are a harmonious couple, inextricably entwined, cooperating and complementing each other. What mathematics has brought together, let no computer scientist put asunder! </li></ul></ul>