Παράδειγμα: μορφοποίηση προγραμμάτων
Διομήδης Σπινέλλης
Τμήμα Διοικητικής Επιστήμης και Τεχνολογίας
Οικονομικό Πανεπιστήμιο Αθηνών
dds@aueb.gr
Ο κύκλος ζωής του λογισμικού
- Ανεπίσημες προδιαγραφές
- Επίσημες προδιαγραφές
- Αρχιτεκτονική σχεδίαση
- Λεπτομερής σχεδίαση
- Κωδικοποίηση
- Συνένωση
- Έλεγχος και δοκιμαστική λειτουργία
- Λειτουργία και συντήρηση
Ανεπίσημες προδιαγραφές
Να γραφεί ένα πρόγραμμα το οποίο να στοιχίζει σωστά προγράμματα γραμμένα
σε C.
Επίσημες προδιαγραφές
Να γραφεί ένα πρόγραμμα το οποίο θα θέτει σωστά τα κενά στην αρχή των
γραμμών.
Παράδειγμα εισόδου:
#include <stdio.h>
/*
* Play the bahm boom game:
* - print ascending numbers;
* - bahm's at 9 multiples;
* - boom's at 7 multiples;
*/
main()
{
int i;
for (i = 0; i < 100; i++) {
if (i % 9 == 0) {
printf("{BAHM}\n");
if (i % 9 == 0) {
printf("{BAHM}\n");
} else if (i % 7 == 0) {
printf("{BOOM}\n");
} else {
printf("%d\n", i);
}
}
}
Παράδειγμα εξόδου:
#include <stdio.h>
/*
* Play the bahm boom game:
* - print ascending numbers;
* - bahm's at 9 multiples;
* - boom's at 7 multiples;
*/
main()
{
int i;
for (i = 0; i < 100; i++) {
if (i % 9 == 0) {
printf("{BAHM}\n");
if (i % 9 == 0) {
printf("{BAHM}\n");
} else if (i % 7 == 0) {
printf("{BOOM}\n");
} else {
printf("%d\n", i);
}
}
}
}
- Υποθέτουμε ότι όλα τα for, if, while, do, else κλπ ακολουθούνται από εντολές
μέσα σε { }.
- Μετά από κάθε { η στοίχιση αυξάνει κατά ένα επίπεδο.
- Μετά από κάθε } η στοίχιση μειώνεται κατά ένα επίπεδο.
- Κατά την επεξεργασία σταθερών χαρακτήρων και συμβολοσειρών οι
παραπάνω δύο κανόνες δεν ισχύουν.
- Κατά την επεξεργασία σχολίων δεν αλλάζουμε τίποτα.
- Οι γραμμές που αρχίζουν με # δεν αλλάζουν καθόλου.
Αρχιτεκτονική σχεδίαση
- Θέλουμε με κάποιο τρόπο να ξέρουμε τι στοιχείο επεξεργαζόμαστε (
κανονικό πρόγραμμα, συμβολοσειρά, σταθερά χαρακτήρα, σχόλιο, κλπ).
- Αυτό εκφράζεται από την κατάσταση (state)
του προγράμματος.
- Η επεξεργασία για κάθε κατάσταση θα γίνεται χωριστά.
- Ορίζουμε τις παρακάτω καταστάσεις:
- NORMAL,
- HASH,
- SLASH,
- COMMENT,
- STAR,
- STRING,
- BACKSLASH_STRING,
- CHARACTER,
- BACKSLASH_CHARACTER,
- NEWLINE,
και το αντίστοιχο
διάγραμμα μετάπτωσης κατάστασης (state transition diagram)
- Στην αρχή της γραμμής αγνοούμε τα κενά και τυπώνουμε τα
δικά μας κενά.
- Οι χαρακτήρες { } αλλάζουν το επίπεδο στοίχισης.
- Η στοίχιση γίνεται από ξεχωριστή συνάρτηση.
Λεπτομερής σχεδίαση
- Σχεδιάζουμε το πλήρες διάγραμμα μετάπτωσης καταστάσεων.
- Κάθε χαρακτήρας που διαβάζεται στέλνεται στην αντίστοιχη
συνάρτηση επεξεργασίας.
- Στην κατάσταση NEWLINE χειριζόμαστε το θέμα της στοίχισης
πριν γίνει η μετάπτωση στην κατάσταση NORMAL.
- Στην κατάσταση NORMAL χειριζόμαστε την αλλαγή επιπέδου
στοίχισης με τα { και }.
Κωδικοποίηση
#include <stdio.h>
/* States the system can be in */
enum states {
NORMAL,
HASH,
SLASH,
COMMENT,
STAR,
STRING,
BACKSLASH_STRING,
CHARACTER,
BACKSLASH_CHARACTER,
NEWLINE,
};
/* Current state */
int state = NORMAL;
/* Current level of indent (tabs to print at the beginning of a line) */
int indent_level = 0;
/*
* Print tabs to indent the following character by indent_level
*/
void
indent(void)
{
int i;
for (i = 0; i < indent_level; i++)
putchar('\t');
}
/*
* State processing functions start here
*/
void
comment(char c)
{
putchar(c);
if (c == '*')
state = STAR;
}
void
slash(char c)
{
putchar(c);
if (c == '*')
state = COMMENT;
else
state = NORMAL;
}
void
string(char c)
{
putchar(c);
if (c == '"')
state = NORMAL;
else if (c == '\\')
state = BACKSLASH_STRING;
}
void
backslash_string(char c)
{
putchar(c);
state = STRING;
}
void
character(char c)
{
putchar(c);
if (c == '\'')
state = NORMAL;
else if (c == '\\')
state = BACKSLASH_CHARACTER;
}
void
backslash_character(char c)
{
putchar(c);
state = CHARACTER;
}
void
hash(char c)
{
putchar(c);
if (c == '\n')
state = NORMAL;
}
void
normal(char c)
{
putchar(c);
switch (c) {
case '#':
state = HASH;
break;
case '/':
state = SLASH;
break;
case '\'':
state = CHARACTER;
break;
case '"':
state = STRING;
break;
case '{':
indent_level++;
break;
case '\n':
state = NEWLINE;
break;
}
}
void
star(char c)
{
putchar(c);
if (c == '/')
state = NORMAL;
else
state = COMMENT;
}
void
newline(char c)
{
switch (c) {
case ' ':
case '\n':
case '\t':
break;
case '}':
indent_level--;
/* FALLTRHOUGH */
default:
indent();
state = NORMAL;
normal(c);
break;
}
}
/*
* Process a single character.
* Call the appropriate state handling function
*/
void
process(char c)
{
switch (state) {
case NORMAL:
normal(c);
break;
case COMMENT:
comment(c);
break;
case HASH:
hash(c);
break;
case SLASH:
slash(c);
break;
case STAR:
star(c);
break;
case STRING:
string(c);
break;
case BACKSLASH_STRING:
backslash_string(c);
break;
case NEWLINE:
newline(c);
break;
case CHARACTER:
character(c);
break;
case BACKSLASH_CHARACTER:
backslash_character(c);
break;
}
}
main()
{
int c;
while ((c = getchar()) != EOF)
process(c);
}
Έλεγχος μονάδων
Ασκήσεις
Η γλώσσα HTML
- Η HTML (Hypertext Markup Language) είναι η γλώσσα στην οποία γράφονται οι σελίδες στο World Wide Web.
Αποτελείται από κείμενο το οποίο εμφανίζεται στην οθόνη
του φυλλομετρητή (browser) και από
εντολές που περικλείονται μέσα σε < και >.
- Μερικές εντολές είναι οι παρακάτω:
- <p> Αλλαγή παραγράφου.
- <li> Αρχή νέας γραμμής σε λίστα
- <h1> Αρχή επικεφαλίδας επιπέδου 1
- <h2> Αρχή επικεφαλίδας επιπέδου 2
- Μπορείτε να δείτε το περιεχόμενο μιας σελίδας σε HTML με την
εντολή του φυλλομετρητή View - Source.
- Μπορείτε να φυλάξετε το περιεχόμενο μιας σελίδας στο δίσκο σας
σε μορφή HTML με την εντολή του φυλλομετρητή File - Save.
Εμφάνιση HTML
- Γράψτε ένα πρόγραμμα το οποίο τυπώνει στην οθόνη το
περιεχόμενο ενός αρχείου HTML με τον παρακάτω τρόπο:
- Όταν το κείμενο περνάει τη στήλη 60 να αλλάζει γραμμή
μετά το πρώτο τέλος λέξης.
- Οι υπόλοιπες αλλαγές σειράς μέσα στο αρχείο αγνοούνται.
- Η εντολή <p> να αρχίζει νέα σειρά
- Η εντολή <li> να αρχίζει νέα σειρά με τους χαρακτήρες "- "
- Η εντολή <h1> να τυπώνει σε νέα σειρά
τον αριθμό της επικεφαλίδας επιπέδου 1
και να τον αυξάνει κατά ένα.
Επιπλέον ξαναρχίζει την αρίθμηση των επικεφαλίδων επιπέδου 2 από
την αρχή.
- Η εντολή <h2> να τυπώνει σε νέα σειρά
τον αριθμό της επικεφαλίδας επιπέδου 1
ακολουθούμενο από "." και τον αριθμό της επικεφαλίδας επιπέδου 2 τον οποίο
και θα αυξάνει κατά ένα.
- Οι υπόλοιπες εντολές μέσα σε < > θα αγνοούνται.
- Οι εντολές μπορούν να δίνονται με κεφαλαία ή με μικρά γράμματα.
Έτσι για παράδειγμα οι εντολές <l> και <L> θα αντιμετωπίζονται
με τον ίδιο τρόπο.
- Δοκιμάστε το πρόγραμμά σας στο περιεχόμενο της σελίδας "παράδειγμα"
του κεφαλαίου αυτού των σημειώσεων.
- Σημείωση: Το πρόγραμμα δε χρειάζεται να εξετάζει αν οι εντολές με
τις οποίες ενεργεί περιέχουν μόνο τα συγκεκριμένα στοιχεία της εντολής.
Αφού συναντήσει την εντολή θα αγνοεί όλα τα υπόλοιπα στοιχεία της
μέχρι να συναντήσει >.
Έτσι για παράδειγμα οι εντολές <l> και <li> θα αντιμετωπίζονται
με τον ίδιο τρόπο.
Παράδειγμα εισόδου
<h1> Κύρια επικεφαλίδα</h1>
<h2> Επικεφαλίδα επιπέδου 2 </h2>
<p>
Κείμενο το οποίο
πρέπει
να εμφανίζεται στοιχισμένο μέχρι τη στήλη 60.
Οι
λέξεις
αυτές
δεν
πρέπει
να
εμφανίζονται
σε ξεχωριστές
γραμμές.
<p>
Εδώ αλλάζουμε γραμμή, αλλά η γραμμή αυτή είναι πάρα πολύ μεγάλη και πρέπει να σπάσει
<h2> Άλλη επικεφαλίδα επιπέδου 2 </h2>
<p>
Λίστα με στοιχεία (ένα σε κάθε γραμμή):
<ul>
<li> Στοιχείο 1 <LI> Στοιχείο 2
<li> Στοιχείο 3
<li> Στοιχείο 4
</ul>
Παράδειγμα εξόδου
1. Κύρια επικεφαλίδα
1.1. Επικεφαλίδα επιπέδου 2
Κείμενο το οποίο πρέπει να εμφανίζεται στοιχισμένο μέχρι τη στήλη
60. Οι λέξεις αυτές δεν πρέπει να εμφανίζονται σε ξεχωριστές γραμμές.
Εδώ αλλάζουμε γραμμή, αλλά η γραμμή αυτή είναι πάρα πολύ μεγάλη
και πρέπει να σπάσει
1.2. Άλλη επικεφαλίδα επιπέδου 2
Λίστα με στοιχεία (ένα σε κάθε γραμμή):
- Στοιχείο 1
- Στοιχείο 2
- Στοιχείο 3
- Στοιχείο 4
Βιβλιογραφία
- Alfred V. Aho, Ravi Sethi, and
Jeffrey D. Ullman.
Compilers,
Principles, Techniques, and Tools, chapter Lexical Analysis, pages
83-158.
Addison-Wesley, 1985.
- Joseph Arceneaux.
CUG392 --- GNU indent v1.8.
C Users Journal, 12(1):88, January 1994.
- T. Berners-Lee
and D. Connolly.
RFC 1866: Hypertext Markup
Language --- 2.0, November 1995.
- Roel Wieringa.
A survey of structured and object-oriented software specification methods and
techniques.
ACM Computing Surveys, 30(4):459-527, December 1998.
Παράδειγμα HTML
Επικεφαλίδα επιπέδου 2
Κείμενο το οποίο
πρέπει
να εμφανίζεται στοιχισμένο μέχρι τη στήλη 60.
Οι
λέξεις
αυτές
δεν
πρέπει
να
εμφανίζονται
σε ξεχωριστές
γραμμές.
Εδώ αλλάζουμε γραμμή, αλλά η γραμμή αυτή είναι πάρα πολύ μεγάλη και πρέπει να σπάσει
Άλλη επικεφαλίδα επιπέδου 2
Λίστα με στοιχεία (ένα σε κάθε γραμμή):
- Στοιχείο 1
- Στοιχείο 2
- Στοιχείο 3
- Στοιχείο 4
HTML example (english)
Heading level 2
Text that should appear wrapped at column 60.
These
words
should
not
be
spread
on
single
lines.
A new paragraph begins at this point, but this line is quite long and should be split.
Another heading level 2
Element list (one per line):
- Element 1
- Element 2
- Element 3
- Element 4