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