1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: hidclex.l,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // Suppress any warnings from generated code:
33 #pragma GCC system_header
34 #elif defined __SUNPRO_CC
36 #elif defined _MSC_VER
37 #pragma warning(push, 1)
40 static char const Revision[] = "$Revision: 1.9 $" ;
55 XX XXXX XXX XX XX XXX XXX XX XXXXX XX XXX
56 XX XX XX XX X XX XX XX XX XX XX X XXX XX
57 XX X XX XX XX X XX XX XX XX XX XXXXXXX XX
58 XX XX XX XX XX XX XXXXX XX XX XX XX
59 XXXX XXXX XXX XXX XX XXXX XXXX XXXXX XXXX
65 /* length of buffer for reading with lex */
67 /* enlarge token buffer to tokenize whole strings */
71 int exclude_bracelevel=0; /* count braces in that start state */
72 static YY_BUFFER_STATE InputFiles[127]; // for recursive parse
73 static int nInputFileDepth = 0;
83 static bool bVerbose = false;
84 void freestring( char const * ); //forward
86 char* dot2underline( char* str )
88 size_t len=strlen(str);
89 for( size_t i=0; i<len; i++ )
90 if( str[i]=='.' ) str[i]='_';
94 void dotappend( char*& base, char const * suffix )
96 // append like "str.suffix" if suffix else "str"
102 if( (siz=strlen(suffix)) == 0 )
105 size_t siz2 = base==NULL ? 0 : strlen(base);
109 {//do never forget to increment/decrement alloc_cnt
110 newstr = (char*) malloc( (siz2+siz+1) +1 /*for "." */ );
115 fprintf( stderr,"error: dotappend() could not malloc() \n"), exit(1);
118 strcpy( newstr, base );
124 strcat( newstr, "." );
125 strcat( newstr, suffix );
129 void dotsubtract( char*& base, char const * suffix )
131 // remove dotted suffix from base.suffix --> base
133 if( base == NULL || suffix == NULL )
135 if( strlen(suffix) == 0 )
137 if( (strlen(suffix)+1) > strlen(base) )
139 char * pos=strstr( base, suffix);
140 if( pos && (pos-1 >= base) && ( *(pos-1) == '.') )
141 if( *(pos+strlen(suffix)) == '\0' ) //only if at end of base
147 char levelbuffer[512];
149 void adjust_levelbuffer()
152 for(i=0; i<level;i++) {
153 levelbuffer[i] = '\t';
155 levelbuffer[i] = '\0';
158 void freestring( char const * ptr )
161 adjust_levelbuffer();
163 fprintf(stdout,"%sinfo: freestring line %d\n",levelbuffer, __LINE__);
164 free(const_cast< char * >(ptr)), ptr = NULL;
167 void makestring(char** newstr, char* oldstr)
170 adjust_levelbuffer();
172 fprintf(stdout,"%sinfo: makestring on line %d\n",levelbuffer,__LINE__);
173 strcpy( (*newstr=(char*)malloc(strlen(oldstr)+1)), oldstr);
174 if( *newstr==NULL ) {
176 "error: cannot malloc for makestring() alloc_cnt==%d \n", alloc_cnt);
182 int strcmpi(char const * stra, char const * strb)
184 // like strcmp() but case insensitive
188 a = (char) tolower(stra[i]);
189 b = (char) tolower(strb[i]);
194 if( a == '\0' && b == '\0' )
200 /* variables for listfile ( with project + pathname of src file ) */
202 #define MAXSRCFILES 2048
203 char* filename_tab[MAXSRCFILES];
204 char* project_tab[MAXSRCFILES];
206 //int fileno = 0; /* currently used filenumber */
208 /* globale variablen */
210 char const *filename = ""; //incl. path
211 //char *basename = "";
212 char const *project = "";
213 char const *subpath = ""; //from project name downwards like source\ui\xxx.src
222 //nicht aendern wg externer Abfrage ->size() == 2
231 for(int i=0; i<MAXRING;i++)
238 for(int i=0; i<MAXRING;i++) {
239 if( ring[i] != NULL )
240 freestring( ring[i] );
245 void set_broken() { broken = 1; }
263 char* extract_last(){
267 char* ttt=ring[last];
273 char* extract_actual() {
277 char *ttt=ring[ringpos];
284 ringpos= (++ringpos) % MAXRING;
285 if( ring[ringpos] != NULL )
286 freestring( ring[ringpos] ); /*otherwise: memory lost*/
287 ring[ ringpos ] = id;
290 "info: ring[%d] == %s broken==%d \n"
291 ,ringpos,ring[ringpos],broken
294 if( !(ringpos==0 && last==-1) )
295 last = (++last) % MAXRING;
300 /* Notnagel: die letzten identifier/number merken, fuer klasse & globalID */
306 #define TOK_SEMICOLON ';'
307 #define TOK_EQUAL '='
308 #define TOK_OPENBRACKET '['
309 #define TOK_CLOSEBRACKET ']'
310 #define TOK_OPENBRACE '{'
311 #define TOK_CLOSEBRACE '}'
312 #define TOK_KOMMA ','
314 #define TOK_GREATER '>'
315 #define TOK_OPENPAREN '('
316 #define TOK_CLOSEPAREN ')'
318 #define TOK_MINUS '-'
320 #define TOK_SLASH '/'
322 #define TOK_POSorSIZE 146
323 #define TOK_POSSIZE 147
324 #define TOK_TEXTTAG 148
325 #define TOK_IDNUM 149
327 #define TOK_EXTRADATA 151
329 #define TOK_MESSAGE 153
330 #define TOK_HELPTEXT 154
332 #define TOK_FALSE 156
334 #define TOK_RESID 180
336 #define TOK_STRING 190
338 #define TOK_INVALID (-1)
340 token lasttoken = TOK_INVALID;
347 char *globalID = const_cast< char * >("");
348 char const *globalKLASSE = NULL;
350 void reset_globalID() {
352 if( globalID && (strlen(globalID) > 0 ) ) {
353 freestring( globalID );
354 globalID = const_cast< char * >("");
359 //--------------------------------------------------------------------
363 resource ( const resource& ); //copy-ctor soll keiner benutzen
364 void operator=( const resource& ); // zuweisung auch nicht
370 token lasttoken; //before opening {
377 resource *ares ; /* aktuell bearbeitete resource */
379 resource::~resource()
381 if( klasse != NULL ) freestring(klasse);
382 if( localID != NULL ) freestring(localID);
383 if( helpID != NULL ) freestring(helpID);
390 lasttoken= TOK_INVALID;
397 int residfound = 0; // "Identifier = " auf momentanem level gefunden
400 resource* stack[MAXSTACK]; /* resource stack */
401 #define EMPTYSTACK (-1)
402 int stackptr = EMPTYSTACK;
404 void push_resource( resource* r )
407 if( stackptr >= MAXSTACK ) {
408 fprintf( stderr, "error: resource stack is full %d \n", stackptr);
411 stack[ stackptr ] = r;
414 resource* pop_resource()
417 fprintf( stderr, "error: pop resource from empty stack \n");
420 return stack[ stackptr-- ];
425 int eat_cpp_comment();
427 /*===================================================*/
429 // '+' im identifier wg basic\source\classes\sb.src
431 // '<' im identifier wg sc subtdlg.src
433 // '&' im identifier wg scerror.src so2..nocode.src svxerr.src scwarngs.src
436 //string (\"[^"]*\") alter einfacher string ohne "
441 %option never-interactive
446 string \"{simple}((((\\\\)*(\\\"))?){simple})*\"
451 resfilelist ([Ff][Ii][Ll][Ee][Ll][Ii][Ss][Tt])
452 resstringlist ([Ss][Tt][Rr][Ii][Nn][Gg][Ll][Ii][Ss][Tt])
453 resstring ([Ss][Tt][Rr][Ii][Nn][Gg])
455 identifier ([a-z_A-Z]+[a-z_A-Z<+&0-9]*)
456 number (([0-9]+)|(0x[0-9a-fA-F]+))
457 residentifier ([Ii][Dd][Ee][Nn][Tt][Ii][Ff][Ii][Ee][Rr])
459 wspecial ([\\ \t\n]*)
460 texttag (([Tt][Ii][Tt][Ll][Ee])|([Tt][Ee][Xx][Tt])|([Mm][Ee][Ss][Ss][Aa][Gg][Ee]))
461 qhelptag (([Qq][Uu][Ii][Cc][Kk])?([Hh][Ee][Ll][Pp][Tt][Ee][Xx][Tt]))
463 helptag ([Hh][Ee][Ll][Pp][Ii][Dd])
464 helpid ([a-zA-Z_0-9]+)
465 num2tag (([Pp][Oo][Ss])|([Ss][Ii][Zz][Ee]))
466 num4tag (([Pp][Oo][Ss][Ss][Ii][Zz][Ee]))
470 /* forget whitespace */;
473 ^[ \t]*#include.*\.src[">].* {
474 char NewFile[255]; //long names???
480 // nicht schoen aber geht...
481 for (i = 0; yytext[i+1] != 0; i++)
485 if ( yytext[i] == '"' || yytext[i] == '>' )
488 NewFile[j++] = yytext[i];
490 if ( yytext[i] == '"' || yytext[i] == '<' )
495 pFile = fopen( NewFile, "r" );
496 if( pFile == NULL ) {
497 fprintf( stdout, "warning: could not open inputfile %s \n", NewFile );
498 // try the new *_tmpl.src version instead
499 // this hack was introduced to allow localisation of included src files
500 const char* sStrTmpl = "_tmpl";
502 for ( i = 0 ; i <5 ; i++,j++ )
504 NewFile[j+5] = NewFile[j];
505 NewFile[j] = sStrTmpl[i];
508 fprintf( stderr, "trying inputfile %s \n", NewFile );
509 pFile = fopen( NewFile, "r" );
510 if( pFile == NULL ) {
511 fprintf( stderr, "error: could not open inputfile %s \n", NewFile );
515 InputFiles[ nInputFileDepth ] = yy_create_buffer( pFile, YY_BUF_SIZE );
516 yy_switch_to_buffer( InputFiles[ nInputFileDepth ] );
519 fprintf( stdout, "%s //ATTENTION!! %s gets included here\n", yytext, NewFile );
520 fprintf( outfile, "// %s //ATTENTION!! %s gets included here\n\n", yytext, NewFile );
524 fprintf( outfile, "%s\n\n", yytext );
527 ^[ \t]*#(if|ifdef|ifndef|elif).* {
538 ^[ \t]*#(undef|error|pragma).* {
543 fprintf( outfile, "%s", yytext );
547 <INITIAL,MACRO_STATE>"/*" {
551 <INITIAL,MACRO_STATE>"//" {
556 fprintf( outfile, "%s\n", yytext );
561 fprintf( outfile, "\\\n" );
562 ;/* macro schadet nicht, koennte gebraucht werden */
567 fprintf( outfile, "%s", yytext );
568 ;/* ignore all this unused input */
571 ";" {ring->set_zero(); lasttoken = TOK_SEMICOLON; }
572 "=" {ring->set_zero(); lasttoken = TOK_EQUAL; }
573 "[" {ring->set_broken(); lasttoken = TOK_OPENBRACKET; }
574 "]" {ring->set_broken(); lasttoken = TOK_CLOSEBRACKET; }
578 exclude_bracelevel += 1;
580 fprintf( stdout,"info: lev %d : found {\n", exclude_bracelevel );
587 // or a brace opens a block
589 if( in_define && !strcmp(yytext,"\\\n") ) {
591 if( in_define++ == 1 )
600 dotappend( globalID, ares->localID );
601 ares->residfound = residfound;
602 push_resource( ares );
607 ares->residfound = 0;
609 ares->lineno = yylineno;
610 ares->lasttoken = lasttoken;
611 if( ring->size() == 2 ) {
612 ares->klasse = ring->extract_last();
613 ares->localID = ring->extract_actual();
614 } else if(ring->size() == 1) {
615 ares->klasse = ring->extract_actual();
617 if( level==1 ){ //Ausnahme: Resource auf Ebene 1
618 globalID= ares->localID;
619 ares->localID = NULL;
620 globalKLASSE= ares->klasse;
624 fprintf(stdout,"info: { level: %d\n", level);
626 lasttoken = TOK_OPENBRACE;
631 //-----------------------------
632 exclude_bracelevel -= 1;
634 fprintf( stdout,"info: lev %d : found }\n", exclude_bracelevel );
635 if( exclude_bracelevel==1 ) {
637 exclude_bracelevel=0;
645 fprintf(stdout,"info: } level: %d\n",level);
647 if( !strcmp(yytext,"}") )
649 else if( in_define && (!strcmp(yytext,"\n") )) {
651 //no continuation line for #define
656 //there was a continuation line for #define
667 char const * globklasse =
668 globalKLASSE==NULL ? LEER:globalKLASSE;
670 ares->localID==NULL ? LEER:ares->localID;
671 char const * klasse =
672 ares->klasse==NULL ? LEER:ares->klasse;
674 globalID==NULL ? LEER:globalID;
677 //wg. Starview-Klasse String in ehdl.c und doc.c
678 // wenn generierte C++-Quellen compiliert werden
680 //if( !strcmp(globklasse,"String" )) globklasse = "string";
681 //if( !strcmp(klasse,"String" )) klasse = "string";
684 //---------------------------------------------------
685 // generate the body of a new C main program,
686 // which is filled with printf statements
687 // to compute (via preproseccor & compiler)
688 // the codenumbers for resource names like menu$RID_SVX$xyz
692 fprintf(outfile, "#include \"starview.hid\" \n\n");
693 fprintf(outfile, " int main() { \n\n\n");
697 strcpy(globunder,glob);
698 dot2underline( globunder );
699 char const * globsuffix = strrchr(glob,'.');
700 globsuffix = globsuffix==NULL ? glob:globsuffix+1;
703 fprintf( outfile,"\n\t printf(\"%s \\t %cs %cu \\n\",\n",
704 ares->helpID,'%','%');
705 fprintf(outfile,"\t\"HelpID\", (%s) ); \n", ares->helpID);
707 else if( ares->localID ) {
708 fprintf( outfile,"\n\t printf(\"%s:%s:%s:%s \\t %cs %cu %cs %cu \\n\",\n",
709 project,klasse,globunder,local,'%','%','%','%');
710 fprintf( outfile,"\t\"Norm %s\", (%s), \"%s\", (%s) );\n",
711 globklasse,globsuffix, klasse,local);
713 else if( (strcmpi("MenuItem",klasse)==0) ||
714 (strcmpi("ToolBoxItem",klasse)==0) ) {
715 ; //no output (99% is a separator)
718 fprintf( outfile,"\n\t printf(\"%s:%s:%s \\t %cs %cu %cs \\n\",\n",
719 project,klasse,globunder,'%','%','%');
720 fprintf( outfile,"\t\"Norm %s\", (%s), \"%s\" );\n",
721 globklasse,globsuffix, klasse);
734 ares = pop_resource();
735 residfound = ares->residfound;
736 dotsubtract( globalID, ares->localID );
740 lasttoken = TOK_CLOSEBRACE;
745 "," {ring->set_broken(); lasttoken = TOK_KOMMA; }
747 "<" {ring->set_broken(); lasttoken = TOK_LESS; }
748 ">" {ring->set_broken(); lasttoken = TOK_GREATER; }
750 "(" {ring->set_broken(); lasttoken = TOK_OPENPAREN; }
751 ")" {ring->set_broken(); lasttoken = TOK_CLOSEPAREN; }
752 "+" {ring->set_broken(); lasttoken = TOK_PLUS; }
753 "-" {ring->set_broken(); lasttoken = TOK_MINUS; }
754 "*" {ring->set_broken(); lasttoken = TOK_STAR; }
755 "/" {ring->set_broken(); lasttoken = TOK_SLASH; }
758 {helptag}{w}"="{w}{helpid}{w}";" {
760 // extract text for helpid and put to ares
761 char* pos = strchr(yytext,'=');
762 size_t offset = strspn(pos+1," \t\n");
763 char* start = pos+1+offset;
764 size_t offset2= strcspn( start, "; \t\n");
765 char* end = start+offset2;
768 makestring( &helpid, start );
769 ares->helpID = helpid;
772 {residentifier}{w}"="[ \t\n]*({identifier}|{number}) {
774 lasttoken = TOK_RESID;
777 //extract resource id and store as localID
778 char *after = strrchr(yytext,'=');
779 char *resid = after + strspn(after,"= \t\n");
781 makestring( &localID, resid );
782 ares->localID = localID;
789 exclude_bracelevel = 1;
791 fprintf( stdout,"info: lev %d : found exclusion\n", exclude_bracelevel );
797 /* identifier/number in einem ring ablegen */
799 char *def=strstr(yytext,"#define");
802 makestring( &identifier, def+1 );
805 makestring( &identifier, yytext );
806 ring->set( identifier );
807 lasttoken = TOK_IDNUM;
810 <INITIAL,EXCLUDE_STATE>{string} {
812 lasttoken = TOK_STRING;
814 fprintf(stdout, "%6s %11s %8d %s \n",project,filename,yylineno, yytext);
818 <INITIAL,EXCLUDE_STATE>. { if ( bVerbose ) fprintf( stdout,"warning: unused input on line %d of %s \n%s\n",
819 yylineno, filename, yytext);
823 ; //do nothing, ignore
830 void makeversion( char* version )
832 char const *pos = strpbrk( Revision, "0123456789." );
833 size_t siz = strspn( pos, "0123456789." );
835 strncpy(version, pos, siz);
836 strcat( version, " ");
839 strcpy( version," unknown " );
842 int main( int argc, char* argv[] )
844 static char const *Compiler = "HID-Compiler ";
845 static char const *Author = "OG ";
846 static char HIDCompiler[100];
847 static char Version[100];
849 // check for switches given on the command line
850 if ( ( argc > 0 ) && ( 0 == strcmp( argv[0], "-verbose" ) ) )
853 for ( size_t i=0; i<argc-1; ++i )
860 makeversion( Version );
861 strcpy( HIDCompiler, Compiler );
862 strcat( HIDCompiler, Version );
863 strcat( HIDCompiler, Author );
865 fprintf( stdout, "\n %s \n\n", HIDCompiler);
869 "usage: hidc [-verbose] file.src file.c project\n"
871 "You must give exactly 3 arguments.\n"
872 "1 - an existing SRC file.\n"
873 "2 - C file to be generated (which generates the HID file when run).\n"
874 "3 - the project name (an arbitrary name).\n\n"
881 char *outfilename = argv[2];
882 if( (outfile=fopen( outfilename , "w" )) ==NULL ) {
883 fprintf(stderr,"error: could not open outputfile '%s' \n", outfilename);
890 pFile = fopen( filename, "r" );
891 if( pFile == NULL ) {
892 fprintf( stderr, "error: could not open inputfile %s \n", filename );
895 InputFiles[ nInputFileDepth ] = yy_create_buffer( pFile, YY_BUF_SIZE );
896 yy_switch_to_buffer( InputFiles[ nInputFileDepth ] );
897 ring = new ident_ring;
900 fprintf(outfile, "/* Generated from %s */\n\n", HIDCompiler );
901 fprintf(outfile, "/* Source was: %s */\n", filename );
904 yylex(); /* do the real work here */
907 fprintf(outfile, "#include \"starview.hid\" \n\n");
908 fprintf(outfile, " int main() { \n\n\n");
910 fprintf(outfile, "\nreturn 0;");
911 fprintf(outfile, "\n} /*main*/\n");
917 yy_delete_buffer( InputFiles[ nInputFileDepth ] );
918 if ( nInputFileDepth == 0 )
919 return 1;/* keine src files mehr */
923 fprintf(outfile, "// Done reading file\n\n");
924 yy_switch_to_buffer( InputFiles[ nInputFileDepth ] );
933 while( (c=yyinput()) != EOF ) {
936 else if( c=='/' && lastc=='*' )
937 break; /* end of comment found */
943 int eat_cpp_comment()
946 while( (c=yyinput()) != EOF ) {
952 unput(c); /* because next #.... line was not found */