Modules | Files | Inheritance Tree | Inheritance Graph | Name Index | Config
File: Synopsis/Parser/C++/occ/pattern.cc
    1| /*
    2|   Copyright (C) 1997-2000 Shigeru Chiba, University of Tsukuba.
    3| 
    4|   Permission to use, copy, distribute and modify this software and   
    5|   its documentation for any purpose is hereby granted without fee,        
    6|   provided that the above copyright notice appear in all copies and that 
    7|   both that copyright notice and this permission notice appear in 
    8|   supporting documentation.
    9| 
   10|   Shigeru Chiba makes no representations about the suitability of this 
   11|   software for any purpose.  It is provided "as is" without express or
   12|   implied warranty.
   13| */
   14| /*
   15|   Copyright (c) 1995, 1996 Xerox Corporation.
   16|   All Rights Reserved.
   17| 
   18|   Use and copying of this software and preparation of derivative works
   19|   based upon this software are permitted. Any copy of this software or
   20|   of any derivative work must include the above copyright notice of
   21|   Xerox Corporation, this paragraph and the one after it.  Any
   22|   distribution of this software or derivative works must comply with all
   23|   applicable United States export control laws.
   24| 
   25|   This software is made available AS IS, and XEROX CORPORATION DISCLAIMS
   26|   ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE
   27|   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   28|   PURPOSE, AND NOTWITHSTANDING ANY OTHER PROVISION CONTAINED HEREIN, ANY
   29|   LIABILITY FOR DAMAGES RESULTING FROM THE SOFTWARE OR ITS USE IS
   30|   EXPRESSLY DISCLAIMED, WHETHER ARISING IN CONTRACT, TORT (INCLUDING
   31|   NEGLIGENCE) OR STRICT LIABILITY, EVEN IF XEROX CORPORATION IS ADVISED
   32|   OF THE POSSIBILITY OF SUCH DAMAGES.
   33| */
   34| 
   35| #include <cstdio>
   36| #include <cstring>
   37| #include <cstdarg>
   38| #if !defined(_MSC_VER)
   39| #include <sys/time.h>
   40| #endif
   41| #include "ptree.h"
   42| #include "token.h"
   43| #include "mop.h"
   44| 
   45| #if (defined(sun) && defined(SUNOS4)) || defined(SUNOS5)
   46| extern "C" {
   47|     int gettimeofday(struct timeval*, void*);
   48| };
   49| #endif
   50| 
   51| const int MAX = 32;
   52| 
   53| static Ptree** resultsArgs[MAX];
   54| static int resultsIndex;
   55| 
   56| static int CountArgs(char* pat);
   57| static charSkipSpaces(char* pat);
   58| 
   59| bool Ptree::Match(Ptree* list, char* pattern, ...)
   60| {
   61|     va_list args;
   62|     int n = CountArgs(pattern);
   63|     if(n >= MAX)
   64|         MopErrorMessage("Ptree::Match()", "bomb! too many arguments");
   65| 
   66|     va_start(args, pattern);
   67|     for(int i = 0; i < n; ++i)
   68|         resultsArgs[i] = va_arg(args, Ptree**);
   69| 
   70|     va_end(args);
   71| 
   72|     char* pat = pattern;
   73|     resultsIndex = 0;
   74|     pat = SkipSpaces(pat);
   75|     pat = MatchPat(list, pat);
   76|     if(pat == nil)
   77|         return FALSE;
   78|     else{
   79|         pat = SkipSpaces(pat);
   80|         if(*pat == '\0')
   81|             return TRUE;
   82|         else{
   83|             MopWarningMessage("Ptree::Match()", "[ ] are forgot?");
   84|             MopMoreWarningMessage(pattern);
   85|             return FALSE;
   86|         }
   87|     }
   88| }
   89| 
   90| static int CountArgs(char* pat)
   91| {
   92|     int n = 0;
   93| 
   94|     for(char c = *pat; c != '\0'; c = *++pat)
   95|         if(c == '%'){
   96|             c = *++pat;
   97|             if(c == '?' || c == 'r')
   98|         ++n;
   99|         }
  100| 
  101|     return n;
  102| }
  103| 
  104| char* Ptree::MatchPat(Ptree* list, char* pat)
  105| {
  106|     switch(*pat){
  107|     case '[' :         /* [] mea
  108|         if(list != nil && list->IsLeaf())
  109|             return nil;
  110|         else
  111|             return MatchList(list, pat + 1);
  112|     case '%' :
  113|         switch(pat[1]){
  114|         case '?' :
  115|             *resultsArgs[resultsIndex++] = list;
  116|             return(pat + 2);
  117|         case '*' :
  118|             return(pat + 2);
  119|         case '_' :
  120|         case 'r' :     /* %_ and %r must be appear in a li
  121|             return nil;
  122|         default :
  123|           break;
  124|         }
  125|     }
  126| 
  127|     if(list != nil && list->IsLeaf())
  128|         return MatchWord(list, pat);
  129|     else
  130|         return nil;
  131| }
  132| 
  133| char* Ptree::MatchList(Ptree* list, char* pat)
  134| {
  135|     char c, d;
  136|     pat = SkipSpaces(pat);
  137|     while((c = *pat) != '\0'){
  138|         if(c == ']')
  139|             if(list == nil)
  140|                return(pat + 1);
  141|         else
  142|                return nil;
  143|         else if(c == '%' && (d = pat[1], (d == 'r' || d == '_'))){
  144|             /* %r or %_ */
  145|             if(d == 'r') 
  146|                *resultsArgs[resultsIndex++] = list;
  147| 
  148|             list = nil;
  149|             pat = pat + 2;
  150|         }
  151|         else if(list == nil)
  152|             return nil;
  153|         else{
  154|             pat = MatchPat(list->Car(), pat);
  155|             if(pat == nil)
  156|                return nil;
  157| 
  158|             list = list->Cdr();
  159|         }
  160| 
  161|         pat = SkipSpaces(pat);
  162|     }
  163| 
  164|     MopErrorMessage("Ptree::Match()", "unmatched bracket");
  165|     return nil;
  166| }
  167| 
  168| char* Ptree::MatchWord(Ptree* list, char* pat)
  169| {
  170|     char* str = list->GetPosition();
  171|     int str_len = list->GetLength();
  172| 
  173|     for(int j = 0; ; ++pat){
  174|         char c = *pat;
  175|         switch(c){
  176|         case '\0' :
  177|         case ' ' :
  178|         case '\t' :
  179|         case '[' :
  180|         case ']' :
  181|             if(j == str_len)
  182|                return pat;
  183|         else
  184|                return nil;
  185|         case '%' :
  186|             c = *++pat;
  187|             switch(c){
  188|             case '[' :
  189|             case ']' :
  190|             case '%' :
  191|                if(j >= str_len || c != str[j++])
  192|                return nil;
  193| 
  194|         break;
  195|             default :
  196|                if(j == str_len)
  197|                return pat;
  198|         else
  199|                return nil;
  200|         }
  201|           break;
  202|         default :
  203|             if(j >= str_len || c != str[j++])
  204|                return nil;
  205|         }
  206|     }
  207| }
  208| 
  209| static char* SkipSpaces(char* pat)
  210| {
  211|     while(*pat == ' ' || *pat == '\t')
  212|         ++pat;
  213| 
  214|     return pat;
  215| }
  216| 
  217| Ptree* Ptree::GenSym()
  218| {
  219| #if !defined(_MSC_VER)
  220|     struct timeval time;
  221| #endif
  222|     static char head[] = "_sym";
  223|     static int seed = 1;
  224|     int len1, len2;
  225| 
  226|     IntegerToString(seed, len1);
  227| 
  228| #if !defined(_MSC_VER)
  229|     gettimeofday(&time, NULL);
  230|     uint rnum = (time.tv_sec * 10 + time.tv_usec / 100) & 0xffff;
  231| #else
  232|     static uint time = 0;
  233|     time++;
  234|     uint rnum = time & 0xffff;
  235| #endif
  236|     char* num = IntegerToString(rnum, len2);
  237| 
  238|     int size = len1 + len2 + sizeof(head) - 1 + 1;
  239|     char* name = new (GC) char[size];
  240|     memmove(name, head, sizeof(head) - 1);
  241|     memmove(&name[sizeof(head) - 1], num, len2);
  242|     name[sizeof(head) - 1 + len2] = '_';
  243|     num = IntegerToString(seed++, len1);
  244|     memmove(&name[sizeof(head) - 1 + len2 + 1], num, len1);
  245|     return new Leaf(name, size);
  246| }
  247| 
  248| // If you edit Make(), you should also edit MakeStatement().
  249| 
  250| Ptree* Ptree::Make(const char* pat, ...)
  251| {
  252|     va_list args;
  253|     const int N = 4096;
  254|     static char buf[N];
  255|     char c;
  256|     int len;
  257|     char* ptr;
  258|     Ptree* p;
  259|     Ptree* q;
  260|     int i = 0, j = 0;
  261|     Ptree* result = nil;
  262| 
  263|     va_start(args, pat);
  264|     while((c = pat[i++]) != '\0')
  265|         if(c == '%'){
  266|             c = pat[i++];
  267|             if(c == '%')
  268|                buf[j++] = c;
  269|             else if(c == 'd'){
  270|                ptr = IntegerToString(va_arg(args, int), len);
  271|                memmove(&buf[j], ptr, len);
  272|                j += len;
  273|         }
  274|             else if(c == 's'){
  275|                ptr = va_arg(args, char*);
  276|                len = strlen(ptr);
  277|                memmove(&buf[j], ptr, len);
  278|                j += len;
  279|         }
  280|             else if(c == 'c')
  281|                buf[j++] = va_arg(args, int);
  282|             else if(c == 'p'){
  283|                p = va_arg(args, Ptree*);
  284|                if(p == nil)
  285|                  /* ignore */;
  286|                else if(p->IsLeaf()){
  287|                    memmove(&buf[j], p->GetPosition(), p->GetLength());
  288|                    j += p->GetLength();
  289|         }
  290|                else{   
  291|                if(j > 0)
  292|                       q = List(new DupLeaf(buf, j), p);
  293|                else
  294|                q = List(p);
  295| 
  296|                j = 0;
  297|                    result = Nconc(result, q);
  298|         }
  299|         }
  300|         else
  301|                MopErrorMessage("Ptree::Make()", "invalid format");
  302|         }
  303|         else
  304|             buf[j++] = c;
  305| 
  306|     va_end(args);
  307| 
  308|     if(j > 0)
  309|         if(result == nil)
  310|             result = new DupLeaf(buf, j);
  311|         else
  312|             result = Snoc(result, new DupLeaf(buf, j));
  313| 
  314|     return result;
  315| }
  316| 
  317| /*
  318|   MakeStatement() is identical to Make() except that the generated
  319|   code is wrapped by a PtreeNonExpr object.
  320|   This helps code-traverse functions such as WalkExpr() distinguish
  321|   statements from expressions.
  322| 
  323|   Note: this version is perfectly identical to Make(). 97/3/26
  324| */
  325| Ptree* Ptree::MakeStatement(const char* pat, ...)
  326| {
  327|     va_list args;
  328|     const int N = 4096;
  329|     static char buf[N];
  330|     char c;
  331|     int len;
  332|     char* ptr;
  333|     Ptree* p;
  334|     Ptree* q;
  335|     int i = 0, j = 0;
  336|     Ptree* result = nil;
  337| 
  338|     va_start(args, pat);
  339| 
  340|     Class::WarnObsoleteness("Ptree::MakeStatement()", "Ptree::Make()");
  341| 
  342|     while((c = pat[i++]) != '\0')
  343|         if(c == '%'){
  344|             c = pat[i++];
  345|             if(c == '%')
  346|                buf[j++] = c;
  347|             else if(c == 'd'){
  348|                ptr = IntegerToString(va_arg(args, int), len);
  349|                memmove(&buf[j], ptr, len);
  350|                j += len;
  351|         }
  352|             else if(c == 's'){
  353|                ptr = va_arg(args, char*);
  354|                len = strlen(ptr);
  355|                memmove(&buf[j], ptr, len);
  356|                j += len;
  357|         }
  358|             else if(c == 'c')
  359|                buf[j++] = va_arg(args, int);
  360|             else if(c == 'p'){
  361|                p = va_arg(args, Ptree*);
  362|                if(p == nil)
  363|                  /* ignore */;
  364|                else if(p->IsLeaf()){
  365|                    memmove(&buf[j], p->GetPosition(), p->GetLength());
  366|                    j += p->GetLength();
  367|         }
  368|                else{   
  369|                if(j > 0)
  370|                       q = new DupLeaf(buf, j);
  371|                else
  372|                q = nil;
  373| 
  374|                j = 0;
  375|                    result = Nconc(result, List(q, p));
  376|         }
  377|         }
  378|         else
  379|                MopErrorMessage("Ptree::MakeStatement()", "invalid format");
  380|         }
  381|         else
  382|             buf[j++] = c;
  383| 
  384|     va_end(args);
  385| 
  386|     if(j > 0)
  387|         if(result == nil)
  388|             result = new DupLeaf(buf, j);
  389|         else
  390|             result = Snoc(result, new DupLeaf(buf, j));
  391| 
  392|     return result;
  393| }
  394| 
  395| bool Ptree::Reify(unsigned int& value)
  396| {
  397|     return Lex::Reify(this, value);
  398| }
  399| 
  400| bool Ptree::Reify(char*& str)
  401| {
  402|     return Lex::Reify(this, str);
  403| }
  404| 
  405| char* Ptree::IntegerToString(sint num, int& length)
  406| {
  407|     const int N = 16;
  408|     static char buf[N];
  409|     bool minus;
  410| 
  411|     int i = N - 1;
  412|     if(num >= 0)
  413|         minus = FALSE;
  414|     else{
  415|         minus = TRUE;
  416|         num = -num;
  417|     }
  418| 
  419|     buf[i--] = '\0';
  420|     if(num == 0){
  421|         buf[i] = '0';
  422|         length = 1;
  423|         return &buf[i];
  424|     }
  425|     else{
  426|         while(num > 0){
  427|             buf[i--] = '0' + char(num % 10);
  428|             num /= 10;
  429|         }
  430| 
  431|         if(minus)
  432|             buf[i--] = '-';
  433| 
  434|         length = N - 2 - i;
  435|         return &buf[i + 1];
  436|     }
  437| }
  438| 
  439| Ptree* Ptree::qMake(char*)
  440| {
  441|     MopErrorMessage("Ptree::qMake()",
  442|                    "the metaclass must be compiled by OpenC++.");
  443|     return nil;
  444| }
  445| 
  446| Ptree* Ptree::qMakeStatement(char*)
  447| {
  448|     MopErrorMessage("Ptree::qMakeStatement()",
  449|                    "the metaclass must be compiled by OpenC++.");
  450|     return nil;
  451| }
  452| 
  453| // class PtreeHead      --- this is used to implement Ptree::qM
  454| 
  455| PtreeHead& PtreeHead::operator + (Ptree* p)
  456| {
  457|     ptree = Append(ptree, p);
  458|     return *this;
  459| }
  460| 
  461| PtreeHead& PtreeHead::operator + (const char* str)
  462| {
  463|     if(*str != '\0')
  464|         ptree =  Append(ptree, (char*)str, strlen(str));
  465| 
  466|     return *this;
  467| }
  468| 
  469| PtreeHead& PtreeHead::operator + (char* str)
  470| {
  471|     if(*str != '\0')
  472|         ptree =  Append(ptree, str, strlen(str));
  473| 
  474|     return *this;
  475| }
  476| 
  477| PtreeHead& PtreeHead::operator + (char c)
  478| {
  479|     ptree =  Append(ptree, &c, 1);
  480|     return *this;
  481| }
  482| 
  483| PtreeHead& PtreeHead::operator + (int n)
  484| {
  485|     int len;
  486|     char* str = Ptree::IntegerToString(n, len);
  487|     ptree =  Append(ptree, str, len);
  488|     return *this;
  489| }
  490| 
  491| Ptree* PtreeHead::Append(Ptree* lst, Ptree* tail)
  492| {
  493|     Ptree* last;
  494|     Ptree* p;
  495|     Ptree* q;
  496| 
  497|     if(tail == nil)
  498|         return lst;
  499| 
  500|     if(!tail->IsLeaf() && tail->Length() == 1){
  501|         tail = tail->Car();
  502|         if(tail == nil)
  503|             return lst;
  504|     }
  505| 
  506|     if(tail->IsLeaf() && lst != nil){
  507|         last = Ptree::Last(lst);
  508|         if(last != nil){
  509|             p = last->Car();
  510|             if(p != nil && p->IsLeaf()){
  511|                q = new DupLeaf(p->GetPosition(), p->GetLength(),
  512|                               tail->GetPosition(), tail->GetLength());
  513|                last->SetCar(q);
  514|                return lst;
  515|         }
  516|         }
  517|     }
  518| 
  519|     return Ptree::Snoc(lst, tail);
  520| }
  521| 
  522| Ptree* PtreeHead::Append(Ptree* lst, char* str, int len)
  523| {
  524|     Ptree* last;
  525|     Ptree* p;
  526|     Ptree* q;
  527| 
  528|     if(lst != nil){
  529|         last = Ptree::Last(lst);
  530|         if(last != nil){
  531|             p = last->Car();
  532|             if(p != nil && p->IsLeaf()){
  533|                q = new DupLeaf(p->GetPosition(), p->GetLength(),
  534|                str, len);
  535|                last->SetCar(q);
  536|                return lst;
  537|         }
  538|         }
  539|     }
  540| 
  541|     return Ptree::Snoc(lst, new DupLeaf(str, len));
  542| }