220 likes | 337 Vues
This lecture from the Art of Design series at Northwestern University explores essential programming concepts, focusing on data flow, top-down versus bottom-up design strategies, and refining design from coarse to fine. It emphasizes the importance of flowcharts in organizing thoughts and streamlining programming tasks. Key topics include incremental programming, task decomposition, and error checking within data representation. Through practical examples, students will learn to structure their programs effectively, thereby enhancing their ability to debug and validate their code.
E N D
ECE230 Lectures Series The Art of Design Ying Wu Electrical & Computer Engineering Northwestern University yingwu@ece.northwestern.edu
Outline • Data flow • Top-down vs. bottom-up • Coarse to fine • Two examples • MP#1 • MP#2
Data Flow • Data • data representation describe your inputs/outputs • E.g. 1: a segment of command line? • E.g. 2: the set of operators? • Inputs and outputs of the building blocks • what are given? • what are expected? • Data flow • blocks are connected through data flow
Flow chart • Coding is a very very small part of programming • design 40% • coding 10% • debugging 50% • When you start to work • always draw flow charts • organize your thoughts by flow charts • use testing cases to validate your flow charts
Top-down • “Incremental” programming • Divide-and-conquer • Task decomposition • No matter how small a task is, you can always divide it into a set of small sequential subtasks • You need to understand your tasks • Focus • Make the structure clear and neat • Always use the basic controls • Sequential • Selection • repetitive
Coarse to Fine • Coarse Fine • Coarse design • determines the structure of the program • tells the basic idea • details are all ignored • concentrate on data flow • Organize it by subtasks • Refinement • A rough “block” can always by replaced by a refined flowchart • It is much easier, because the tasks are simpler
Bottom-up • “Brain-storming” programming • Bottom design • creating a set of small “tools” • thinking based on “basic operations” • Bottom Up • putting tools together • this needs more experiences
“Tools” • Extracting those basic operations • E.g. 1: bypass all “white spaces” • E.g. 2: check digits • Forming functions • inputs • outputs • error checking
Before you start … • Data representation? • How do you represent a “segment”? • st/ed • Your objectives? • Find a segment determine st/ed
End of the string? Command line buffer[500] Y N Find the first element of a seg. done Find the last element of the seg. Start the next segment Copy the segment to piece[100] piece screen A Coarse Design
Code it int main() { cout << “Welcome bla bla bla” << endl; char buffer[500]; cout << "\nInput a command line: "; cin.getline(buffer, 500); char piece[500]; int st = 0, ed = 0; while( buffer[st]!=0 ){ st = _find_the_first_element( ); ed = _find_the_last_element( st ); _copy_segment(piece, st, ed); _display_segment(piece); st = ed + 1; } return 0; }
End of the string? Checking after actions Command line buffer[500] Y N Find the first element of a seg. N Successful? Y Find the last element of the seg. N Start the next segment Successful? Y Copy the segment to piece[100] Error piece screen
Code it int main() { cout << “Welcome bla bla bla” << endl; char buffer[500]; cout << "\nInput a command line: "; cin.getline(buffer, 500); char piece[500]; int st = 0, ed = 0, err_code = 1; while( buffer[st]!=0 ){ st = _find_the_first_element( ); if (buffer[st] == 0) err_code = 0; ed = _find_the_last_element( st ); // err_code can be set inside if (err_code == 0) break; else { _copy_segment(piece, st, ed); _display_segment(piece); st = ed + 1; } } return err_code; }
st st Find the first element of a seg. ‘ ‘ ‘v ‘ ‘ a‘ ‘ r‘ ‘ _‘ ‘ 1‘ ‘ ‘ ‘ ‘ ‘ a‘ ‘ ‘ ‘ +‘ ‘ ‘ ‘3‘ ‘ .‘ ‘ 1‘ ‘ 4‘ ‘ ‘ 0 buffer[0] st Y buffer[st] == ‘ ‘ && buffer[st] != 0 st ++ N st Coarse-to-fine
Is buffer[st] a letter? st ed Find the first element of a seg. init ed = st Is buffer[st] a ‘[‘? Is buffer[st] a digit? Is buffer[st] a ‘:’? Y N Is buffer[st] an operator? Scan to find ed N Y N Y Scan to find ed Y Scan to find ed Y Scan to find ed err_code = 0 Scan to find ed ed and err_code Coarse-to-fine
buffer[st] = ‘[‘ ed Scan to find ed init ed = st+1 buffer[ed] != ‘]’ Conditions for buffer[ed] err_code = 0 break ed ++ Go even finer
Put things together • From coarse-to-fine • always draw flowcharts • keep all your flowchart • Adding things little by little • don’t put together all at once • Validate the new components • whenever you refine a block, always debug it and make sure the whole thing is correct • keep the structure of the program clear
Data Representation (MP#2) • Attention, we only check 4 types of valid grammars. • assignment: "operand_1 = operand_2", e.g., a = 1 • binary operation: "operand_1 operator operand_2", e.g., a + b • unary operation: "operand_1 operator", e.g., a++ • assignment and binary operation: "result = operand_1 operator operand_2", e.g., a = b + c • According to that, we can define • Operations, (e.g., +, -, *, /, ++, --) • Operation types. (e.g., assignment, unary, binary) • So, enum OP {ASN, ADD, MIN, MUL, DIV, INC, DEC}; enum OP_TYPE {asn, unary, binary};
Quit ? Successful? Print version/welcome Y N Command line buffer[500] done Resolve a statement error Y “understand” a statement A Coarse Design
# of pieces result_name operator_name operator_type operand_1 operand_2 Data Flow Resolve a statement ( ) Understand a statement ( ) CL_buffer[] err_code
piece[ ] buffer[ ] Read_a_Piece( ) start_from err_code c c c T/F T/F T/F Is_Char_a_Letter( ) Is_Char_a_Digit( ) Is_Char_a_Operator( ) Tools Use MP#1
Coarse-to-fine • Resolve_a_Statement • T1: scanning to determine the # of pieces • T2: finding operators • T3: grammar check • T4: finding two operands (based on T1/T2) • Understand_a_Statement • Switch/case based on op type • Simply translate and print them out