2 * Copyright 2005-2006 Adrian Thurston <thurston@cs.queensu.ca>
5 /* This file is part of Ragel.
7 * Ragel is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * Ragel is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Ragel; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include "rlcodegen.h"
46 Key readKey( char *td, char **end );
47 long readOffsetPtr( char *td, char **end );
48 unsigned long readLength( char *td );
50 CodeGenMap codeGenMap;
57 /* General data types. */
63 /* Inline parse tree items. */
77 %token TAG_start_state
78 %token TAG_action_list
79 %token TAG_action_table_list
81 %token TAG_action_table
85 %token TAG_state_actions
86 %token TAG_entry_points
88 %token TAG_cond_space_list
93 /* Inline block tokens. */
115 %token TAG_set_tokend
116 %token TAG_get_tokend
117 %token TAG_init_tokstart
118 %token TAG_set_tokstart
125 %token <data> XML_Word
126 %token <data> XML_Literal
127 %type <attrList> AttributeList
129 %type <illist> InlineList
130 %type <ilitem> InlineItem
131 %type <illist> LmActionList
133 %type <ilitem> TagText
134 %type <ilitem> TagGoto
135 %type <ilitem> TagCall
136 %type <ilitem> TagNext
137 %type <ilitem> TagGotoExpr
138 %type <ilitem> TagCallExpr
139 %type <ilitem> TagNextExpr
140 %type <ilitem> TagRet
141 %type <ilitem> TagBreak
142 %type <ilitem> TagPChar
143 %type <ilitem> TagChar
144 %type <ilitem> TagHold
145 %type <ilitem> TagExec
146 %type <ilitem> TagHoldTE
147 %type <ilitem> TagExecTE
148 %type <ilitem> TagCurs
149 %type <ilitem> TagTargs
150 %type <ilitem> TagIlEntry
151 %type <ilitem> TagLmSwitch
152 %type <ilitem> TagLmSetActId
153 %type <ilitem> TagLmGetTokEnd
154 %type <ilitem> TagLmSetTokEnd
155 %type <ilitem> TagLmInitTokStart
156 %type <ilitem> TagLmInitAct
157 %type <ilitem> TagLmSetTokStart
158 %type <ilitem> TagInlineAction
159 %type <ilitem> TagSubAction
163 /* Input is any number of input sections. An empty file is accepted. */
167 /* Assume the frontend died if we get no input. It will emit an error.
168 * Cause us to return an error code. */
175 '<' '/' TAG_ragel '>';
178 '<' TAG_ragel AttributeList '>' {
179 Attribute *fileNameAttr = $3->find( "filename" );
180 if ( fileNameAttr == 0 )
181 xml_error(@2) << "tag <ragel> requires a filename attribute" << endl;
183 sourceFileName = fileNameAttr->value;
185 Attribute *langAttr = $3->find( "lang" );
187 xml_error(@2) << "tag <ragel> requires a lang attribute" << endl;
189 if ( strcmp( langAttr->value, "C" ) == 0 ) {
190 hostLangType = CCode;
191 hostLang = &hostLangC;
193 else if ( strcmp( langAttr->value, "D" ) == 0 ) {
194 hostLangType = DCode;
195 hostLang = &hostLangD;
197 else if ( strcmp( langAttr->value, "Java" ) == 0 ) {
198 hostLangType = JavaCode;
199 hostLang = &hostLangJava;
203 /* Eventually more types will be supported. */
204 if ( hostLangType == JavaCode && codeStyle != GenTables ) {
205 error() << "java: only the table code style -T0 is "
206 "currently supported" << endl;
209 openOutput( sourceFileName );
213 AttributeList Attribute {
215 $$->append( Attribute( attrKey, attrValue ) );
222 XML_Word '=' XML_Literal {
228 HostOrDefList HostOrDef |
232 TagHost | TagRagelDef;
236 '<' '/' TAG_host '>' {
237 if ( outputFormat == OutCode )
238 *outStream << xmlData.data;
242 '<' TAG_host AttributeList '>' {
243 Attribute *lineAttr = $3->find( "line" );
245 xml_error(@2) << "tag <host> requires a line attribute" << endl;
247 int line = atoi( lineAttr->value );
248 if ( outputFormat == OutCode )
249 lineDirective( *outStream, sourceFileName, line );
256 '<' '/' TAG_ragel_def '>' {
257 if ( gblErrorCount == 0 )
262 '<' TAG_ragel_def AttributeList '>' {
263 bool wantComplete = outputFormat != OutGraphvizDot;
266 Attribute *nameAttr = $3->find( "name" );
267 if ( nameAttr != 0 ) {
268 fsmName = nameAttr->value;
270 CodeGenMapEl *mapEl = codeGenMap.find( fsmName );
274 cgd = new CodeGenData( sourceFileName, fsmName, wantComplete );
275 codeGenMap.insert( fsmName, cgd );
279 cgd = new CodeGenData( sourceFileName, fsmName, wantComplete );
283 cgd->writeData = false;
284 cgd->writeInit = false;
285 cgd->writeExec = false;
286 cgd->writeEOF = false;
287 ::keyOps = &cgd->thisKeyOps;
291 RagelDefItemList RagelDefItem |
303 '<' TAG_write AttributeList '>'
305 '<' '/' TAG_write '>' {
306 Attribute *what = $3->find( "what" );
308 xml_error(@2) << "tag <write> requires a what attribute" << endl;
311 if ( strcmp( what->value, "data" ) == 0 )
312 cgd->writeData = true;
313 else if ( strcmp( what->value, "init" ) == 0 )
314 cgd->writeInit = true;
315 else if ( strcmp( what->value, "exec" ) == 0 )
316 cgd->writeExec = true;
317 else if ( strcmp( what->value, "eof" ) == 0 )
318 cgd->writeEOF = true;
323 OptionList TagOption |
328 '<' '/' TAG_option '>' {
329 if ( strcmp( xmlData.data, "noend" ) == 0 )
330 cgd->writeOps |= WO_NOEND;
331 else if ( strcmp( xmlData.data, "noerror" ) == 0 )
332 cgd->writeOps |= WO_NOERROR;
333 else if ( strcmp( xmlData.data, "noprefix" ) == 0 )
334 cgd->writeOps |= WO_NOPREFIX;
335 else if ( strcmp( xmlData.data, "nofinal" ) == 0 )
336 cgd->writeOps |= WO_NOFF;
338 warning() << "unrecognized write option" << endl;
345 '<' '/' TAG_alphtype '>' {
346 if ( ! cgd->setAlphType( xmlData.data ) )
347 xml_error(@2) << "tag <alphtype> specifies unknown alphabet type" << endl;
353 '<' '/' TAG_getkey '>' {
354 cgd->getKeyExpr = $4;
360 '<' '/' TAG_access '>' {
361 cgd->accessExpr = $4;
367 '<' '/' TAG_curstate '>' {
368 cgd->curStateExpr = $4;
374 '<' '/' TAG_machine '>' {
375 cgd->finishMachine();
379 '<' TAG_machine '>' {
380 cgd->createMachine();
384 MachineItemList MachineItem |
396 '<' TAG_start_state '>'
397 '<' '/' TAG_start_state '>' {
398 unsigned long startState = strtoul( xmlData.data, 0, 10 );
399 cgd->setStartState( startState );
403 '<' TAG_entry_points AttributeList '>'
405 '<' '/' TAG_entry_points '>' {
406 Attribute *errorAttr = $3->find( "error" );
407 if ( errorAttr != 0 )
408 cgd->setForcedErrorState();
412 EntryPointList TagEntry |
416 '<' TAG_entry AttributeList '>'
417 '<' '/' TAG_entry '>' {
418 Attribute *nameAttr = $3->find( "name" );
420 xml_error(@2) << "tag <entry_points>::<entry> requires a name attribute" << endl;
422 char *data = xmlData.data;
423 unsigned long entry = strtoul( data, &data, 10 );
424 cgd->addEntryPoint( nameAttr->value, entry );
431 '<' '/' TAG_state_list '>';
434 '<' TAG_state_list AttributeList '>' {
435 Attribute *lengthAttr = $3->find( "length" );
436 if ( lengthAttr == 0 )
437 xml_error(@2) << "tag <state_list> requires a length attribute" << endl;
439 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
440 cgd->initStateList( length );
452 '<' '/' TAG_state '>' {
457 '<' TAG_state AttributeList '>' {
458 Attribute *lengthAttr = $3->find( "final" );
459 if ( lengthAttr != 0 )
460 cgd->setFinal( curState );
464 StateItemList StateItem |
473 '<' TAG_state_actions '>'
474 '<' '/' TAG_state_actions '>' {
475 char *ad = xmlData.data;
477 long toStateAction = readOffsetPtr( ad, &ad );
478 long fromStateAction = readOffsetPtr( ad, &ad );
479 long eofAction = readOffsetPtr( ad, &ad );
481 cgd->setStateActions( curState, toStateAction,
482 fromStateAction, eofAction );
488 '<' '/' TAG_cond_list '>';
490 TagStateCondListHead:
491 '<' TAG_cond_list AttributeList '>' {
492 Attribute *lengthAttr = $3->find( "length" );
493 if ( lengthAttr == 0 )
494 xml_error(@2) << "tag <cond_list> requires a length attribute" << endl;
496 ulong length = readLength( lengthAttr->value );
497 cgd->initStateCondList( curState, length );
503 StateCondList StateCond |
509 char *td = xmlData.data;
510 Key lowKey = readKey( td, &td );
511 Key highKey = readKey( td, &td );
512 long condId = readOffsetPtr( td, &td );
513 cgd->addStateCond( curState, lowKey, highKey, condId );
519 '<' '/' TAG_trans_list '>' {
520 cgd->finishTransList( curState );
524 '<' TAG_trans_list AttributeList '>' {
525 Attribute *lengthAttr = $3->find( "length" );
526 if ( lengthAttr == 0 )
527 xml_error(@2) << "tag <trans_list> requires a length attribute" << endl;
529 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
530 cgd->initTransList( curState, length );
540 '<' TAG_t AttributeList '>'
542 char *td = xmlData.data;
543 Key lowKey = readKey( td, &td );
544 Key highKey = readKey( td, &td );
545 long targ = readOffsetPtr( td, &td );
546 long action = readOffsetPtr( td, &td );
548 cgd->newTrans( curState, curTrans++, lowKey, highKey, targ, action );
554 '<' '/' TAG_action_list '>';
557 '<' TAG_action_list AttributeList '>' {
558 Attribute *lengthAttr = $3->find( "length" );
559 if ( lengthAttr == 0 )
560 xml_error(@2) << "tag <action_list> requires a length attribute" << endl;
562 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
563 cgd->initActionList( length );
569 ActionList TagAction |
573 '<' TAG_action AttributeList '>'
575 '<' '/' TAG_action '>' {
576 Attribute *lineAttr = $3->find( "line" );
577 Attribute *colAttr = $3->find( "col" );
578 Attribute *nameAttr = $3->find( "name" );
579 if ( lineAttr == 0 || colAttr == 0)
580 xml_error(@2) << "tag <action> requires a line and col attributes" << endl;
582 unsigned long line = strtoul( lineAttr->value, 0, 10 );
583 unsigned long col = strtoul( colAttr->value, 0, 10 );
587 name = nameAttr->value;
589 cgd->newAction( curAction++, name, line, col, $5 );
594 InlineList InlineItem {
595 /* Append the item to the list, return the list. */
600 /* Start with empty list. */
633 '<' TAG_text AttributeList '>'
634 '<' '/' TAG_text '>' {
635 $$ = new InlineItem( InputLoc(), InlineItem::Text );
636 $$->data = strdup(xmlData.data);
641 '<' '/' TAG_goto '>' {
642 int targ = strtol( xmlData.data, 0, 10 );
643 $$ = new InlineItem( InputLoc(), InlineItem::Goto );
649 '<' '/' TAG_call '>' {
650 int targ = strtol( xmlData.data, 0, 10 );
651 $$ = new InlineItem( InputLoc(), InlineItem::Call );
657 '<' '/' TAG_next '>' {
658 int targ = strtol( xmlData.data, 0, 10 );
659 $$ = new InlineItem( InputLoc(), InlineItem::Next );
664 '<' TAG_goto_expr '>'
666 '<' '/' TAG_goto_expr '>' {
667 $$ = new InlineItem( InputLoc(), InlineItem::GotoExpr );
672 '<' TAG_call_expr '>'
674 '<' '/' TAG_call_expr '>' {
675 $$ = new InlineItem( InputLoc(), InlineItem::CallExpr );
680 '<' TAG_next_expr '>'
682 '<' '/' TAG_next_expr '>' {
683 $$ = new InlineItem( InputLoc(), InlineItem::NextExpr );
689 '<' '/' TAG_ret '>' {
690 $$ = new InlineItem( InputLoc(), InlineItem::Ret );
695 '<' '/' TAG_pchar '>' {
696 $$ = new InlineItem( InputLoc(), InlineItem::PChar );
701 '<' '/' TAG_char '>' {
702 $$ = new InlineItem( InputLoc(), InlineItem::Char );
707 '<' '/' TAG_hold '>' {
708 $$ = new InlineItem( InputLoc(), InlineItem::Hold );
714 '<' '/' TAG_exec '>' {
715 $$ = new InlineItem( InputLoc(), InlineItem::Exec );
721 '<' '/' TAG_holdte '>' {
722 $$ = new InlineItem( InputLoc(), InlineItem::HoldTE );
728 '<' '/' TAG_execte '>' {
729 $$ = new InlineItem( InputLoc(), InlineItem::ExecTE );
735 '<' '/' TAG_curs '>' {
736 $$ = new InlineItem( InputLoc(), InlineItem::Curs );
741 '<' '/' TAG_targs '>' {
742 $$ = new InlineItem( InputLoc(), InlineItem::Targs );
747 '<' '/' TAG_entry '>' {
748 int targ = strtol( xmlData.data, 0, 10 );
749 $$ = new InlineItem( InputLoc(), InlineItem::Entry );
755 '<' '/' TAG_break '>' {
756 $$ = new InlineItem( InputLoc(), InlineItem::Break );
761 '<' TAG_lm_switch AttributeList '>'
763 '<' '/' TAG_lm_switch '>' {
764 bool handlesError = false;
765 Attribute *handlesErrorAttr = $3->find( "handles_error" );
766 if ( handlesErrorAttr != 0 )
769 $$ = new InlineItem( InputLoc(), InlineItem::LmSwitch );
771 $$->handlesError = handlesError;
775 LmActionList TagInlineAction {
784 '<' TAG_sub_action AttributeList '>'
786 '<' '/' TAG_sub_action '>' {
787 $$ = new InlineItem( InputLoc(), InlineItem::SubAction );
790 Attribute *idAttr = $3->find( "id" );
792 unsigned long id = strtoul( idAttr->value, 0, 10 );
799 '<' '/' TAG_set_act '>' {
800 $$ = new InlineItem( InputLoc(), InlineItem::LmSetActId );
801 $$->lmId = strtol( xmlData.data, 0, 10 );
805 '<' TAG_get_tokend '>'
806 '<' '/' TAG_get_tokend '>' {
807 $$ = new InlineItem( InputLoc(), InlineItem::LmGetTokEnd );
811 '<' TAG_set_tokend '>'
812 '<' '/' TAG_set_tokend '>' {
813 $$ = new InlineItem( InputLoc(), InlineItem::LmSetTokEnd );
814 $$->offset = strtol( xmlData.data, 0, 10 );
818 '<' TAG_sub_action '>'
820 '<' '/' TAG_sub_action '>' {
821 $$ = new InlineItem( InputLoc(), InlineItem::SubAction );
826 '<' TAG_init_tokstart '>'
827 '<' '/' TAG_init_tokstart '>' {
828 $$ = new InlineItem( InputLoc(), InlineItem::LmInitTokStart );
833 '<' '/' TAG_init_act '>' {
834 $$ = new InlineItem( InputLoc(), InlineItem::LmInitAct );
838 '<' TAG_set_tokstart '>'
839 '<' '/' TAG_set_tokstart '>' {
840 $$ = new InlineItem( InputLoc(), InlineItem::LmSetTokStart );
841 cgd->hasLongestMatch = true;
845 TagActionTableListHead
847 '<' '/' TAG_action_table_list '>';
849 TagActionTableListHead:
850 '<' TAG_action_table_list AttributeList '>' {
851 Attribute *lengthAttr = $3->find( "length" );
852 if ( lengthAttr == 0 )
853 xml_error(@2) << "tag <action_table_list> requires a length attribute" << endl;
855 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
856 cgd->initActionTableList( length );
862 ActionTableList TagActionTable |
866 '<' TAG_action_table AttributeList '>'
867 '<' '/' TAG_action_table '>' {
868 /* Find the length of the action table. */
869 Attribute *lengthAttr = $3->find( "length" );
870 if ( lengthAttr == 0 )
871 xml_error(@2) << "tag <at> requires a length attribute" << endl;
873 unsigned long length = strtoul( lengthAttr->value, 0, 10 );
875 /* Collect the action table. */
876 RedAction *redAct = cgd->allActionTables + curActionTable;
877 redAct->actListId = curActionTable;
878 redAct->key.setAsNew( length );
879 char *ptr = xmlData.data;
881 while ( *ptr != 0 ) {
882 unsigned long actionId = strtoul( ptr, &ptr, 10 );
883 redAct->key[pos].key = 0;
884 redAct->key[pos].value = cgd->allActions+actionId;
888 /* Insert into the action table map. */
889 cgd->redFsm->actionMap.insert( redAct );
898 '<' '/' TAG_cond_space_list '>';
900 TagCondSpaceListHead:
901 '<' TAG_cond_space_list AttributeList '>' {
902 Attribute *lengthAttr = $3->find( "length" );
903 if ( lengthAttr == 0 )
904 xml_error(@2) << "tag <cond_space_list> requires a length attribute" << endl;
906 ulong length = readLength( lengthAttr->value );
907 cgd->initCondSpaceList( length );
913 CondSpaceList TagCondSpace |
917 '<' TAG_cond_space AttributeList '>'
918 '<' '/' TAG_cond_space '>' {
919 Attribute *lengthAttr = $3->find( "length" );
920 Attribute *idAttr = $3->find( "id" );
921 if ( lengthAttr == 0 )
922 xml_error(@2) << "tag <cond_space> requires a length attribute" << endl;
924 if ( lengthAttr == 0 )
925 xml_error(@2) << "tag <cond_space> requires an id attribute" << endl;
927 unsigned long condSpaceId = strtoul( idAttr->value, 0, 10 );
928 ulong length = readLength( lengthAttr->value );
930 char *td = xmlData.data;
931 Key baseKey = readKey( td, &td );
933 cgd->newCondSpace( curCondSpace, condSpaceId, baseKey );
934 for ( ulong a = 0; a < length; a++ ) {
935 long actionOffset = readOffsetPtr( td, &td );
936 cgd->condSpaceItem( curCondSpace, actionOffset );
945 unsigned long readLength( char *td )
947 return strtoul( td, 0, 10 );
950 Key readKey( char *td, char **end )
952 if ( keyOps->isSigned )
953 return Key( strtol( td, end, 10 ) );
955 return Key( strtoul( td, end, 10 ) );
958 long readOffsetPtr( char *td, char **end )
960 while ( *td == ' ' || *td == '\t' )
969 return strtol( td, end, 10 );
972 void yyerror( char *err )
974 /* Bison won't give us the location, but in the last call to the scanner we
975 * saved a pointer to the locationn variable. Use that. instead. */
976 error(::yylloc->first_line, ::yylloc->first_column) << err << endl;