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