From feb76874bfcc2b9e2652bd561877f0ac51dde48d Mon Sep 17 00:00:00 2001 From: Lutz Kettner Date: Fri, 20 Dec 1996 16:19:53 +0000 Subject: [PATCH] Last revision before Christmas 1996. This version is send out to the kernel developers. It contains the new naming scheme \ccX... --- Packages/Manual_tools/src/cc_build_checker.C | 289 +++++++++++++++++-- Packages/Manual_tools/src/cc_extract.C | 42 ++- 2 files changed, 303 insertions(+), 28 deletions(-) diff --git a/Packages/Manual_tools/src/cc_build_checker.C b/Packages/Manual_tools/src/cc_build_checker.C index aca2947f634..d157ed9a67b 100644 --- a/Packages/Manual_tools/src/cc_build_checker.C +++ b/Packages/Manual_tools/src/cc_build_checker.C @@ -1,9 +1,15 @@ /************************************************************************** - cgal_build_checker.cc + cc_build_checker.cc ============================================================= Project : CGAL tool that constructs the specification checker - Function : main program, command line parameter parsing + Function : Checks whether the C++ declarations from a TeX + specification file written with the cc_manual.sty + really exists in a C++ header file. This program + extracts a flex program from a TeX specification + that does the actual checking. This program is used + with a script `cc_check' that is provided for the user. + main program, command line parameter parsing System : bison, flex, C++ (g++) Author : (c) 1995 Lutz Kettner Revision : $Revision$ @@ -15,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -45,6 +52,8 @@ void yyparse(); void init_scanner( FILE* in); extern int line_number; extern int unchecked_tag; +extern char* global_classname; +extern char* global_template_params; /* Name the scanned file */ /* ===================== */ @@ -56,11 +65,23 @@ const char* error_filename; /* Buffer to hold an appropriate error message */ Buffer* errmessage = new Buffer; +/* the n_class that counts the actual class */ +int n_class = 0; + + /* Buffer to hold the pattern to be scanned for */ /* Only necessary for special patterns */ Buffer* pattern = new Buffer; Buffer* pattern2 = new Buffer; +/* Buffer to hold a generalized function declaration where + in the parameter lists variable names are substituted by the + special constant IDFIER_TAG + */ +Buffer* function_decl = new Buffer; +const char IDFIER_TAG = 254; +const char INLINE_TAG = 253; + /* Number of pattern's written */ int n_pattern = 0; @@ -75,6 +96,10 @@ char char_tricky_tmp[16] = "\"{ws}*\" \"{ws}*\""; const char* patternText( char c, char d = 'X') { switch ( c) { + case IDFIER_TAG: + return "\"{idfier}\""; + case INLINE_TAG: + return "\"{ws}*\">\"{ws}*(inline)?{ws}*\""; case ' ': case '\t': case '\r': @@ -94,10 +119,10 @@ const char* patternText( char c, char d = 'X') { case '>': case '*': case '&': - if ( d != ' ') { - char_tricky_tmp[7] = c; - return char_tricky_tmp; - } + // if ( d != ' ') { + char_tricky_tmp[7] = c; + return char_tricky_tmp; + // } break; } char_tmp[0] = c; @@ -107,7 +132,7 @@ const char* patternText( char c, char d = 'X') { void printProlog( ostream& out_pattern, ostream& out_errmessage) { int i; out_pattern << "/* =============================================" << endl; - out_pattern << " CGAL checker program to verify consistency" << endl; + out_pattern << " CC checker program to verify consistency" << endl; out_pattern << " between specification and implementation." << endl; out_pattern << " Generated for the specification:" << endl; out_pattern << " `" << file_name; @@ -116,12 +141,12 @@ void printProlog( ostream& out_pattern, ostream& out_errmessage) { } out_pattern << "'" << endl; out_pattern << endl; - out_pattern << " R 1.1 28.10.1995 Lutz Kettner" << endl; - out_pattern << " kettner@inf.fu-berlin.de" << endl; - out_pattern << " FU Berlin, Germany." << endl; + out_pattern << " R 1.2 03.12.1996 Lutz Kettner" << endl; + out_pattern << " kettner@acm.org" << endl; + out_pattern << " ETH Zurich, Switzerland" << endl; out_pattern << endl; - out_pattern << " Compilation with `flex' and `cc'" << endl; - out_pattern << "============================================= */" << endl; + out_pattern << " Compilation with `flex' and `cc' (or `gcc')" << endl; + out_pattern << "============================================== */" << endl; out_pattern << endl; out_pattern << "%{" << endl; out_pattern << "#include " << endl; @@ -132,6 +157,9 @@ void printProlog( ostream& out_pattern, ostream& out_errmessage) { out_pattern << "/* the tag array that collects correct matches */" << endl; out_pattern << "int *tags;" << endl; out_pattern << endl; + out_pattern << "/* the n_class that counts the actual class */" << endl; + out_pattern << "int n_class = -1;" << endl; + out_pattern << endl; out_pattern << "/* the name array that stores the filename */" << endl; out_pattern << "const char **name;" << endl; out_pattern << endl; @@ -179,8 +207,10 @@ void printProlog( ostream& out_pattern, ostream& out_errmessage) { out_pattern << "fwcomment [@][!].*$" << endl; out_pattern << "ws [ \\t\\n\\r]|{cccommentnl}" << endl; out_pattern << "nol [^a-zA-Z0-9_]" << endl; + out_pattern << "classend {ws}*(([:][^:])|([{]))" << endl; out_pattern << "optionalclass {ws}*(class{ws}*)?" << endl; out_pattern << "optionalkeywords ([a-z]+({ws}+[a-z]+)*)?" << endl; + out_pattern << "idfier [a-zA-Z_][a-zA-Z0-9_]*" << endl; out_pattern << endl; out_pattern << "%%" << endl; out_pattern << " /* The matching rules */" << endl; @@ -219,7 +249,7 @@ void printProlog( ostream& out_pattern, ostream& out_errmessage) { out_errmessage << "/* =============================================" << endl; - out_errmessage << " CGAL checker program to verify consistency" << endl; + out_errmessage << " CC checker program to verify consistency" << endl; out_errmessage << " between specification and implementation." << endl; out_errmessage << " Generated for the specification:" << endl; out_errmessage << " `" << file_name; @@ -228,9 +258,9 @@ void printProlog( ostream& out_pattern, ostream& out_errmessage) { } out_errmessage << "'" << endl; out_errmessage << endl; - out_errmessage << " R 1.1 28.10.1995 Lutz Kettner" << endl; - out_errmessage << " kettner@inf.fu-berlin.de" << endl; - out_errmessage << " FU Berlin, Germany." << endl; + out_errmessage << " R 1.2 03.12.1996 Lutz Kettner" << endl; + out_errmessage << " kettner@acm.org" << endl; + out_errmessage << " ETH Zurich, Switzerland" << endl; out_errmessage << endl; out_errmessage << " Auxiliary file for the pattern texts." << endl; out_errmessage << "============================================= */" @@ -249,6 +279,8 @@ void printEpilog( ostream& out_pattern, ostream& out_errmessage) { out_pattern << " int i;" << endl; out_pattern << " int err = 0;" << endl; out_pattern << " int flags = 1;" << endl; + out_pattern << " int err_count = 0;" << endl; + out_pattern << " int warn_count = 0;" << endl; out_pattern << " tags = (int*)malloc( " << n_pattern << " * sizeof( int));" << endl; out_pattern << " name = (const char**)malloc( " << n_pattern @@ -323,16 +355,25 @@ void printEpilog( ostream& out_pattern, ostream& out_errmessage) { out_pattern << " for ( i=0; i<" << n_pattern << "; i++) {" << endl; out_pattern << " if ( tags[i] == 0) {" << endl; out_pattern << " err = 2;" << endl; + out_pattern << " err_count++;" << endl; out_pattern << " fprintf( stderr, \"check error: %s cannot " "be found in the implementation.\\n\", patternText( i));" << endl; out_pattern << " } else if ( tags[i] > 0) {" << endl; out_pattern << " err = 3;" << endl; + out_pattern << " warn_count++;" << endl; out_pattern << " fprintf( stderr, \"check warning: %s only " "recognized as prefix in `%s' line %d.\\n\", " "patternText( i), name[i], tags[i]);" << endl; out_pattern << " }" << endl; out_pattern << " }" << endl; + out_pattern << " if ( err_count || warn_count) {" << endl; + out_pattern << " fprintf( stderr, \"---------------------" + "----------------------------------\\n\"); " << endl; + out_pattern << " fprintf( stderr, \"%d error(s) and %d warning(s)" + ".\\n\\n\", err_count, warn_count); " << endl; + out_pattern << " " << endl; + out_pattern << " }" << endl; out_pattern << " free( tags);" << endl; out_pattern << " free( name);" << endl; out_pattern << " return err;" << endl; @@ -513,12 +554,23 @@ void printFunctionPattern( ostream& out_pattern, out_errmessage << " return \"line " << line_number << " in `" << file_name << "': \\\""; for ( i=0; i"; + break; + default: out_errmessage << str[i]; + break; + } } out_errmessage << "\\\"\";" << endl; @@ -527,6 +579,144 @@ void printFunctionPattern( ostream& out_pattern, +/* Translate argument names in function declarations to idfiers */ +/* ============================================================ */ + +// Given a string interval, decide whether it contains a valid type name +// or only declarative keywords and other symbols. This check is necessary +// to distinguish between function arguments with and without argument +// name. +bool isTypeInFunctionArgument( const char* s, const char* end) { + while( s != end) { + // isolate identifier + while( s != end && ( !isalpha(*s) && *s != '_')) + s++; + const char* p = s; // idfier start + while( s != end && ( isalpha(*s) || *s == '_')) + s++; + if ( s == p) + return false; + bool is_keyword = false; + is_keyword = is_keyword || 0 == strncmp( p, "auto", 4); + is_keyword = is_keyword || 0 == strncmp( p, "class", 5); + is_keyword = is_keyword || 0 == strncmp( p, "const", 5); + is_keyword = is_keyword || 0 == strncmp( p, "enum", 4); + is_keyword = is_keyword || 0 == strncmp( p, "extern", 6); + is_keyword = is_keyword || 0 == strncmp( p, "register", 8); + is_keyword = is_keyword || 0 == strncmp( p, "signed", 6); + is_keyword = is_keyword || 0 == strncmp( p, "static", 6); + is_keyword = is_keyword || 0 == strncmp( p, "struct", 6); + is_keyword = is_keyword || 0 == strncmp( p, "template", 8); + is_keyword = is_keyword || 0 == strncmp( p, "union", 5); + is_keyword = is_keyword || 0 == strncmp( p, "unsigned", 8); + is_keyword = is_keyword || 0 == strncmp( p, "volatile", 8); + if (!is_keyword) + return true; + } + return false; +} + +// Scan a full C++ function declaration in decl. Return value in func. +// Scans argument by argument and replaces the argument name by a symbol +// denoting an idfier. The output routine replaces this symbol with the +// actual regular expression for an identifier. +void translateFunctionArgumentLists( const char* decl, Buffer *func) { + func->flush(); + const char* current = decl; + while ( *current != '(') { + current++; + ADT_Assert( *current); + } + ADT_Assert( *current == '('); + current++; + ADT_Assert( *current); + func->add( decl, current - decl); + + /* the parsing starts here. It counts parenthesis. */ + int nesting = 1; + bool in_init = false; + const char* from = current; + const char* last_idfier = current - 1; + while ( nesting > 0) { + ADT_Assert( *current); + if ( nesting == 1 && *current == '=') + in_init = true; + if ( nesting == 1 + && !in_init + && (isalnum(*current) || *current == '_')) + last_idfier = current; + + if ( nesting == 1 && (*current == ',' || *current == ')')) { + if ( last_idfier - from < 0) { + /* fail save behavior in case of errors */ + func->add( from, current-from+1); + } else { + const char* p = last_idfier; + while( isalnum( *p) || *p == '_') + p--; + p++; /* points to idfier start */ + ADT_Assert( p - from >= 0); + if ( isTypeInFunctionArgument( from, p)) { + func->add( from, p - from); + func->add( IDFIER_TAG); + func->add( last_idfier + 1, current - last_idfier); + } else { + /* fail save behavior in case of errors */ + func->add( from, current-from+1); + } + } + from = current + 1; + if (*current == ')') + nesting--; + in_init = false; + } else { + switch ( *current) { + case '(': + case '<': + nesting++; + break; + case ')': + case '>': + nesting--; + ADT_Assert( nesting >= 1); + break; + } + } + current++; + } + func->add( from); +} + +// Check whether the declaration starts with a template keyword, and +// if so, use the INLINE_TAG to add the regular expression for an optional +// inline keyword right after the template declaration. +void checkTemplateKeyword( Buffer *decl){ + if( 0 == strncmp( "template", decl->string(), 8)) { + const char* p = decl->string() + 8; + int nesting = 0; + while( *p != '\0') { + switch( *p) { + case '<': + case '(': + nesting ++; + break; + case ')': + nesting --; + break; + case '>': + nesting --; + if ( nesting == 0) { + decl->set( p - decl->string(), INLINE_TAG); + return; + } + break; + } + p++; + } + } +} + + /* Taylored semantic functions used in syntax.y */ /* ============================================ */ @@ -539,18 +729,33 @@ void handleComment( const Text& ) { } void handleClass( const char* classname) { + if ( global_classname) + free( global_classname); + global_classname = strdup( classname); errmessage->flush(); errmessage->add( "class "); errmessage->add( classname); errmessage->add( " "); - printPattern( *p_out_pattern, *p_out_errmessage, errmessage); + pattern->flush(); + pattern->add( "class{ws}+\""); + pattern->add( classname); + pattern->add( "\"{classend}"); + printPattern( *p_out_pattern, *p_out_errmessage, errmessage, pattern); } void handleClassEnd( void) { + if ( global_classname) + free( global_classname); return; } void handleClassTemplate( const char* classname) { + if ( global_classname) + free( global_classname); + global_classname = strdup( classname); + global_template_params = global_classname; + while( *global_template_params && *global_template_params != '<') + ++global_template_params; errmessage->flush(); pattern->flush(); errmessage->add( "template < ..."); @@ -607,11 +812,14 @@ void handleClassTemplate( const char* classname) { pattern->add( *s); s++; } - pattern->add( "\"{nol}"); + pattern->add( "\"{classend}"); printPattern( *p_out_pattern, *p_out_errmessage, errmessage, pattern); } void handleClassTemplateEnd( void) { + global_template_params = 0; + if ( global_classname) + free( global_classname); return; } @@ -629,7 +837,42 @@ void handleDeclaration( const char* decl) { printPattern( *p_out_pattern, *p_out_errmessage, errmessage); } +void handleNestedType( const char* decl) { + errmessage->flush(); + int l = strlen( decl); + while ( l > 0 && decl[ l-1] == ' ') l--; + errmessage->add( decl, l); + pattern->flush(); + pattern->add( "typedef{ws}*[^;]+"); + pattern->add( decl, l); + pattern->add( "{ws}*;"); + // Sorry, not working in full general. + // pattern->add( "{ws}*;)|(((struct)|(class)){ws}*"); + // pattern->add( decl, l); + // pattern->add( "{ws}*[:\\{;])"); + printPattern( *p_out_pattern, *p_out_errmessage, errmessage, pattern); +} + +void handleMethodDeclaration( const char* decl) { + translateFunctionArgumentLists( decl, function_decl); + checkTemplateKeyword( function_decl); + decl = function_decl->string(); + errmessage->flush(); + int l = strlen( decl); + while ( l > 0 && decl[ l-1] == ' ') l--; + if ( decl[ l-1] != ';' ) + printErrorMessage( SemicolonMissingError); + else + l--; + while ( l > 0 && decl[ l-1] == ' ') l--; + errmessage->add( decl, l); + printFunctionPattern( *p_out_pattern, *p_out_errmessage, errmessage); +} + void handleFunctionDeclaration( const char* decl) { + translateFunctionArgumentLists( decl, function_decl); + checkTemplateKeyword( function_decl); + decl = function_decl->string(); errmessage->flush(); int l = strlen( decl); while ( l > 0 && decl[ l-1] == ' ') l--; @@ -643,6 +886,8 @@ void handleFunctionDeclaration( const char* decl) { } void handleFunctionTemplateDeclaration( const char* templ, const char* decl) { + translateFunctionArgumentLists( decl, function_decl); + decl = function_decl->string(); errmessage->flush(); pattern->flush(); pattern2->flush(); @@ -784,7 +1029,7 @@ main( int argc, char **argv) { (nParameters > MaxParameters) || (help_switch != NO_SWITCH)) { if (help_switch == NO_SWITCH) cerr << "Error: in parameter list" << endl; - cerr << "Usage: cgal_build_checker [] " + cerr << "Usage: cc_build_checker [] " " []" << endl; cerr << " -trace sets the `yydebug' variable of bison" << endl; diff --git a/Packages/Manual_tools/src/cc_extract.C b/Packages/Manual_tools/src/cc_extract.C index 9d4a9103831..6f360d36d5a 100644 --- a/Packages/Manual_tools/src/cc_extract.C +++ b/Packages/Manual_tools/src/cc_extract.C @@ -1,9 +1,11 @@ /************************************************************************** - cgal_extract.cc + cc_extract.C ============================================================= Project : CGAL merger tool for the specification task - Function : main program, command line parameter parsing + Function : Extract C++ declarations from a TeX specification + file written with the cc_manual.sty. + Main program, command line parameter parsing. System : bison, flex, C++ (g++) Author : (c) 1995 Lutz Kettner Revision : $Revision$ @@ -30,6 +32,7 @@ Switch nomc_switch = NO_SWITCH; Switch nosc_switch = NO_SWITCH; + /* Declarations from syntax.y */ /* ========================== */ extern int yydebug; @@ -38,6 +41,8 @@ void yyparse(); /* Declarations from lex.yy */ /* ========================== */ void init_scanner( FILE* in); +extern char* global_classname; +extern char* global_template_params; /* Name the scanned file */ @@ -69,6 +74,9 @@ void handleComment( const Text& T) { } void handleClass( const char* classname) { + if ( global_classname) + free( global_classname); + global_classname = strdup( classname); cout << indNewline; cout << "class " << classname << " {" << indNewline; cout << "public:" << indNewline; @@ -76,12 +84,20 @@ void handleClass( const char* classname) { } void handleClassEnd( void) { + if ( global_classname) + free( global_classname); cout << outdent; cout << indNewline; - cout << "}" << indNewline; + cout << "};" << indNewline; } void handleClassTemplate( const char* classname) { + if ( global_classname) + free( global_classname); + global_classname = strdup( classname); + global_template_params = global_classname; + while( *global_template_params && *global_template_params != '<') + ++global_template_params; cout << indNewline; cout << "template < class "; const char* s = classname; @@ -130,9 +146,12 @@ void handleClassTemplate( const char* classname) { } void handleClassTemplateEnd( void) { + global_template_params = 0; + if ( global_classname) + free( global_classname); cout << outdent; cout << indNewline; - cout << "}" << indNewline; + cout << "};" << indNewline; } @@ -141,6 +160,16 @@ void handleDeclaration( const char* decl) { cout << decl; } +void handleNestedType( const char* decl) { + cout << endl << indNewline; + cout << "Nested type required: " << global_classname << "::" << decl; +} + +void handleMethodDeclaration( const char* decl) { + cout << endl << indNewline; + cout << decl; +} + void handleFunctionDeclaration( const char* decl) { cout << endl << indNewline; cout << decl; @@ -252,12 +281,13 @@ main( int argc, char **argv) { (nParameters > MaxParameters) || (help_switch != NO_SWITCH)) { if (help_switch == NO_SWITCH) cerr << "Error: in parameter list" << endl; - cerr << "Usage: cgal_extract [] [ ...]" << endl; + cerr << "Usage: cc_extract [] [ ...]" << endl; cerr << " -nomc no main comments" << endl; cerr << " -nosc no sub comments" << endl; cerr << " -noc no comments (main and sub)" << endl; cerr << " -trace sets the `yydebug' variable of bison" << endl; + cerr << " -h, -help this help message" << endl; exit(1); } @@ -266,7 +296,7 @@ main( int argc, char **argv) { FILE* in; if ( (in = fopen( parameters[i], "r")) == NULL) { fprintf( stderr, - "\ncgal_extract: error: cannot open infile %s.\n", + "\ncc_extract: error: cannot open infile %s.\n", parameters[i]); exit(1); }