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             error() << "Missing variable name\n";
179         } else {
180             p->name = s.substr(nameStart + 1);
181             s.erase(nameStart);
182             if (p->name.find('*') != string::npos) {
183                 error() << "The '*' should be attached to the type\n";
184             }
185         }
186     }
187 
188     if (s == "void" && !isReturn) {
189         error() << "void is only allowed for ret:\n";
190     }
191     p->type = s;
192     p->lineNumber = mLineNumber;
193     return p;
194 }
195