001: package gnu.ecmascript;
002:
003: import java.util.Vector;
004: import gnu.text.SyntaxException;
005: import gnu.mapping.*;
006: import gnu.expr.*;
007: import gnu.lists.Sequence;
008:
009: public class Parser {
010: InPort port;
011: Lexer lexer;
012:
013: Object previous_token;
014: Object token;
015:
016: public static Expression eofExpr = new QuoteExp(Sequence.eofValue);
017:
018: public Parser(InPort port) {
019: this .port = port;
020: this .lexer = new Lexer(port);
021: }
022:
023: public Expression parseConditionalExpression()
024: throws java.io.IOException, SyntaxException {
025: Expression exp1 = parseBinaryExpression(1);
026: Object result = peekToken();
027: if (result != Lexer.condToken)
028: return exp1;
029: skipToken();
030: Expression exp2 = parseAssignmentExpression();
031: if (getToken() != Lexer.colonToken)
032: return syntaxError("expected ':' in conditional expression");
033: Expression exp3 = parseAssignmentExpression();
034: return new IfExp(exp1, exp2, exp3);
035: }
036:
037: public Expression parseAssignmentExpression()
038: throws java.io.IOException, SyntaxException {
039: Expression exp1 = parseConditionalExpression();
040: Object token = peekToken();
041: if (token == Lexer.equalToken) {
042: skipToken();
043: Expression exp2 = parseAssignmentExpression();
044: if (exp1 instanceof ReferenceExp) {
045: SetExp sex = new SetExp(
046: ((ReferenceExp) exp1).getName(), exp2);
047: sex.setDefining(true);
048: return sex;
049: }
050: return syntaxError("unmplemented non-symbol ihs in assignment");
051: } else {
052: if (!(token instanceof Reserved))
053: return exp1;
054: Reserved op = (Reserved) token;
055: if (!op.isAssignmentOp())
056: return exp1;
057: skipToken();
058: Expression exp2 = parseAssignmentExpression();
059: Expression[] args = { exp1, exp2 };
060: return new ApplyExp(new QuoteExp(op.proc), args);
061: }
062: }
063:
064: public Expression parseExpression() throws java.io.IOException,
065: SyntaxException {
066: Expression[] exps = null;
067: int nExps = 0;
068: for (;;) {
069: Expression exp1 = parseAssignmentExpression();
070: boolean last = peekToken() != Lexer.commaToken;
071: if (exps == null) {
072: if (last)
073: return exp1;
074: exps = new Expression[2];
075: } else if (last ? exps.length != nExps + 1
076: : exps.length <= nExps) { // need to resize
077: int newsize = last ? nExps + 1 : 2 * exps.length;
078: Expression[] new_exps = new Expression[newsize];
079: System.arraycopy(exps, 0, new_exps, 0, nExps);
080: exps = new_exps;
081: }
082: exps[nExps++] = exp1;
083: if (last)
084: return new BeginExp(exps);
085: skipToken();
086: }
087: }
088:
089: /** Return the next token from the lexer.
090: * A LineTerminator is considered a token.
091: */
092: public Object peekTokenOrLine() throws java.io.IOException,
093: SyntaxException {
094: if (token == null)
095: token = lexer.getToken();
096: return token;
097: }
098:
099: /** Return the next non-whitespace token from the lexer.
100: * LineTerminators are skipped until a non-eolToken is found.
101: */
102: public Object peekToken() throws java.io.IOException,
103: SyntaxException {
104: if (token == null)
105: token = lexer.getToken();
106: while (token == Lexer.eolToken) {
107: skipToken();
108: token = lexer.getToken();
109: }
110: return token;
111: }
112:
113: public Object getToken() throws java.io.IOException,
114: SyntaxException {
115: Object result = peekToken();
116: skipToken();
117: return result;
118: }
119:
120: public final void skipToken() {
121: if (token != Lexer.eofToken) {
122: previous_token = token;
123: token = null;
124: }
125: }
126:
127: /** Skip an explicit or implicit semicolon. */
128: public void getSemicolon() throws java.io.IOException,
129: SyntaxException {
130: token = peekToken();
131: if (token == Lexer.semicolonToken)
132: skipToken();
133: else if (token == Lexer.rbraceToken || token == Lexer.eofToken
134: || previous_token == Lexer.eolToken)
135: ; // implicit ("inserted") semicolon
136: else
137: syntaxError("missing ';' after expression");
138: }
139:
140: public Expression parsePrimaryExpression()
141: throws java.io.IOException, SyntaxException {
142: Object result = getToken();
143: if (result instanceof QuoteExp)
144: return (QuoteExp) result;
145: if (result instanceof String)
146: return new ReferenceExp((String) result);
147: if (result == Lexer.lparenToken) {
148: Expression expr = parseExpression();
149: Object token = getToken();
150: if (token != Lexer.rparenToken)
151: return syntaxError("expected ')' - got:" + token);
152: return expr;
153: }
154: return syntaxError("unexpected token: " + result);
155: }
156:
157: public Expression makePropertyAccessor(Expression exp,
158: Expression prop) {
159: return null; // FIXME
160: }
161:
162: public final static Expression[] emptyArgs = {};
163:
164: public Expression[] parseArguments() throws java.io.IOException,
165: SyntaxException {
166: skipToken();
167: Object token = peekToken();
168: if (token == Lexer.rparenToken) {
169: skipToken();
170: return emptyArgs;
171: }
172: Vector args = new Vector(10);
173: for (;;) {
174: Expression arg = parseAssignmentExpression();
175: args.addElement(arg);
176: token = getToken();
177: if (token == Lexer.rparenToken)
178: break;
179: if (token != Lexer.commaToken)
180: syntaxError("invalid token '" + token
181: + "' in argument list");
182: }
183: Expression[] exps = new Expression[args.size()];
184: args.copyInto(exps);
185: return exps;
186: }
187:
188: public Expression makeNewExpression(Expression exp,
189: Expression[] args) {
190: if (args == null)
191: args = emptyArgs;
192: exp = null; // FIXME
193: return new ApplyExp(exp, args);
194: }
195:
196: public Expression makeCallExpression(Expression exp,
197: Expression[] args) {
198: return new ApplyExp(exp, args); // FIXME
199: }
200:
201: public String getIdentifier() throws java.io.IOException,
202: SyntaxException {
203: Object token = getToken();
204: if (token instanceof String)
205: return (String) token;
206: syntaxError("missing identifier");
207: return "??";
208: }
209:
210: public Expression parseLeftHandSideExpression()
211: throws java.io.IOException, SyntaxException {
212: int newCount = 0;
213: while (peekToken() == Lexer.newToken) {
214: newCount++;
215: skipToken();
216: }
217: Expression exp = parsePrimaryExpression();
218: for (;;) {
219: Object token = peekToken();
220: if (token == Lexer.dotToken) {
221: skipToken();
222: String name = getIdentifier();
223: exp = makePropertyAccessor(exp, new QuoteExp(name));
224: } else if (token == Lexer.lbracketToken) {
225: skipToken();
226: Expression prop = parseExpression();
227: token = getToken();
228: if (token != Lexer.rbracketToken)
229: return syntaxError("expected ']' - got:" + token);
230: exp = makePropertyAccessor(exp, prop);
231: } else if (token == Lexer.lparenToken) {
232: Expression[] args = parseArguments();
233: System.err.println("after parseArgs:" + peekToken());
234: if (newCount > 0) {
235: exp = makeNewExpression(exp, args);
236: newCount--;
237: } else
238: exp = makeCallExpression(exp, args);
239: } else
240: break;
241: }
242: for (; newCount > 0; newCount--) {
243: exp = makeNewExpression(exp, null);
244: }
245: return exp;
246: }
247:
248: public Expression parsePostfixExpression()
249: throws java.io.IOException, SyntaxException {
250: Expression exp = parseLeftHandSideExpression();
251: Object op = peekTokenOrLine();
252: if (op != Reserved.opPlusPlus && op != Reserved.opMinusMinus)
253: return exp;
254: skipToken();
255: Expression[] args = { exp };
256: return new ApplyExp(new QuoteExp(((Reserved) op).proc), args);
257: }
258:
259: public Expression parseUnaryExpression()
260: throws java.io.IOException, SyntaxException {
261: //Object op = peekTokenOrLine();
262: // FIXME
263: return parsePostfixExpression();
264: }
265:
266: public int errors;
267:
268: public Expression syntaxError(String message) {
269: // same as Translator.syntaxError. FIXME
270: errors++;
271: OutPort err = OutPort.errDefault();
272: String current_filename = port.getName();
273: int current_line = port.getLineNumber() + 1;
274: int current_column = port.getColumnNumber() + 1;
275: if (current_line > 0) {
276: if (current_filename != null)
277: err.print(current_filename);
278: err.print(':');
279: err.print(current_line);
280: if (current_column > 1) {
281: err.print(':');
282: err.print(current_column);
283: }
284: err.print(": ");
285: }
286: err.println(message);
287: return new ErrorExp(message);
288: }
289:
290: public Expression parseBinaryExpression(int prio)
291: throws java.io.IOException, SyntaxException {
292: Expression exp1 = parseUnaryExpression();
293: for (;;) {
294: token = peekToken();
295: if (!(token instanceof Reserved))
296: return exp1;
297: Reserved op = (Reserved) token;
298: if (op.prio < prio)
299: return exp1;
300: getToken();
301: Expression exp2 = parseBinaryExpression(op.prio + 1);
302: Expression[] args = { exp1, exp2 };
303: exp1 = new ApplyExp(new QuoteExp(op.proc), args);
304: }
305: }
306:
307: static Expression emptyStatement = new QuoteExp(Values.empty);
308:
309: public Expression parseIfStatement() throws java.io.IOException,
310: SyntaxException {
311: skipToken();
312: Object token = getToken();
313: if (token != Lexer.lparenToken)
314: return syntaxError("expected '(' - got:" + token);
315: Expression test_part = parseExpression();
316: token = getToken();
317: if (token != Lexer.rparenToken)
318: return syntaxError("expected ')' - got:" + token);
319: Expression then_part = parseStatement();
320: token = peekToken();
321: Expression else_part;
322: if (token == Lexer.elseToken) {
323: skipToken();
324: else_part = parseStatement();
325: } else
326: else_part = null;
327: return new IfExp(test_part, then_part, else_part);
328: }
329:
330: public Expression buildLoop(Expression init, Expression test,
331: Expression incr, Expression body) {
332: if (init != null) {
333: Expression[] pair = new Expression[2];
334: pair[0] = init;
335: pair[1] = buildLoop(null, test, incr, body);
336: return new BeginExp(pair);
337: }
338: throw new Error("not implemented - buildLoop");
339: }
340:
341: public Expression parseWhileStatement() throws java.io.IOException,
342: SyntaxException {
343: skipToken(); // Skip 'while'.
344: Object token = getToken();
345: if (token != Lexer.lparenToken)
346: return syntaxError("expected '(' - got:" + token);
347: Expression test_part = parseExpression();
348: token = getToken();
349: if (token != Lexer.rparenToken)
350: return syntaxError("expected ')' - got:" + token);
351: Expression body = parseStatement();
352: return buildLoop(null, test_part, null, body);
353: }
354:
355: public Expression parseFunctionDefinition()
356: throws java.io.IOException, SyntaxException {
357: skipToken();
358: String name = getIdentifier();
359: Object token = getToken();
360: if (token != Lexer.lparenToken)
361: return syntaxError("expected '(' - got:" + token);
362: Vector args = new Vector(10);
363: if (peekToken() == Lexer.rparenToken) {
364: skipToken();
365: } else {
366: for (;;) {
367: String arg = getIdentifier();
368: args.addElement(arg);
369: token = getToken();
370: if (token == Lexer.rparenToken)
371: break;
372: if (token != Lexer.commaToken)
373: syntaxError("invalid token '" + token
374: + "' in argument list");
375: }
376: }
377: Expression body = parseBlock();
378: LambdaExp lexp = new LambdaExp(body);
379: lexp.setName(name);
380: SetExp sexp = new SetExp(name, lexp);
381: sexp.setDefining(true);
382: return sexp;
383: }
384:
385: public Expression parseBlock() throws java.io.IOException,
386: SyntaxException {
387: Expression[] exps = null;
388: if (getToken() != Lexer.lbraceToken)
389: return syntaxError("extened '{'");
390: int nExps = 0;
391: for (;;) {
392: token = peekToken();
393: boolean last;
394: if (token == Lexer.rbraceToken) {
395: skipToken();
396: if (exps == null)
397: return emptyStatement;
398: last = true;
399: } else
400: last = false;
401: if (exps == null)
402: exps = new Expression[2];
403: else if (last ? exps.length != nExps : exps.length <= nExps) { // need to resize
404: int newsize = last ? nExps : 2 * exps.length;
405: Expression[] new_exps = new Expression[newsize];
406: System.arraycopy(exps, 0, new_exps, 0, nExps);
407: exps = new_exps;
408: }
409: if (last)
410: return new BeginExp(exps);
411: exps[nExps++] = parseStatement();
412: }
413: }
414:
415: public Expression parseStatement() throws java.io.IOException,
416: SyntaxException {
417: Object token = peekToken();
418: if (token instanceof Reserved) {
419: switch (((Reserved) token).prio) {
420: case Reserved.IF_TOKEN:
421: return parseIfStatement();
422: case Reserved.WHILE_TOKEN:
423: return parseWhileStatement();
424: case Reserved.FUNCTION_TOKEN:
425: return parseFunctionDefinition();
426: }
427: }
428: if (token == Lexer.eofToken)
429: return eofExpr;
430: if (token == Lexer.semicolonToken) {
431: skipToken();
432: return emptyStatement;
433: }
434: if (token == Lexer.lbraceToken)
435: return parseBlock();
436:
437: Expression exp = parseExpression();
438: getSemicolon();
439: return exp;
440: }
441:
442: public static void main(String[] args) {
443: Language language = new kawa.standard.Scheme(); // FIXME
444:
445: InPort inp = InPort.inDefault();
446: if (inp instanceof TtyInPort) {
447: Object prompter = new Prompter();
448: ((TtyInPort) inp).setPrompter((Procedure) prompter);
449: }
450:
451: Parser parser = new Parser(inp);
452: OutPort out = OutPort.outDefault();
453: for (;;) {
454: try {
455: /*
456: Object token = parser.peekToken();
457: if (token == Lexer.eofToken)
458: break;
459: if (token == Lexer.eolToken)
460: {
461: parser.getToken();
462: continue;
463: }
464: Expression expr = parser.parseExpression();
465: */
466: Expression expr = parser.parseStatement();
467: if (expr == eofExpr)
468: break;
469: out.print("[Expression: ");
470: expr.print(out);
471: out.println("]");
472: Object result = expr.eval(Environment.user());
473: out.print("result: ");
474: out.print(result);
475: out.println();
476: } catch (Throwable ex) {
477: System.err.println("caught exception:" + ex);
478: ex.printStackTrace(System.err);
479: return;
480: }
481: }
482: }
483: }
|