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 #include "schema_cursor.h"
 27 #include <iostream>
 28 #include<cstring>
 29 
 30 
 31 SchemaCursor::SchemaCursor(char *ptr): ptr(ptr) {
 32 }
 33 
 34 SchemaCursor::~SchemaCursor() = default;
 35 
 36 void SchemaCursor::in(const char *location) {
 37     where.push(location);
 38 }
 39 
 40 void SchemaCursor::out() {
 41     where.pop();
 42 }
 43 
 44 SchemaCursor *SchemaCursor::skipWhiteSpace() {
 45     while (*ptr == ' ' || *ptr == '\n' || *ptr == '\t') {
 46         step(1);
 47     }
 48     return this;
 49 }
 50 
 51 
 52 SchemaCursor *SchemaCursor::skipIdentifier() {
 53     while (peekAlpha() || peekDigit()) {
 54         step(1);
 55     }
 56     return this;
 57 }
 58 
 59 void SchemaCursor::step(int count) {
 60     while (count--) {
 61         ptr++;
 62     }
 63 }
 64 
 65 bool SchemaCursor::peekAlpha() {
 66     skipWhiteSpace();
 67     return (::isalpha(*ptr));
 68 }
 69 
 70 bool SchemaCursor::peekDigit() {
 71     skipWhiteSpace();
 72     return (::isdigit(*ptr));
 73 }
 74 
 75 bool SchemaCursor::is(const char ch) {
 76     skipWhiteSpace();
 77     if (*ptr == ch) {
 78         step(1);
 79         return true;
 80     }
 81     return false;
 82 }
 83 
 84 bool SchemaCursor::isColon() {
 85     return is(':');
 86 }
 87 
 88 bool SchemaCursor::expect(char ch, const char *context, int line) {
 89     if (is(ch)) {
 90         return true;
 91     }
 92     if (!where.empty()) {
 93         std::cerr << where.top() << " ";
 94     }
 95     std::cerr << "@" << line << ": parse error expecting  '" << ch << "' " << context << " looking at " << ptr <<
 96             std::endl;
 97    // exit(1);
 98     return false;
 99 }
100 
101 bool SchemaCursor::expect(const char ch, const int line) {
102     return expect(ch, "", line);
103 }
104 
105 bool SchemaCursor::expectDigit(const char *context, const int line) {
106     if (::isdigit(*ptr)) {
107         return true;
108     }
109     if (!where.empty()) {
110         std::cerr << where.top() << " ";
111     }
112     std::cerr << "@" << line << ": parse error expecting digit " << context << " looking at " << ptr << std::endl;
113    // exit(1);
114     return false;
115 }
116 
117 bool SchemaCursor::expectAlpha(const char *context, const 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 
129 bool SchemaCursor::isEither(const char ch1, const char ch2, char *actual) {
130     skipWhiteSpace();
131     if (*ptr == ch1 || *ptr == ch2) {
132         step(1);
133         *actual = *ptr;
134         return true;
135     }
136     return false;
137 }
138 
139 void SchemaCursor::expectEither(const char ch1, const char ch2, char *actual, const int line) {
140     skipWhiteSpace();
141     if (*ptr == ch1 || *ptr == ch2) {
142         step(1);
143         *actual = *ptr;
144         return;
145     }
146     if (!where.empty()) {
147         std::cerr << where.top() << " ";
148     }
149     std::cerr << "@" << line << ": parse error expecting  '" << ch1 << "' or '" << ch2 << "'  looking at " << ptr <<
150             std::endl;
151     exit(1);
152 }
153 
154 int SchemaCursor::getInt() {
155     const int value = *ptr - '0';
156     step(1);
157     if (peekDigit()) {
158         return value * 10 + getInt();
159     }
160     return value;
161 }
162 
163 long SchemaCursor::getLong() {
164     const long value = *ptr - '0';
165     step(1);
166     if (peekDigit()) {
167         return value * 10 + getLong();
168     }
169     return value;
170 }
171 
172 char *SchemaCursor::getIdentifier() {
173     const char *identifierStart = ptr;
174     skipIdentifier();
175     const size_t len = ptr - identifierStart;
176     auto identifier = new char[len + 1];
177     memcpy(identifier, identifierStart, len);
178     identifier[len] = '\0';
179     return identifier;
180 }
181 
182 void SchemaCursor::error(std::ostream &ostream, const char *file,  const int line, const char *str) const {
183     ostream << file << ":" << "@" << line << ": parse error " << str << " looking at " << ptr << std::endl;
184     exit(1);
185 }