summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--bin/man1/order.14
-rw-r--r--bin/order.y121
2 files changed, 63 insertions, 62 deletions
diff --git a/bin/man1/order.1 b/bin/man1/order.1
index 8e0f9661..89fcbda5 100644
--- a/bin/man1/order.1
+++ b/bin/man1/order.1
@@ -19,8 +19,8 @@ according to the precedence rules in
 If no
 .Ar expr
 are given,
-each line of standard input
-is parsed and printed.
+an expression is read
+from standard input.
 .
 .Sh EXAMPLES
 .Bd -literal
diff --git a/bin/order.y b/bin/order.y
index b4b40a34..b3cbf2df 100644
--- a/bin/order.y
+++ b/bin/order.y
@@ -24,12 +24,6 @@
 #include <string.h>
 #include <sysexits.h>
 
-int vasprintf(char **ret, const char *format, va_list ap);
-
-static void yyerror(const char *str) {
-	errx(EX_DATAERR, "%s", str);
-}
-
 #define YYSTYPE char *
 
 static char *fmt(const char *format, ...) {
@@ -43,9 +37,12 @@ static char *fmt(const char *format, ...) {
 }
 
 static int yylex(void);
+static void yyerror(const char *str);
 
 %}
 
+%token Ident
+
 %left ','
 %right '=' MulAss DivAss ModAss AddAss SubAss ShlAss ShrAss AndAss XorAss OrAss
 %right '?' ':'
@@ -62,8 +59,6 @@ static int yylex(void);
 %right '!' '~' Inc Dec Sizeof
 %left '(' ')' '[' ']' Arr '.'
 
-%token Var
-
 %%
 
 start:
@@ -71,11 +66,11 @@ start:
 	;
 
 expr:
-	Var
+	Ident
 	| '(' expr ')' { $$ = $2; }
 	| expr '[' expr ']' { $$ = fmt("(%s[%s])", $1, $3); }
-	| expr Arr Var { $$ = fmt("(%s->%s)", $1, $3); }
-	| expr '.' Var { $$ = fmt("(%s.%s)", $1, $3); }
+	| expr Arr Ident { $$ = fmt("(%s->%s)", $1, $3); }
+	| expr '.' Ident { $$ = fmt("(%s.%s)", $1, $3); }
 	| '!' expr { $$ = fmt("(!%s)", $2); }
 	| '~' expr { $$ = fmt("(~%s)", $2); }
 	| Inc expr { $$ = fmt("(++%s)", $2); }
@@ -128,67 +123,73 @@ ass:
 
 #define T(a, b) ((int)(a) << 8 | (int)(b))
 
-static const char *input;
+static FILE *in;
 
 static int yylex(void) {
-	while (isspace(input[0])) input++;
-	if (!input[0]) return EOF;
-
-	int len;
-	for (len = 0; isalnum(input[len]) || input[len] == '_'; ++len);
-	if (len) {
-		if (!strncmp(input, "sizeof", len)) {
-			input += len;
-			return Sizeof;
+	char ch;
+	while (isspace(ch = getc(in)));
+
+	if (isalnum(ch)) {
+		char ident[64] = { ch, '\0' };
+		for (size_t i = 1; i < sizeof(ident) - 1; ++i) {
+			ch = getc(in);
+			if (!isalnum(ch) && ch != '_') break;
+			ident[i] = ch;
 		}
-		yylval = fmt("%.*s", len, input);
-		input += len;
-		return Var;
-	}
-
-	int tok;
-	switch (T(input[0], input[1])) {
-		break; case T('-', '>'): tok = Arr;
-		break; case T('+', '+'): tok = Inc;
-		break; case T('-', '-'): tok = Dec;
-		break; case T('<', '<'): tok = Shl;
-		break; case T('>', '>'): tok = Shr;
-		break; case T('<', '='): tok = Le;
-		break; case T('>', '='): tok = Ge;
-		break; case T('=', '='): tok = Eq;
-		break; case T('!', '='): tok = Ne;
-		break; case T('&', '&'): tok = And;
-		break; case T('|', '|'): tok = Or;
-		break; case T('*', '='): tok = MulAss;
-		break; case T('/', '='): tok = DivAss;
-		break; case T('%', '='): tok = ModAss;
-		break; case T('+', '='): tok = AddAss;
-		break; case T('-', '='): tok = SubAss;
-		break; case T('&', '='): tok = AndAss;
-		break; case T('^', '='): tok = XorAss;
-		break; case T('|', '='): tok = OrAss;
-		break; default: return *input++;
+		ungetc(ch, in);
+		if (!strcmp(ident, "sizeof")) return Sizeof;
+		yylval = fmt("%s", ident);
+		return Ident;
 	}
-	input += 2;
 
-	switch (T(tok, input[0])) {
-		case T(Shl, '='): input++; return ShlAss;
-		case T(Shr, '='): input++; return ShrAss;
+	char ne = getc(in);
+	switch (T(ch, ne)) {
+		case T('-', '>'): return Arr;
+		case T('+', '+'): return Inc;
+		case T('-', '-'): return Dec;
+		case T('<', '='): return Le;
+		case T('>', '='): return Ge;
+		case T('=', '='): return Eq;
+		case T('!', '='): return Ne;
+		case T('&', '&'): return And;
+		case T('|', '|'): return Or;
+		case T('*', '='): return MulAss;
+		case T('/', '='): return DivAss;
+		case T('%', '='): return ModAss;
+		case T('+', '='): return AddAss;
+		case T('-', '='): return SubAss;
+		case T('&', '='): return AndAss;
+		case T('^', '='): return XorAss;
+		case T('|', '='): return OrAss;
+		case T('<', '<'): {
+			if ('=' == (ne = getc(in))) return ShlAss;
+			ungetc(ne, in);
+			return Shl;
+		}
+		case T('>', '>'): {
+			if ('=' == (ne = getc(in))) return ShrAss;
+			ungetc(ne, in);
+			return Shr;
+		}
+		default: {
+			ungetc(ne, in);
+			return ch;
+		}
 	}
+}
 
-	return tok;
+static void yyerror(const char *str) {
+	errx(EX_DATAERR, "%s", str);
 }
 
 int main(int argc, char *argv[]) {
 	for (int i = 1; i < argc; ++i) {
-		input = argv[i];
+		in = fmemopen(argv[i], strlen(argv[i]), "r");
+		if (!in) err(EX_OSERR, "fmemopen");
 		yyparse();
+		fclose(in);
 	}
 	if (argc > 1) return EX_OK;
-	size_t cap = 0;
-	char *buf = NULL;
-	while (0 < getline(&buf, &cap, stdin)) {
-		input = buf;
-		yyparse();
-	}
+	in = stdin;
+	yyparse();
 }