Modules | Files | Inheritance Tree | Inheritance Graph | Name Index | Config
File: Synopsis/Parser/C++/occ/buffer.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 <iostream>
   36| #include <string>
   37| #include <cstring>
   38| #include <cstdlib>
   39| #include "buffer.h"
   40| #include "token.h"
   41| #include "ptree-core.h"
   42| #include "mop.h"
   43| 
   44| #if defined(_PARSE_VCC)
   45| #define _MSC_VER        
   46| #endif
   47| 
   48| // Compiler Firewalled private data
   49| struct LineMapNode {
   50|     // Position in file buffer
   51|     uint pos;
   52|     // Line number
   53|     int line;
   54|     // Filename
   55|     charfilename;
   56|     // Filename length
   57|     int filename_len;
   58| };
   59| 
   60| struct Program::Private {
   61|     // This only works if you ask for the line numbers in order
   62|     LineMapNode firstlast;
   63| 
   64|     // Find the last pos in the map
   65|     uint lastPos() {
   66|         return last.pos;
   67|     }
   68|     void start(LineMapNode& node) {
   69|         first = last = node;
   70|     }
   71|     void insert(LineMapNode& node) {
   72|         //cout << "### Inserting node at " << node.pos << " line " << node.line;
   73|         //cout << " in " << std::string(node.filename, node.filename_len) << endl;
   74|         last = node;
   75|     }
   76| };
   77| 
   78| Program::Program(char* name)
   79| {
   80|     replacement = nil;
   81|     defaultname = name;
   82|     m = new Private;
   83|     // Add defaultname at line 0
   84|     LineMapNode node;
   85|     node.pos = 0node.line = 0;
   86|     node.filename = name;
   87|     node.filename_len = strlen(name);
   88|     m->start(node);
   89| }
   90| 
   91| Program::~Program()
   92| {
   93|     delete m;
   94| }
   95| 
   96| char Program::Get()
   97| {
   98|     if(buf[index] == '\0')
   99|         return buf[index];
  100|     else
  101|         return buf[index++];
  102| }
  103| 
  104| void Program::Subst(Ptree* newtext, Ptree* oldtext)
  105| {
  106|     Replace(oldtext->LeftMost(), oldtext->RightMost(), newtext);
  107| }
  108| 
  109| void Program::Insert(Ptree* pos, Ptree* before_text, Ptree* after_text)
  110| {
  111|     charp;
  112| 
  113|     if(before_text != nil){
  114|         p = pos->LeftMost();
  115|         Replace(ppbefore_text);
  116|     }
  117| 
  118|     if(after_text != nil){
  119|         p = pos->RightMost();
  120|         Replace(ppafter_text);
  121|     }
  122| }
  123| 
  124| void Program::MinimumSubst(Ptree* newtext, Ptree* oldtext)
  125| {
  126|     if(MinimumSubst2(newtextoldtext))
  127|         Subst(newtextoldtext);
  128| }
  129| 
  130| bool Program::MinimumSubst2(Ptree* newtext, Ptree* oldtext)
  131| {
  132|     int what;
  133|     if(oldtext == newtext)
  134|         return FALSE;
  135|     else if(oldtext == nil || newtext == nil)
  136|         return TRUE;
  137|     else if(what = newtext->What(),
  138|             (what == ntExprStatement || what == ntTypedef))
  139|         return TRUE;
  140|     else if(oldtext->IsLeaf() || newtext->IsLeaf())
  141|         return TRUE;
  142|     else if(oldtext->Car() == nil && oldtext->Cdr() == nil)
  143|         return TRUE;
  144|     else if(oldtext == newtext->Cdr()){
  145|         Insert(oldtextnewtext->Car(), nil);
  146|         return FALSE;
  147|     }
  148|     else if(oldtext->Car() != nil && oldtext->Car() == newtext->Second()){
  149|         Insert(oldtext->Car(), newtext->Car(), nil);
  150|         newtext = newtext->ListTail(2);
  151|         if(MinimumSubst2(newtextoldtext->Cdr()))
  152|             if(oldtext->Cdr() == nil)
  153|                Insert(oldtext->Car(), nil, newtext);
  154|         else
  155|                Subst(newtextoldtext->Cdr());
  156| 
  157|         return FALSE;
  158|     }
  159|     else{
  160|         bool dirty1 = MinimumSubst2(newtext->Car(), oldtext->Car());
  161|         bool dirty2 = MinimumSubst2(newtext->Cdr(), oldtext->Cdr());
  162|         if(dirty1 == dirty2)
  163|             return dirty1;
  164|         else if(dirty1)
  165|             if(oldtext->Cdr() == nil && newtext->Cdr() == nil)
  166|                return TRUE;
  167|             else if(oldtext->Car() == nil)
  168|                Insert(oldtext->Cdr(), newtext->Car(), nil);
  169|         else
  170|                Subst(newtext->Car(), oldtext->Car());
  171|         else
  172|             if(oldtext->Car() == nil && newtext->Car() == nil)
  173|                return TRUE;
  174|             else if(oldtext->Cdr() == nil)
  175|                Insert(oldtext->Car(), nil, newtext->Cdr());
  176|         else
  177|                Subst(newtext->Cdr(), oldtext->Cdr());
  178| 
  179|         return FALSE;
  180|     }
  181| }
  182| 
  183| void Program::Replace(char* startpos, char* endpos, Ptree* text)
  184| {
  185|     if(startpos == nil || endpos == nil)
  186|         return;
  187| 
  188|     uint start = uint(startpos - buf);
  189|     uint end = uint(endpos - buf);
  190|     Replacementp = replacement;
  191|     if(p == nil)
  192|         replacement = new Replacement(nil, start, end, text);
  193|     else if(p->next == nil)
  194|         if(start < p->startpos)
  195|             replacement = new Replacement(p, start, end, text);
  196|         else
  197|             p->next = new Replacement(nil, start, end, text);
  198|     else{
  199|         for(; p->next != nil; p = p->next)
  200|             if(start < p->next->startpos)
  201|         break;
  202| 
  203|         p->next = new Replacement(p->next, start, end, text);
  204|     }
  205| }
  206| 
  207| /*
  208|   LineNumber() returns the line number of the line pointed to by PTR.
  209| */
  210| uint Program::LineNumber(char* ptr, char*& filename, int& filename_length)
  211| {
  212|     sint n;
  213|     int  len;
  214|     uint name;
  215|     int nline = 0;
  216| 
  217|     // Determine pos in file
  218|     uint pos = uint(ptr - buf), startpos = pos;
  219|     if(pos > size){
  220|         // error?
  221|         filename = defaultname;
  222|         filename_length = strlen(defaultname);
  223|         return 0;
  224|     }
  225| 
  226|     // Determine if already passed this point
  227|     uint lastpos = m->lastPos();
  228| 
  229|     sint line_number = -1;
  230|     filename_length = 0;
  231| 
  232|     while(pos != lastpos){
  233|         switch(Ref(--pos)){
  234|         case '\n' :
  235|             ++nline;
  236|           break;
  237|         case '#' :
  238|             len = 0;
  239|             n = ReadLineDirective(pos, -1namelen);
  240|             if(n >= 0){                      
  241|                if(line_number < 0)
  242|                    line_number = n + nline;
  243| 
  244|                if(len > 0 && filename_length == 0){
  245|                    filename = (char*)Read(name);
  246|                    filename_length = len;
  247|         }
  248|         }
  249|           break;
  250|         }
  251| 
  252|         if(line_number >= 0 && filename_length > 0) {
  253|             //cout << "### Reached line directive at " << pos << endl;
  254|             // We reached a line directive. Record this node
  255|             LineMapNode node;
  256|             node.pos = startposnode.line = line_number;
  257|             node.filename = filenamenode.filename_len = filename_length;
  258|             m->insert(node);
  259|             return line_number;
  260|         }
  261|     }
  262| 
  263|     //cout << "### Reached end of map at " << pos << endl;
  264| 
  265|     // We reached the last recorded node, so use that to work it out
  266|     LineMapNodenode = m->last;
  267| 
  268|     if(filename_length == 0){
  269|         filename = node.filename;
  270|         filename_length = node.filename_len;
  271|     }
  272| 
  273|     if(line_number < 0)
  274|         line_number = nline + node.line;
  275| 
  276|     // Now record this new node for future reference
  277|     LineMapNode newnode;
  278|     newnode.pos = startposnewnode.line = line_number;
  279|     newnode.filename = filenamenewnode.filename_len = filename_length;
  280|     m->insert(newnode);
  281| 
  282|     return line_number;
  283| }
  284| 
  285| /*
  286|   Write() saves the program as a file named FILE_NAME.
  287|   This assumes that the first line of the program is
  288|   a # line directive.
  289| */
  290| void Program::Write(std::ostream& out, const char* file_name)
  291| {
  292|     Replacementrep = replacement;
  293|     uint pos;
  294|     uint nlines = 1;
  295|     uint line_number = 1;
  296|     uint i = 0;
  297|     char c;
  298| 
  299|     uint filename = 0;
  300|     int filename_length = 0;
  301| 
  302|     if(Ref(i) == '#')
  303|         line_number = ReadLineDirective(i, (sint)line_number,
  304|                              filenamefilename_length);
  305| 
  306|     for(; rep != nil; rep = rep->next){
  307|         pos = rep->startpos;
  308|         while(i < pos){
  309|             c = Ref(i++);
  310|             if(c == '\0'){
  311|         --i;
  312|         break;
  313|         }
  314| 
  315|             out << c;
  316|             if(c == '\n'){
  317|                ++nlines;
  318|                ++line_number;
  319|                if(Ref(i) == '#')
  320|                    line_number = ReadLineDirective(i, (sint)line_number,
  321|                                     filenamefilename_length);
  322|         }
  323|         }
  324| 
  325|         if(i > 0 && Ref(i - 1) != '\n'){
  326|             out << '\n';
  327|             ++nlines;
  328|         }
  329| 
  330| #if defined(_MSC_VER) || defined(IRIX_CC)
  331|         out << "#line " << nlines + 1 << " \"" << file_name << "\"\n";
  332| #else
  333|         out << "# " << nlines + 1 << " \"" << file_name << "\"\n";
  334| #endif
  335|         ++nlines;
  336|         nlines += rep->text->Write(out);
  337|         pos = rep->endpos;
  338|         if(rep->next != nil && rep->next->startpos <= pos){
  339|             rep = rep->next;
  340|             out << '\n';
  341|             ++nlines;
  342|             nlines += rep->text->Write(out);
  343|             if(rep->endpos > pos)
  344|                pos = rep->endpos;
  345|         }
  346| 
  347|         while(i < pos){
  348|             c = Ref(i++);
  349|             if(c == '\0'){
  350|         --i;
  351|         break;
  352|         }
  353|             else if(c == '\n'){
  354|                ++line_number;
  355|                if(Ref(i) == '#')
  356|                    line_number = ReadLineDirective(i, (sint)line_number,
  357|                                     filenamefilename_length);
  358|         }
  359|         }
  360| 
  361| #if defined(_MSC_VER) || defined(IRIX_CC)
  362|         out << "\n#line " << line_number << ' ';
  363| #else
  364|         out << "\n# " << line_number << ' ';
  365| #endif
  366|         ++nlines;
  367|         if(filename_length > 0)
  368|             for(int j = 0j < filename_length; ++j)
  369|                out << (char)Ref(filename + j);
  370|         else
  371|             out << '"' << defaultname << '"';
  372| 
  373|         out << '\n';
  374|         ++nlines;
  375|     }
  376| 
  377|     while((c = Ref(i++)) != '\0'){
  378|         out << c;
  379|         if(c == '\n')
  380|             ++nlines;
  381|     }
  382| 
  383| #if defined(_MSC_VER) || defined(IRIX_CC)
  384|     out << "\n#line " << nlines + 2 << " \"" << file_name << "\"\n";
  385| #else
  386|     out << "\n# " << nlines + 2 << " \"" << file_name << "\"\n";
  387| #endif
  388|     Class::FinalizeAll(out);
  389|     opcxx_ListOfMetaclass::FinalizeAll(out);
  390| }
  391| 
  392| sint Program::ReadLineDirective(uint i, sint line_number,
  393|                              uint& filename, int& filename_length)
  394| {
  395|     char c;
  396| 
  397|     do{
  398|         c = Ref(++i);
  399|     }while(is_blank(c));
  400| 
  401| #if defined(_MSC_VER) || defined(IRIX_CC)
  402|     if(i + 4 <= GetSize() && strncmp(Read(i), "line", 4) == 0){
  403|         i += 3;
  404|         do{
  405|             c = Ref(++i);
  406|         }while(is_blank(c));
  407|     }
  408| #endif
  409| 
  410|     if(is_digit(c)){           /* # <line> <file> */
  411|         uint num = c - '0';
  412|         for(;;){
  413|             c = Ref(++i);
  414|             if(is_digit(c))
  415|                num = num * 10 + c - '0';
  416|         else
  417|         break;
  418|         }
  419| 
  420|         line_number = num - 1; /* line_number'll be incremented soon *
  421| 
  422|         if(is_blank(c)){
  423|         do{
  424|                c = Ref(++i);
  425|             }while(is_blank(c));
  426|             if(c == '"'){
  427|                uint fname_start = i;
  428|         do{
  429|                  c = Ref(++i);
  430|                while(c != '"');
  431|                if(i > fname_start + 2){
  432|                    filename = fname_start;
  433|                    filename_length = int(i - fname_start + 1);
  434|         }
  435|         }
  436|         }
  437|     }
  438| 
  439|     return line_number;
  440| }
  441| 
  442| // class Program::Replacement
  443| 
  444| Program::Replacement::Replacement(Replacement* n, uint st,
  445|                       uint ed, Ptree* t)
  446| {
  447|     next = n;
  448|     startpos = st;
  449|     endpos = ed;
  450|     text = t;
  451| }
  452| 
  453| // subclasses
  454| 
  455| ProgramFile::ProgramFile(std::ifstream& f, char *filename)
  456| : Program(filename)
  457| {
  458|     f.seekg(0, std::ios::end);
  459|     size = f.tellg();
  460|     f.seekg(0);
  461| 
  462|     buf = new char[size + 1];
  463|     f.read(buf, int(size));
  464| #if defined(_WIN32)
  465|     // Under win31/95/NT, the pair CR-LF is replaced by LF,
  466|     // implying a smallest size
  467|     size = f.gcount();
  468| #endif
  469|     buf[size] = '\0';
  470|     index = 0;
  471| }
  472| 
  473| ProgramFile::~ProgramFile()
  474| {
  475|     delete [] buf;
  476|     buf = nil;
  477| }
  478| 
  479| ProgramFromStdin::ProgramFromStdin()
  480| : Program("stdin")
  481| {
  482|     const int Size = 512 * 1024;
  483|     buf = new char[Size];
  484|     buf_size = Size;
  485|     index = size = 0;
  486| }
  487| 
  488| ProgramFromStdin::~ProgramFromStdin()
  489| {
  490|     delete [] buf;
  491|     buf = nil;
  492| }
  493| 
  494| char ProgramFromStdin::Get()
  495| {
  496|     if(size >= buf_size){
  497|         std::cerr << "ProgramFromStdin: sorry, out of memory\n";
  498|         exit(1);
  499|     }
  500| 
  501|     if(index >= size){
  502|         int c = std::cin.get();
  503|         if(c == EOF)
  504|             c = '\0';
  505| 
  506|         buf[size++] = c;
  507|     }
  508| 
  509|     if(buf[index] == '\0')
  510|         return buf[index];
  511|     else
  512|         return buf[index++];
  513| }
  514| 
  515| // class ProgramString
  516| 
  517| const int Quantum = 4;
  518| const int BufSize = 1 << Quantum;
  519| 
  520| ProgramString::ProgramString()
  521| : Program("unknown")
  522| {
  523|     buf = new (GC) char[BufSize];
  524|     buf[0] = '\0';
  525|     size = BufSize;
  526|     index = str_length = 0;
  527| }
  528| 
  529| ProgramString::~ProgramString()
  530| {
  531| //  delete [] buf;
  532|     buf = nil;
  533| }
  534| 
  535| ProgramString& ProgramString::operator << (const char* str)
  536| {
  537|     int len = strlen(str) + 1;
  538| 
  539|     if(str_length + len < size){
  540|         memmove(&buf[str_length], str, len);
  541|         str_length += len - 1;
  542|     }
  543|     else{
  544|         size = (str_length + len + BufSize) & ~(BufSize - 1);
  545|         char* newbuf = new (GC) char[size];
  546|         memmove(newbuf, buf, size_t(str_length));
  547|         memmove(&newbuf[str_length], str, len);
  548| //      delete [
  549|         buf = newbuf;
  550|         str_length += len - 1;
  551|     }
  552| 
  553|     return *this;
  554| }
  555| 
  556| ProgramString& ProgramString::operator << (const char c)
  557| {
  558|     if(str_length + 2 < size){
  559|         buf[str_length] = c;
  560|         buf[++str_length] = '\0';
  561|     }
  562|     else{
  563|         size = (str_length + 2 + BufSize) & ~(BufSize - 1);
  564|         char* newbuf = new (GC) char[size];
  565|         memmove(newbuf, buf, size_t(str_length));
  566|         newbuf[str_length] = c;
  567|         newbuf[++str_length] = '\0';
  568| //      delete [
  569|         buf = newbuf;
  570|     }
  571| 
  572|     return *this;
  573| }