/*
- * Copyright 2001-2007 Adrian Thurston <thurston@cs.queensu.ca>
+ * Copyright 2001-2007 Adrian Thurston <thurston@complang.org>
*/
/* This file is part of Ragel.
#include "ragel.h"
#include <iostream>
#include <errno.h>
+#include <stdlib.h>
using std::cout;
using std::cerr;
using std::endl;
-ParserDict parserDict;
-
%%{
parser Parser;
statement: getkey_spec commit;
statement: access_spec commit;
statement: variable_spec commit;
+statement: export_block commit;
+statement: pre_push_spec commit;
+statement: post_pop_spec commit;
+statement: length_spec commit;
+
+length_spec:
+ KW_Length TK_Word ';'
+ final {
+ LengthDef *lengthDef = new LengthDef( $2->data );
+ pd->lengthDefList.append( lengthDef );
+
+ /* Generic creation of machine for instantiation and assignment. */
+ MachineDef *machineDef = new MachineDef( lengthDef );
+ tryMachineDef( $2->loc, $2->data, machineDef, false );
+ };
+
+pre_push_spec:
+ KW_PrePush '{' inline_block '}'
+ final {
+ if ( pd->prePushExpr != 0 ) {
+ /* Recover by just ignoring the duplicate. */
+ error($2->loc) << "pre_push code already defined" << endl;
+ }
+
+ pd->prePushExpr = $3->inlineList;
+ };
+
+
+post_pop_spec:
+ KW_PostPop '{' inline_block '}'
+ final {
+ if ( pd->postPopExpr != 0 ) {
+ /* Recover by just ignoring the duplicate. */
+ error($2->loc) << "post_pop code already defined" << endl;
+ }
+
+ pd->postPopExpr = $3->inlineList;
+ };
+
+
+export_open: KW_Export
+ final {
+ exportContext.append( true );
+ };
+
+nonterm opt_export
+{
+ bool isSet;
+};
+
+opt_export: export_open final { $$->isSet = true; };
+opt_export: final { $$->isSet = false; };
+
+export_block: export_open '{' statement_list '}'
+ final {
+ exportContext.remove( exportContext.length()-1 );
+ };
assignment:
- machine_name '=' join ';' final {
+ opt_export machine_name '=' join ';' final {
/* Main machine must be an instance. */
bool isInstance = false;
- if ( strcmp($1->token.data, machineMain) == 0 ) {
- warning($1->token.loc) <<
+ if ( strcmp($2->token.data, mainMachine) == 0 ) {
+ warning($2->token.loc) <<
"main machine will be implicitly instantiated" << endl;
isInstance = true;
}
/* Generic creation of machine for instantiation and assignment. */
- JoinOrLm *joinOrLm = new JoinOrLm( $3->join );
- tryMachineDef( $1->token.loc, $1->token.data, joinOrLm, isInstance );
+ MachineDef *machineDef = new MachineDef( $4->join );
+ tryMachineDef( $2->token.loc, $2->token.data, machineDef, isInstance );
+
+ if ( $1->isSet )
+ exportContext.remove( exportContext.length()-1 );
+
+ $4->join->loc = $3->loc;
};
instantiation:
- machine_name TK_ColonEquals join_or_lm ';' final {
+ opt_export machine_name TK_ColonEquals join_or_lm ';' final {
/* Generic creation of machine for instantiation and assignment. */
- tryMachineDef( $1->token.loc, $1->token.data, $3->joinOrLm, true );
+ tryMachineDef( $2->token.loc, $2->token.data, $4->machineDef, true );
+
+ if ( $1->isSet )
+ exportContext.remove( exportContext.length()-1 );
+
+ /* Pass a location to join_or_lm */
+ if ( $4->machineDef->join != 0 )
+ $4->machineDef->join->loc = $3->loc;
};
type token_type
else {
//cerr << "NEW ACTION " << $2->data << " " << $4->inlineList << endl;
/* Add the action to the list of actions. */
- Action *newAction = new Action( $3->loc, $2->data, $4->inlineList );
+ Action *newAction = new Action( $3->loc, $2->data,
+ $4->inlineList, pd->nextCondId++ );
/* Insert to list and dict. */
pd->actionList.append( newAction );
# semi-colon.
alphtype_spec:
KW_AlphType TK_Word TK_Word ';' final {
- if ( ! pd->setAlphType( $2->data, $3->data ) ) {
+ if ( ! pd->setAlphType( $1->loc, $2->data, $3->data ) ) {
// Recover by ignoring the alphtype statement.
error($2->loc) << "\"" << $2->data <<
" " << $3->data << "\" is not a valid alphabet type" << endl;
alphtype_spec:
KW_AlphType TK_Word ';' final {
- if ( ! pd->setAlphType( $2->data ) ) {
+ if ( ! pd->setAlphType( $1->loc, $2->data ) ) {
// Recover by ignoring the alphtype statement.
error($2->loc) << "\"" << $2->data <<
"\" is not a valid alphabet type" << endl;
variable_spec:
KW_Variable opt_whitespace TK_Word inline_expr ';' final {
/* FIXME: Need to implement the rest of this. */
- if ( strcmp( $3->data, "curstate" ) == 0 )
- pd->curStateExpr = $4->inlineList;
- else {
- error($3->loc) << "sorry, unimplementd" << endl;
- }
+ bool wasSet = pd->setVariable( $3->data, $4->inlineList );
+ if ( !wasSet )
+ error($3->loc) << "bad variable name" << endl;
};
opt_whitespace: opt_whitespace IL_WhiteSpace;
nonterm join_or_lm
{
- JoinOrLm *joinOrLm;
+ MachineDef *machineDef;
};
join_or_lm:
join final {
- $$->joinOrLm = new JoinOrLm( $1->join );
+ $$->machineDef = new MachineDef( $1->join );
};
join_or_lm:
TK_BarStar lm_part_list '*' '|' final {
pd->lmList.append( lm );
for ( LmPartList::Iter lmp = *($2->lmPartList); lmp.lte(); lmp++ )
lmp->longestMatch = lm;
- $$->joinOrLm = new JoinOrLm( lm );
+ $$->machineDef = new MachineDef( lm );
};
nonterm lm_part_list
};
lm_part_list:
- lm_part_list longest_match_part final {
+ lm_part_list longest_match_part
+ final {
if ( $2->lmPart != 0 )
$1->lmPartList->append( $2->lmPart );
$$->lmPartList = $1->lmPartList;
};
lm_part_list:
- longest_match_part final {
+ longest_match_part
+ final {
/* Create a new list with the part. */
$$->lmPartList = new LmPartList;
if ( $1->lmPart != 0 )
action->isLmAction = true;
$$->lmPart = new LongestMatchPart( $1->join, action,
$3->loc, pd->nextLongestMatchId++ );
+
+ /* Provide a location to join. Unfortunately We don't
+ * have the start of the join as in other occurances. Use the end. */
+ $1->join->loc = $3->loc;
};
nonterm opt_lm_part_action
};
expression:
- expression '|' term final {
+ expression '|' term_short final {
$$->expression = new Expression( $1->expression,
$3->term, Expression::OrType );
};
expression:
- expression '&' term final {
+ expression '&' term_short final {
$$->expression = new Expression( $1->expression,
$3->term, Expression::IntersectType );
};
-# This priority specification overrides the innermost parsing strategy which
-# results ordered choice interpretation of the grammar.
expression:
- expression pri(1) '-' term final {
+ expression '-' term_short final {
$$->expression = new Expression( $1->expression,
$3->term, Expression::SubtractType );
};
expression:
- expression TK_DashDash term final {
+ expression TK_DashDash term_short final {
$$->expression = new Expression( $1->expression,
$3->term, Expression::StrongSubtractType );
};
expression:
- term final {
+ term_short final {
$$->expression = new Expression( $1->term );
};
+# This is where we resolve the ambiguity involving -. By default ragel tries to
+# do a longest match, which gives precedence to a concatenation because it is
+# innermost. What we need is to force term into a shortest match so that when -
+# is seen it doesn't try to extend term with a concatenation, but ends term and
+# goes for a subtraction.
+#
+# The shortest tag overrides the default longest match action ordering strategy
+# and instead forces a shortest match stragegy. The wrap the term production in
+# a new nonterminal 'term_short' to guarantee the shortest match behaviour.
+
+shortest term_short;
+nonterm term_short
+{
+ Term *term;
+};
+
+term_short:
+ term final {
+ $$->term = $1->term;
+ };
+
nonterm term
{
Term *term;
};
factor_with_aug:
factor_with_aug aug_type_cond action_embed final {
- $1->factorWithAug->conditions.append( ParserAction( $2->loc,
- $2->augType, 0, $3->action ) );
+ $1->factorWithAug->conditions.append( ConditionTest( $2->loc,
+ $2->augType, $3->action, true ) );
+ $$->factorWithAug = $1->factorWithAug;
+ };
+factor_with_aug:
+ factor_with_aug aug_type_cond '!' action_embed final {
+ $1->factorWithAug->conditions.append( ConditionTest( $2->loc,
+ $2->augType, $4->action, false ) );
$$->factorWithAug = $1->factorWithAug;
};
factor_with_aug:
aug_type_cond: TK_LeavingCond final { $$->loc = $1->loc; $$->augType = at_leave; };
aug_type_cond: '%' KW_When final { $$->loc = $1->loc; $$->augType = at_leave; };
aug_type_cond: KW_When final { $$->loc = $1->loc; $$->augType = at_all; };
+aug_type_cond: KW_InWhen final { $$->loc = $1->loc; $$->augType = at_start; };
+aug_type_cond: KW_OutWhen final { $$->loc = $1->loc; $$->augType = at_leave; };
#
# To state actions.
nonterm action_embed uses action_ref;
action_embed: action_embed_word final { $$->action = $1->action; };
+action_embed: '(' action_embed_word ')' final { $$->action = $2->action; };
action_embed: action_embed_block final { $$->action = $1->action; };
nonterm action_embed_word uses action_ref;
action_embed_block:
'{' inline_block '}' final {
/* Create the action, add it to the list and pass up. */
- Action *newAction = new Action( $1->loc, 0, $2->inlineList );
+ Action *newAction = new Action( $1->loc, 0, $2->inlineList, pd->nextCondId++ );
pd->actionList.append( newAction );
$$->action = newAction;
};
// Convert the priority number to a long. Check for overflow.
errno = 0;
//cerr << "PRIOR AUG: " << $1->token.data << endl;
- int aug = strtol( $1->token.data, 0, 10 );
+ long aug = strtol( $1->token.data, 0, 10 );
if ( errno == ERANGE && aug == LONG_MAX ) {
/* Priority number too large. Recover by setting the priority to 0. */
error($1->token.loc) << "priority number " << $1->token.data <<
TK_UInt final {
// Convert the priority number to a long. Check for overflow.
errno = 0;
- int rep = strtol( $1->data, 0, 10 );
+ long rep = strtol( $1->data, 0, 10 );
if ( errno == ERANGE && rep == LONG_MAX ) {
// Repetition too large. Recover by returing repetition 1. */
error($1->loc) << "repetition number " << $1->data << " overflows" << endl;
'(' join ')' final {
/* Create a new factor going to a parenthesized join. */
$$->factor = new Factor( $2->join );
+ $2->join->loc = $1->loc;
};
nonterm range_lit
}
void Parser::tryMachineDef( InputLoc &loc, char *name,
- JoinOrLm *joinOrLm, bool isInstance )
+ MachineDef *machineDef, bool isInstance )
{
GraphDictEl *newEl = pd->graphDict.insert( name );
if ( newEl != 0 ) {
/* New element in the dict, all good. */
- newEl->value = new VarDef( name, joinOrLm );
+ newEl->value = new VarDef( name, machineDef );
newEl->isInstance = isInstance;
newEl->loc = loc;
+ newEl->value->isExport = exportContext[exportContext.length()-1];
/* It it is an instance, put on the instance list. */
if ( isInstance )
/* Maintain the error count. */
gblErrorCount += 1;
- cerr << token.loc.fileName << ":" << token.loc.line << ":" << token.loc.col << ": ";
+ cerr << token.loc << ": ";
cerr << "at token ";
if ( tokId < 128 )
cerr << "\"" << Parser_lelNames[tokId] << "\"";