xref: /haiku/src/tests/add-ons/print/ppd/parser/Parser.cpp (revision 4420c1ceffd7f2246e4303d59cf02ed122980e9d)
1*4420c1ceSMichael Pfeiffer /*
2*4420c1ceSMichael Pfeiffer  * Copyright 2008, Haiku.
3*4420c1ceSMichael Pfeiffer  * Distributed under the terms of the MIT license.
4*4420c1ceSMichael Pfeiffer  *
5*4420c1ceSMichael Pfeiffer  * Authors:
6*4420c1ceSMichael Pfeiffer  *		Michael Pfeiffer <laplace@users.sourceforge.net>
7*4420c1ceSMichael Pfeiffer  */
8*4420c1ceSMichael Pfeiffer 
9*4420c1ceSMichael Pfeiffer #include "AutoDelete.h"
10*4420c1ceSMichael Pfeiffer #include "CharacterClasses.h"
11*4420c1ceSMichael Pfeiffer #include "Parser.h"
12*4420c1ceSMichael Pfeiffer 
Parser(const char * file)13*4420c1ceSMichael Pfeiffer Parser::Parser(const char* file)
14*4420c1ceSMichael Pfeiffer 	: fScanner(file)
15*4420c1ceSMichael Pfeiffer {
16*4420c1ceSMichael Pfeiffer 	if (InitCheck() == B_OK) {
17*4420c1ceSMichael Pfeiffer 		NextChar();
18*4420c1ceSMichael Pfeiffer 	}
19*4420c1ceSMichael Pfeiffer }
20*4420c1ceSMichael Pfeiffer 
InitCheck()21*4420c1ceSMichael Pfeiffer status_t Parser::InitCheck()
22*4420c1ceSMichael Pfeiffer {
23*4420c1ceSMichael Pfeiffer 	return fScanner.InitCheck();
24*4420c1ceSMichael Pfeiffer }
25*4420c1ceSMichael Pfeiffer 
SkipWhitespaces()26*4420c1ceSMichael Pfeiffer void Parser::SkipWhitespaces()
27*4420c1ceSMichael Pfeiffer {
28*4420c1ceSMichael Pfeiffer 	while (IsWhitespace(GetCurrentChar())) {
29*4420c1ceSMichael Pfeiffer 		NextChar();
30*4420c1ceSMichael Pfeiffer 	}
31*4420c1ceSMichael Pfeiffer }
32*4420c1ceSMichael Pfeiffer 
SkipComment()33*4420c1ceSMichael Pfeiffer void Parser::SkipComment()
34*4420c1ceSMichael Pfeiffer {
35*4420c1ceSMichael Pfeiffer 	while (GetCurrentChar() != kEof && GetCurrentChar() != kCr) {
36*4420c1ceSMichael Pfeiffer 		NextChar();
37*4420c1ceSMichael Pfeiffer 	}
38*4420c1ceSMichael Pfeiffer 	NextChar();
39*4420c1ceSMichael Pfeiffer }
40*4420c1ceSMichael Pfeiffer 
SkipWhitespaceSeparator()41*4420c1ceSMichael Pfeiffer void Parser::SkipWhitespaceSeparator()
42*4420c1ceSMichael Pfeiffer {
43*4420c1ceSMichael Pfeiffer 	while (IsWhitespaceSeparator(GetCurrentChar())) {
44*4420c1ceSMichael Pfeiffer 		NextChar();
45*4420c1ceSMichael Pfeiffer 	}
46*4420c1ceSMichael Pfeiffer }
47*4420c1ceSMichael Pfeiffer 
ParseKeyword(Statement * statement)48*4420c1ceSMichael Pfeiffer bool Parser::ParseKeyword(Statement* statement)
49*4420c1ceSMichael Pfeiffer {
50*4420c1ceSMichael Pfeiffer 	// ["?"]
51*4420c1ceSMichael Pfeiffer 	if (GetCurrentChar() == '?') {
52*4420c1ceSMichael Pfeiffer 		NextChar();
53*4420c1ceSMichael Pfeiffer 		statement->SetType(Statement::kQuery);
54*4420c1ceSMichael Pfeiffer 	}
55*4420c1ceSMichael Pfeiffer 	// Keyword
56*4420c1ceSMichael Pfeiffer 	BString* keyword = fScanner.ScanIdent();
57*4420c1ceSMichael Pfeiffer 	if (keyword == NULL) {
58*4420c1ceSMichael Pfeiffer 		Error("Identifier expected");
59*4420c1ceSMichael Pfeiffer 		return false;
60*4420c1ceSMichael Pfeiffer 	}
61*4420c1ceSMichael Pfeiffer 	statement->SetKeyword(keyword);
62*4420c1ceSMichael Pfeiffer 	return true;
63*4420c1ceSMichael Pfeiffer }
64*4420c1ceSMichael Pfeiffer 
ParseTranslation(Value * value,int separator)65*4420c1ceSMichael Pfeiffer bool Parser::ParseTranslation(Value* value, int separator)
66*4420c1ceSMichael Pfeiffer {
67*4420c1ceSMichael Pfeiffer 	BString* translation = fScanner.ScanTranslationValue(separator);
68*4420c1ceSMichael Pfeiffer 	if (translation == NULL) {
69*4420c1ceSMichael Pfeiffer 		Error("Out of memory scanning translationn!");
70*4420c1ceSMichael Pfeiffer 		return false;
71*4420c1ceSMichael Pfeiffer 	}
72*4420c1ceSMichael Pfeiffer 	value->SetTranslation(translation);
73*4420c1ceSMichael Pfeiffer 	return true;
74*4420c1ceSMichael Pfeiffer }
75*4420c1ceSMichael Pfeiffer 
ParseOption(Statement * statement)76*4420c1ceSMichael Pfeiffer bool Parser::ParseOption(Statement* statement)
77*4420c1ceSMichael Pfeiffer {
78*4420c1ceSMichael Pfeiffer 	// ["^"]
79*4420c1ceSMichael Pfeiffer 	bool isSymbolValue = GetCurrentChar() == '^';
80*4420c1ceSMichael Pfeiffer 	if (isSymbolValue) {
81*4420c1ceSMichael Pfeiffer 		NextChar();
82*4420c1ceSMichael Pfeiffer 	}
83*4420c1ceSMichael Pfeiffer 
84*4420c1ceSMichael Pfeiffer 	// [ ... Option ...]
85*4420c1ceSMichael Pfeiffer 	if (IsOptionChar(GetCurrentChar())) {
86*4420c1ceSMichael Pfeiffer 
87*4420c1ceSMichael Pfeiffer 		BString* option = fScanner.ScanOption();
88*4420c1ceSMichael Pfeiffer 		if (option == NULL) {
89*4420c1ceSMichael Pfeiffer 			Error("Out of memory scanning option!");
90*4420c1ceSMichael Pfeiffer 			return false;
91*4420c1ceSMichael Pfeiffer 		}
92*4420c1ceSMichael Pfeiffer 		Value::Type type;
93*4420c1ceSMichael Pfeiffer 		if (isSymbolValue) {
94*4420c1ceSMichael Pfeiffer 			type = Value::kSymbolValue;
95*4420c1ceSMichael Pfeiffer 		} else {
96*4420c1ceSMichael Pfeiffer 			type = Value::kStringValue;
97*4420c1ceSMichael Pfeiffer 		}
98*4420c1ceSMichael Pfeiffer 		Value* value = new Value(option, type);
99*4420c1ceSMichael Pfeiffer 		statement->SetOption(value);
100*4420c1ceSMichael Pfeiffer 
101*4420c1ceSMichael Pfeiffer 		SkipWhitespaceSeparator();
102*4420c1ceSMichael Pfeiffer 		// ["/" Translation ]
103*4420c1ceSMichael Pfeiffer 		if (GetCurrentChar() == '/') {
104*4420c1ceSMichael Pfeiffer 			NextChar();
105*4420c1ceSMichael Pfeiffer 			return ParseTranslation(value, ':');
106*4420c1ceSMichael Pfeiffer 		}
107*4420c1ceSMichael Pfeiffer 	} else {
108*4420c1ceSMichael Pfeiffer 		if (isSymbolValue) {
109*4420c1ceSMichael Pfeiffer 			Error("Expected symbol value!");
110*4420c1ceSMichael Pfeiffer 			return false;
111*4420c1ceSMichael Pfeiffer 		}
112*4420c1ceSMichael Pfeiffer 	}
113*4420c1ceSMichael Pfeiffer 	return true;
114*4420c1ceSMichael Pfeiffer }
115*4420c1ceSMichael Pfeiffer 
ParseValue(Statement * statement)116*4420c1ceSMichael Pfeiffer bool Parser::ParseValue(Statement* statement)
117*4420c1ceSMichael Pfeiffer {
118*4420c1ceSMichael Pfeiffer 	if (GetCurrentChar() == '"') {
119*4420c1ceSMichael Pfeiffer 		NextChar();
120*4420c1ceSMichael Pfeiffer 
121*4420c1ceSMichael Pfeiffer 		// "..."
122*4420c1ceSMichael Pfeiffer 		AutoDelete<Value> value(new Value());
123*4420c1ceSMichael Pfeiffer 
124*4420c1ceSMichael Pfeiffer 		BString* string;
125*4420c1ceSMichael Pfeiffer 		if (statement->GetOption() != NULL) {
126*4420c1ceSMichael Pfeiffer 			string = fScanner.ScanInvocationValue();
127*4420c1ceSMichael Pfeiffer 			value.Get()->SetType(Value::kInvocationValue);
128*4420c1ceSMichael Pfeiffer 		} else {
129*4420c1ceSMichael Pfeiffer 			string = fScanner.ScanQuotedValue();
130*4420c1ceSMichael Pfeiffer 			value.Get()->SetType(Value::kQuotedValue);
131*4420c1ceSMichael Pfeiffer 		}
132*4420c1ceSMichael Pfeiffer 
133*4420c1ceSMichael Pfeiffer 		if (string == NULL) {
134*4420c1ceSMichael Pfeiffer 			Error("Expected value");
135*4420c1ceSMichael Pfeiffer 			return false;
136*4420c1ceSMichael Pfeiffer 		}
137*4420c1ceSMichael Pfeiffer 
138*4420c1ceSMichael Pfeiffer 		// " is expected
139*4420c1ceSMichael Pfeiffer 		if (GetCurrentChar() != '"') {
140*4420c1ceSMichael Pfeiffer 			Error("Expected \" at end of value");
141*4420c1ceSMichael Pfeiffer 			return false;
142*4420c1ceSMichael Pfeiffer 		}
143*4420c1ceSMichael Pfeiffer 		NextChar();
144*4420c1ceSMichael Pfeiffer 
145*4420c1ceSMichael Pfeiffer 		value.Get()->SetValue(string);
146*4420c1ceSMichael Pfeiffer 		statement->SetValue(value.Release());
147*4420c1ceSMichael Pfeiffer 	} else if (GetCurrentChar() == '^') {
148*4420c1ceSMichael Pfeiffer 		// ^ SymbolValue
149*4420c1ceSMichael Pfeiffer 		BString* symbol = fScanner.ScanOption();
150*4420c1ceSMichael Pfeiffer 		if (symbol == NULL) {
151*4420c1ceSMichael Pfeiffer 			Error("Symbol expected!");
152*4420c1ceSMichael Pfeiffer 			return false;
153*4420c1ceSMichael Pfeiffer 		}
154*4420c1ceSMichael Pfeiffer 		Value* value = new Value(symbol, Value::kSymbolValue);
155*4420c1ceSMichael Pfeiffer 		statement->SetValue(value);
156*4420c1ceSMichael Pfeiffer 	} else {
157*4420c1ceSMichael Pfeiffer 		// StringValue
158*4420c1ceSMichael Pfeiffer 		BString* stringValue = fScanner.ScanStringValue();
159*4420c1ceSMichael Pfeiffer 		if (stringValue == NULL) {
160*4420c1ceSMichael Pfeiffer 			Error("String value expected!");
161*4420c1ceSMichael Pfeiffer 			return false;
162*4420c1ceSMichael Pfeiffer 		}
163*4420c1ceSMichael Pfeiffer 
164*4420c1ceSMichael Pfeiffer 		Value* value = new Value(stringValue, Value::kStringValue);
165*4420c1ceSMichael Pfeiffer 		statement->SetValue(value);
166*4420c1ceSMichael Pfeiffer 	}
167*4420c1ceSMichael Pfeiffer 	if (GetCurrentChar() == '/') {
168*4420c1ceSMichael Pfeiffer 		NextChar();
169*4420c1ceSMichael Pfeiffer 		return ParseTranslation(statement->GetValue(), kCr);
170*4420c1ceSMichael Pfeiffer 	}
171*4420c1ceSMichael Pfeiffer 	return true;
172*4420c1ceSMichael Pfeiffer }
173*4420c1ceSMichael Pfeiffer 
174*4420c1ceSMichael Pfeiffer 
UpdateStatementType(Statement * statement)175*4420c1ceSMichael Pfeiffer void Parser::UpdateStatementType(Statement* statement)
176*4420c1ceSMichael Pfeiffer {
177*4420c1ceSMichael Pfeiffer 	if (statement->GetType() != Statement::kUnknown) return;
178*4420c1ceSMichael Pfeiffer 
179*4420c1ceSMichael Pfeiffer 	BString* keyword = statement->GetKeyword();
180*4420c1ceSMichael Pfeiffer 	Statement::Type type;
181*4420c1ceSMichael Pfeiffer 	if (keyword->FindFirst("Default") == 0) {
182*4420c1ceSMichael Pfeiffer 		type = Statement::kDefault;
183*4420c1ceSMichael Pfeiffer 		keyword->RemoveFirst("Default");
184*4420c1ceSMichael Pfeiffer 	} else if (keyword->FindFirst("Param") == 0) {
185*4420c1ceSMichael Pfeiffer 		type = Statement::kParam;
186*4420c1ceSMichael Pfeiffer 		keyword->RemoveFirst("Param");
187*4420c1ceSMichael Pfeiffer 	} else {
188*4420c1ceSMichael Pfeiffer 		type = Statement::kValue;
189*4420c1ceSMichael Pfeiffer 	}
190*4420c1ceSMichael Pfeiffer 	statement->SetType(type);
191*4420c1ceSMichael Pfeiffer }
192*4420c1ceSMichael Pfeiffer 
193*4420c1ceSMichael Pfeiffer // ["?"]Keyword [["^"]Option["/"Translation]]
194*4420c1ceSMichael Pfeiffer // [":"
195*4420c1ceSMichael Pfeiffer //   ["^"]Value ["/" Translation].
196*4420c1ceSMichael Pfeiffer // ]
ParseStatement()197*4420c1ceSMichael Pfeiffer Statement* Parser::ParseStatement()
198*4420c1ceSMichael Pfeiffer {
199*4420c1ceSMichael Pfeiffer 	AutoDelete<Statement> statement(new Statement());
200*4420c1ceSMichael Pfeiffer 
201*4420c1ceSMichael Pfeiffer 	if (!ParseKeyword(statement.Get())) {
202*4420c1ceSMichael Pfeiffer 		return NULL;
203*4420c1ceSMichael Pfeiffer 	}
204*4420c1ceSMichael Pfeiffer 	SkipWhitespaceSeparator();
205*4420c1ceSMichael Pfeiffer 
206*4420c1ceSMichael Pfeiffer 	if (!ParseOption(statement.Get())) {
207*4420c1ceSMichael Pfeiffer 		return NULL;
208*4420c1ceSMichael Pfeiffer 	}
209*4420c1ceSMichael Pfeiffer 
210*4420c1ceSMichael Pfeiffer 	SkipWhitespaceSeparator();
211*4420c1ceSMichael Pfeiffer 	// [":" ... ]
212*4420c1ceSMichael Pfeiffer 	if (GetCurrentChar() == ':') {
213*4420c1ceSMichael Pfeiffer 		NextChar();
214*4420c1ceSMichael Pfeiffer 		SkipWhitespaceSeparator();
215*4420c1ceSMichael Pfeiffer 		if (!ParseValue(statement.Get())) {
216*4420c1ceSMichael Pfeiffer 			return NULL;
217*4420c1ceSMichael Pfeiffer 		}
218*4420c1ceSMichael Pfeiffer 	}
219*4420c1ceSMichael Pfeiffer 	SkipWhitespaceSeparator();
220*4420c1ceSMichael Pfeiffer 	if (GetCurrentChar() == kEof || GetCurrentChar() == kLf || GetCurrentChar() == kCr) {
221*4420c1ceSMichael Pfeiffer 		UpdateStatementType(statement.Get());
222*4420c1ceSMichael Pfeiffer 		Statement* result = statement.Release();
223*4420c1ceSMichael Pfeiffer 		return result;
224*4420c1ceSMichael Pfeiffer 	} else {
225*4420c1ceSMichael Pfeiffer 		Error("Newline expected at end of statement");
226*4420c1ceSMichael Pfeiffer 		return NULL;
227*4420c1ceSMichael Pfeiffer 	}
228*4420c1ceSMichael Pfeiffer }
229*4420c1ceSMichael Pfeiffer 
Parse()230*4420c1ceSMichael Pfeiffer Statement* Parser::Parse()
231*4420c1ceSMichael Pfeiffer {
232*4420c1ceSMichael Pfeiffer 	while (true) {
233*4420c1ceSMichael Pfeiffer 		int ch = GetCurrentChar();
234*4420c1ceSMichael Pfeiffer 		if (ch == -1) {
235*4420c1ceSMichael Pfeiffer 			return NULL;
236*4420c1ceSMichael Pfeiffer 		}
237*4420c1ceSMichael Pfeiffer 		if (IsWhitespace(ch)) {
238*4420c1ceSMichael Pfeiffer 			SkipWhitespaces();
239*4420c1ceSMichael Pfeiffer 		} else if (ch == '*') {
240*4420c1ceSMichael Pfeiffer 			// begin of comment or statement
241*4420c1ceSMichael Pfeiffer 			NextChar();
242*4420c1ceSMichael Pfeiffer 			ch = GetCurrentChar();
243*4420c1ceSMichael Pfeiffer 			if (ch == '%') {
244*4420c1ceSMichael Pfeiffer 				SkipComment();
245*4420c1ceSMichael Pfeiffer 			} else {
246*4420c1ceSMichael Pfeiffer 				return ParseStatement();
247*4420c1ceSMichael Pfeiffer 			}
248*4420c1ceSMichael Pfeiffer 		} else {
249*4420c1ceSMichael Pfeiffer 			Error("Expected *");
250*4420c1ceSMichael Pfeiffer 			return NULL;
251*4420c1ceSMichael Pfeiffer 		}
252*4420c1ceSMichael Pfeiffer 	}
253*4420c1ceSMichael Pfeiffer }
254*4420c1ceSMichael Pfeiffer 
255