1 /*
  2  * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 #pragma once
 27 #include <vector>
 28 #include <cstring>
 29 #include <iostream>
 30 #include <iomanip>
 31 #include <stack>
 32 
 33 struct Cursor {
 34 private:
 35     std::stack<const char *> where;
 36 public:
 37     char *ptr;
 38     Cursor(char *ptr): ptr(ptr) {
 39     }
 40     virtual ~Cursor() {
 41     }
 42     void in(const char * location){
 43         where.push(location);
 44     }
 45     void out(){
 46         where.pop();
 47     }
 48 private:
 49     Cursor *skipWhiteSpace() {
 50         while (*ptr == ' ' || *ptr == '\n' || *ptr == '\t') {
 51             step(1);
 52         }
 53         return this;
 54     }
 55 
 56 
 57     Cursor *skipIdentifier() {
 58         while (peekAlpha() || peekDigit()) {
 59             step(1);
 60         }
 61         return this;
 62     }
 63 public:
 64     void step(int count) {
 65         while (count--) {
 66             ptr++;
 67         }
 68     }
 69 
 70     bool peekAlpha() {
 71         skipWhiteSpace();
 72         return (::isalpha(*ptr));
 73     }
 74 
 75     bool peekDigit() {
 76         skipWhiteSpace();
 77         return (::isdigit(*ptr));
 78     }
 79 
 80     bool is(char ch) {
 81         skipWhiteSpace();
 82         if (*ptr == ch) {
 83             step(1);
 84             return true;
 85         }
 86         return false;
 87     }
 88     bool isColon() {
 89        return is(':');
 90     }
 91 
 92     bool expect(char ch, const char *context,  int line ) {
 93         if (is(ch)){
 94             return true;
 95         }
 96         if (!where.empty()){
 97             std::cerr << where.top() << " ";
 98         }
 99         std::cerr << "@" << line << ": parse error expecting  '" << ch << "' "<< context <<" looking at " << ptr << std::endl;
100         exit(1);
101         return false;
102     }
103     bool expect(char ch,  int line ) {
104         return expect(ch, "", line);
105     }
106     bool expectDigit(const char *context,  int line ) {
107         if (::isdigit(*ptr)){
108             return true;
109         }
110         if (!where.empty()){
111             std::cerr << where.top() << " ";
112         }
113         std::cerr << "@" << line << ": parse error expecting digit "<< context <<" looking at " << ptr << std::endl;
114         exit(1);
115         return false;
116     }
117     bool expectAlpha(const char *context,  int line ) {
118         if (::isalpha(*ptr)){
119             return true;
120         }
121         if (!where.empty()){
122             std::cerr << where.top() << " ";
123         }
124         std::cerr << "@" << line << ": parse error expecting alpha "<< context <<" looking at " << ptr << std::endl;
125         exit(1);
126         return false;
127     }
128     bool isEither(char ch1, char ch2, char*actual) {
129         skipWhiteSpace();
130         if (*ptr == ch1 || *ptr == ch2) {
131             step(1);
132             *actual = *ptr;
133             return true;
134         }
135         return false;
136     }
137     void expectEither(char ch1, char ch2, char*actual, int line) {
138         skipWhiteSpace();
139         if (*ptr == ch1 || *ptr == ch2) {
140             step(1);
141             *actual = *ptr;
142             return;
143         }
144         if (!where.empty()){
145             std::cerr << where.top() << " ";
146         }
147         std::cerr << "@" << line << ": parse error expecting  '" << ch1 << "' or '"<<ch2<< "'  looking at " << ptr << std::endl;
148         exit(1);
149 
150     }
151     /*bool is(char *str) {
152         skipWhiteSpace();
153         int count = 0;
154         char *safePtr = ptr;
155         while (*str && *ptr && *str == *ptr) {
156             ptr++;
157             str++;
158             count++;
159         }
160         if (count > 0 && *str == '\0') {
161             step(count);
162             return true;
163         }
164         ptr = safePtr;
165         return false;
166     }*/
167 
168     int getInt() {
169         int value = *ptr - '0';
170         step(1);
171         if (peekDigit()) {
172             return value * 10 + getInt();
173         }
174         return value;
175     }
176 
177     long getLong() {
178         long value = *ptr - '0';
179         step(1);
180         if (peekDigit()) {
181             return value * 10 + getLong();
182         }
183         return value;
184     }
185 
186     char *getIdentifier() {
187         char *identifierStart = ptr;
188         skipIdentifier();
189         size_t len = ptr - identifierStart;
190         char *identifier = new char[len + 1];
191         std::memcpy(identifier, identifierStart, len);
192         identifier[len] = '\0';
193         return identifier;
194     }
195 
196     void error(std::ostream &ostream, const char *file, int line, const char *str) {
197         ostream << file << ":" << "@" << line << ": parse error " << str << " looking at " << ptr << std::endl;
198         exit(1);
199     }
200 
201 };
202 ;