1 /*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <iostream>
18 #include <sstream>
19
20 #include "Scanner.h"
21 #include "Specification.h"
22 #include "Utilities.h"
23
24 using namespace std;
25
26 // Maximum of errors we'll report before bailing out.
27 const int MAX_ERRORS = 10;
28
Scanner(const string & fileName,FILE * file)29 Scanner::Scanner(const string& fileName, FILE* file)
30 : mFileName(fileName), mFile(file), mLineNumber(0), mTagConsumed(true), mErrorCount(0) {
31 }
32
atEnd()33 bool Scanner::atEnd() {
34 return (mTagConsumed && feof(mFile)) || mErrorCount > MAX_ERRORS;
35 }
36
getChar()37 int Scanner::getChar() {
38 int c = fgetc(mFile);
39 if (c == '\n') {
40 mLineNumber++;
41 }
42 return c;
43 }
44
readUpTo(char delimiter,string * segment)45 void Scanner::readUpTo(char delimiter, string* segment) {
46 for (;;) {
47 int c = getChar();
48 if (c == EOF || c == '\n') {
49 break;
50 }
51 segment->push_back((char)c);
52 if (c == delimiter) {
53 break;
54 }
55 }
56 }
57
readRestOfLine(string * segment)58 void Scanner::readRestOfLine(string* segment) {
59 for (;;) {
60 int c = getChar();
61 if (c == EOF || c == '\n') {
62 return;
63 }
64 segment->push_back((char)c);
65 }
66 }
67
getNextEntry()68 bool Scanner::getNextEntry() {
69 mTag.clear();
70 mValue.clear();
71 for (;;) {
72 int c = getChar();
73 if (c == EOF) {
74 return false;
75 }
76 if (c == '#') {
77 // Skip the comment
78 string comment;
79 readRestOfLine(&comment);
80 continue;
81 }
82 if (c == ' ') {
83 readRestOfLine(&mValue);
84 break;
85 } else if (c == '\n') {
86 break;
87 } else {
88 mTag = c;
89 readUpTo(':', &mTag);
90 readRestOfLine(&mValue);
91 trimSpaces(&mValue);
92 break;
93 }
94 }
95 return true;
96 }
97
error()98 ostream& Scanner::error() {
99 return error(mLineNumber);
100 }
101
error(int lineNumber)102 ostream& Scanner::error(int lineNumber) {
103 if (++mErrorCount <= MAX_ERRORS) {
104 cerr << mFileName << ":" << lineNumber << ": error: ";
105 }
106 return cerr;
107 }
108
skipBlankEntries()109 void Scanner::skipBlankEntries() {
110 while (findOptionalTag("")) {
111 if (!mValue.empty()) {
112 error() << "Unexpected: \" " << mValue << "\".\n";
113 }
114 }
115 }
116
findTag(const char * tag)117 bool Scanner::findTag(const char* tag) {
118 bool found = findOptionalTag(tag);
119 if (!found) {
120 error() << "Found \"" << mTag << "\" while looking for \"" << tag << "\".\n";
121 }
122 mTagConsumed = true;
123 return found;
124 }
125
findOptionalTag(const char * tag)126 bool Scanner::findOptionalTag(const char* tag) {
127 if (mTagConsumed) {
128 if (!getNextEntry()) {
129 return false;
130 }
131 }
132 mTagConsumed = (mTag == tag);
133 return mTagConsumed;
134 }
135
skipUntilTag(const char * tag)136 void Scanner::skipUntilTag(const char* tag) {
137 while(!findOptionalTag(tag)) {
138 mTagConsumed = true;
139 }
140 }
141
checkNoValue()142 void Scanner::checkNoValue() {
143 if (!mValue.empty()) {
144 error() << "Did not expect \"" << mValue << "\" after \"" << mTag << "\".\n";
145 }
146 }
147
parseDocumentation(string * s,string * documentation)148 void Scanner::parseDocumentation(string* s, string* documentation) {
149 size_t docStart = s->find(", \"");
150 if (docStart == string::npos) {
151 documentation->erase();
152 } else {
153 size_t first = docStart + 3;
154 size_t last = s->find('\"', first);
155 if (last == string::npos) {
156 error() << "Missing closing double quote\n";
157 }
158 *documentation = s->substr(first, last - first);
159 s->erase(docStart);
160 }
161 }
162
parseArgString(bool isReturn)163 ParameterEntry* Scanner::parseArgString(bool isReturn) {
164 string s = mValue;
165 ParameterEntry* p = new ParameterEntry();
166 parseDocumentation(&s, &p->documentation);
167
168 size_t optionStart = s.find(", ");
169 if (optionStart != string::npos) {
170 p->testOption = s.substr(optionStart + 2);
171 s.erase(optionStart);
172 }
173
174 trimSpaces(&s);
175 if (!isReturn) {
176 size_t nameStart = s.rfind(' ');
177 if (nameStart == string::npos) {
178 if (s == "...") {
179 p->name = s;
180 p->type = s;
181 p->lineNumber = mLineNumber;
182 return p;
183 } else {
184 error() << "Missing variable name\n";
185 }
186 } else {
187 p->name = s.substr(nameStart + 1);
188 s.erase(nameStart);
189 if (p->name.find('*') != string::npos) {
190 error() << "The '*' should be attached to the type\n";
191 }
192 }
193 }
194
195 if (s == "void" && !isReturn) {
196 error() << "void is only allowed for ret:\n";
197 }
198 p->type = s;
199 p->lineNumber = mLineNumber;
200 return p;
201 }
202