If the condition embedding code runs out of available characters in the
authorthurston <thurston@052ea7fc-9027-0410-9066-f65837a77df0>
Thu, 13 Sep 2007 17:54:31 +0000 (17:54 +0000)
committerthurston <thurston@052ea7fc-9027-0410-9066-f65837a77df0>
Thu, 13 Sep 2007 17:54:31 +0000 (17:54 +0000)
keyspace an error message is emitted. A paragraph about this was added to the
manual.

git-svn-id: http://svn.complang.org/ragel/trunk@278 052ea7fc-9027-0410-9066-f65837a77df0

common/common.h
doc/ragel-guide.tex
ragel/fsmap.cpp
ragel/fsmgraph.h
ragel/parsedata.cpp
ragel/parsedata.h
ragel/rlparse.kl

index c0470d3..cfe8500 100644 (file)
@@ -57,9 +57,13 @@ public:
        long getVal() const { return key; };
 
        /* Returns the key casted to a long long. This form of the key does not
        long getVal() const { return key; };
 
        /* Returns the key casted to a long long. This form of the key does not
-        * require and signedness interpretation. */
+        * require any signedness interpretation. */
        long long getLongLong() const;
 
        long long getLongLong() const;
 
+       /* Returns the distance from the key value to the maximum value that the
+        * key implementation can hold. */
+       Size availableSpace() const;
+
        bool isUpper() const { return ( 'A' <= key && key <= 'Z' ); }
        bool isLower() const { return ( 'a' <= key && key <= 'z' ); }
        bool isPrintable() const
        bool isUpper() const { return ( 'A' <= key && key <= 'Z' ); }
        bool isLower() const { return ( 'a' <= key && key <= 'z' ); }
        bool isPrintable() const
@@ -252,6 +256,14 @@ inline long long Key::getLongLong() const
        return keyOps->isSigned ? (long long)key : (long long)(unsigned long)key;
 }
 
        return keyOps->isSigned ? (long long)key : (long long)(unsigned long)key;
 }
 
+inline Size Key::availableSpace() const
+{
+       if ( keyOps->isSigned ) 
+               return (long long)LONG_MAX - (long long)key;
+       else
+               return (unsigned long long)ULONG_MAX - (unsigned long long)(unsigned long)key;
+}
+       
 inline Key operator+(const Key key1, const Key key2)
 {
        /* FIXME: must be made aware of isSigned. */
 inline Key operator+(const Key key1, const Key key2)
 {
        /* FIXME: must be made aware of isSigned. */
index 03672a7..f27a0f4 100644 (file)
@@ -3553,6 +3553,16 @@ performing checks on the semantic structure of input seen so far. In the
 next section we describe how Ragel accommodates several common parser
 engineering problems.
 
 next section we describe how Ragel accommodates several common parser
 engineering problems.
 
+\vspace{10pt}
+
+\noindent {\large\bf Note:} The semantic condition feature works only with
+alphabet types that are smaller in width than the \verb|long| type. To
+implement semantic conditions Ragel needs to be able to allocate characters
+from the alphabet space. Ragel uses these allocated characters to express
+"character C with condition P true" or "C with P false." Since internally Ragel
+uses longs to store characters there is no room left in the alphabet space
+unless an alphabet type smaller than long is used.
+
 \section{Implementing Lookahead}
 
 There are a few strategies for implementing lookahead in Ragel programs.
 \section{Implementing Lookahead}
 
 There are a few strategies for implementing lookahead in Ragel programs.
index 53587e3..c9e673a 100644 (file)
@@ -802,8 +802,15 @@ CondSpace *FsmAp::addCondSpace( const CondSet &condSet )
 {
        CondSpace *condSpace = condData->condSpaceMap.find( condSet );
        if ( condSpace == 0 ) {
 {
        CondSpace *condSpace = condData->condSpaceMap.find( condSet );
        if ( condSpace == 0 ) {
-               Key baseKey = condData->nextCondKey;
-               condData->nextCondKey += (1 << condSet.length() ) * keyOps->alphSize();
+               /* Do we have enough keyspace left? */
+               Size availableSpace = condData->lastCondKey.availableSpace();
+               Size neededSpace = (1 << condSet.length() ) * keyOps->alphSize();
+               if ( neededSpace > availableSpace )
+                       throw FsmConstructFail( FsmConstructFail::CondNoKeySpace );
+
+               Key baseKey = condData->lastCondKey;
+               baseKey.increment();
+               condData->lastCondKey += (1 << condSet.length() ) * keyOps->alphSize();
 
                condSpace = new CondSpace( condSet );
                condSpace->baseKey = baseKey;
 
                condSpace = new CondSpace( condSet );
                condSpace->baseKey = baseKey;
index b2ded15..e3b3486 100644 (file)
@@ -25,6 +25,7 @@
 #include "config.h"
 #include <assert.h>
 #include <iostream>
 #include "config.h"
 #include <assert.h>
 #include <iostream>
+#include <string>
 #include "common.h"
 #include "vector.h"
 #include "bstset.h"
 #include "common.h"
 #include "vector.h"
 #include "bstset.h"
@@ -641,16 +642,28 @@ struct Removal
 
 struct CondData
 {
 
 struct CondData
 {
-       CondData() : nextCondKey(0) {}
+       CondData() : lastCondKey(0) {}
 
        /* Condition info. */
 
        /* Condition info. */
-       Key nextCondKey;
+       Key lastCondKey;
 
        CondSpaceMap condSpaceMap;
 };
 
 extern CondData *condData;
 
 
        CondSpaceMap condSpaceMap;
 };
 
 extern CondData *condData;
 
+struct FsmConstructFail
+{
+       enum Reason
+       {
+               CondNoKeySpace
+       };
+
+       FsmConstructFail( Reason reason ) 
+               : reason(reason) {}
+       Reason reason;
+};
+
 /* State class that implements actions and priorities. */
 struct StateAp 
 {
 /* State class that implements actions and priorities. */
 struct StateAp 
 {
index c860fef..6abe995 100644 (file)
@@ -849,16 +849,18 @@ void ParseData::initGraphDict( )
 }
 
 /* Set the alphabet type. If the types are not valid returns false. */
 }
 
 /* Set the alphabet type. If the types are not valid returns false. */
-bool ParseData::setAlphType( char *s1, char *s2 )
+bool ParseData::setAlphType( const InputLoc &loc, char *s1, char *s2 )
 {
 {
+       alphTypeLoc = loc;
        userAlphType = findAlphType( s1, s2 );
        alphTypeSet = true;
        return userAlphType != 0;
 }
 
 /* Set the alphabet type. If the types are not valid returns false. */
        userAlphType = findAlphType( s1, s2 );
        alphTypeSet = true;
        return userAlphType != 0;
 }
 
 /* Set the alphabet type. If the types are not valid returns false. */
-bool ParseData::setAlphType( char *s1 )
+bool ParseData::setAlphType( const InputLoc &loc, char *s1 )
 {
 {
+       alphTypeLoc = loc;
        userAlphType = findAlphType( s1 );
        alphTypeSet = true;
        return userAlphType != 0;
        userAlphType = findAlphType( s1 );
        alphTypeSet = true;
        return userAlphType != 0;
@@ -906,8 +908,7 @@ void ParseData::initKeyOps( )
                thisKeyOps.maxKey = makeFsmKeyNum( upperNum, rangeHighLoc, this );
        }
 
                thisKeyOps.maxKey = makeFsmKeyNum( upperNum, rangeHighLoc, this );
        }
 
-       thisCondData.nextCondKey = thisKeyOps.maxKey;
-       thisCondData.nextCondKey.increment();
+       thisCondData.lastCondKey = thisKeyOps.maxKey;
 }
 
 void ParseData::printNameInst( NameInst *nameInst, int level )
 }
 
 void ParseData::printNameInst( NameInst *nameInst, int level )
@@ -1365,8 +1366,32 @@ void ParseData::makeExports()
 
 }
 
 
 }
 
+/* Construct the machine and catch failures which can occur during
+ * construction. */
 void ParseData::prepareMachineGen( GraphDictEl *graphDictEl )
 {
 void ParseData::prepareMachineGen( GraphDictEl *graphDictEl )
 {
+       try {
+               /* This machine construction can fail. */
+               prepareMachineGenTBWrapped( graphDictEl );
+       }
+       catch ( FsmConstructFail fail ) {
+               switch ( fail.reason ) {
+                       case FsmConstructFail::CondNoKeySpace: {
+                               InputLoc &loc = alphTypeSet ? alphTypeLoc : sectionLoc;
+                               error(loc) << "sorry, no more characters are "
+                                               "available in the alphabet space" << endl;
+                               error(loc) << "  for conditions, please use a "
+                                               "smaller alphtype or reduce" << endl;
+                               error(loc) << "  the span of characters on which "
+                                               "conditions are embedded" << endl;
+                               break;
+                       }
+               }
+       }
+}
+
+void ParseData::prepareMachineGenTBWrapped( GraphDictEl *graphDictEl )
+{
        beginProcessing();
        initKeyOps();
        makeRootNames();
        beginProcessing();
        initKeyOps();
        makeRootNames();
index ad90ccd..4f8d04c 100644 (file)
@@ -187,8 +187,8 @@ struct ParseData
        void resolveActionNameRefs();
 
        /* Set the alphabet type. If type types are not valid returns false. */
        void resolveActionNameRefs();
 
        /* Set the alphabet type. If type types are not valid returns false. */
-       bool setAlphType( char *s1, char *s2 );
-       bool setAlphType( char *s1 );
+       bool setAlphType( const InputLoc &loc, char *s1, char *s2 );
+       bool setAlphType( const InputLoc &loc, char *s1 );
 
        /* Override one of the variables ragel uses. */
        bool setVariable( char *var, InlineList *inlineList );
 
        /* Override one of the variables ragel uses. */
        bool setVariable( char *var, InlineList *inlineList );
@@ -214,6 +214,7 @@ struct ParseData
        void makeExports();
 
        void prepareMachineGen( GraphDictEl *graphDictEl );
        void makeExports();
 
        void prepareMachineGen( GraphDictEl *graphDictEl );
+       void prepareMachineGenTBWrapped( GraphDictEl *graphDictEl );
        void generateXML( ostream &out );
        FsmAp *sectionGraph;
        bool generatingSectionSubset;
        void generateXML( ostream &out );
        FsmAp *sectionGraph;
        bool generatingSectionSubset;
@@ -254,6 +255,7 @@ struct ParseData
        /* Alphabet type. */
        HostType *userAlphType;
        bool alphTypeSet;
        /* Alphabet type. */
        HostType *userAlphType;
        bool alphTypeSet;
+       InputLoc alphTypeLoc;
 
        /* Element type and get key expression. */
        InlineList *getKeyExpr;
 
        /* Element type and get key expression. */
        InlineList *getKeyExpr;
index d6c2c02..bf93978 100644 (file)
@@ -147,7 +147,7 @@ action_spec:
 # semi-colon.
 alphtype_spec:
        KW_AlphType TK_Word TK_Word ';' final {
 # 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;
                        // Recover by ignoring the alphtype statement.
                        error($2->loc) << "\"" << $2->data << 
                                        " " << $3->data << "\" is not a valid alphabet type" << endl;
@@ -156,7 +156,7 @@ alphtype_spec:
 
 alphtype_spec:
        KW_AlphType TK_Word ';' final {
 
 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;
                        // Recover by ignoring the alphtype statement.
                        error($2->loc) << "\"" << $2->data << 
                                        "\" is not a valid alphabet type" << endl;