From cdf925f29e53eba20bc47af161fb6aec3b7c465d Mon Sep 17 00:00:00 2001 From: Curtis McEnroe Date: Wed, 15 May 2019 19:33:38 -0400 Subject: Add order --- bin/.gitignore | 1 + bin/Makefile | 4 ++ bin/README | 1 + bin/bin.7 | 3 ++ bin/man1/order.1 | 34 +++++++++++++ bin/order.y | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 194 insertions(+) create mode 100644 bin/man1/order.1 create mode 100644 bin/order.y diff --git a/bin/.gitignore b/bin/.gitignore index ce3a976f..f1d66fc3 100644 --- a/bin/.gitignore +++ b/bin/.gitignore @@ -15,6 +15,7 @@ hi hnel modem open +order pbcopy pbd pbpaste diff --git a/bin/Makefile b/bin/Makefile index 48cfb184..50d60133 100644 --- a/bin/Makefile +++ b/bin/Makefile @@ -23,6 +23,7 @@ BINS += glitch BINS += hi BINS += hnel BINS += modem +BINS += order BINS += pbd BINS += pngo BINS += psf2png @@ -127,6 +128,9 @@ $(HTMLS): ttpre hi html.sh .c.html: sh html.sh $< man1/$(<:.c=.1) > $@ +.y.html: + sh html.sh $< man1/$(<:.y=.1) > $@ + .sh.html: sh html.sh $< man1/$(<:.sh=.1) > $@ diff --git a/bin/README b/bin/README index d3d05ade..6bfdb10e 100644 --- a/bin/README +++ b/bin/README @@ -19,6 +19,7 @@ DESCRIPTION hi(1) syntax highlighter hnel(1) PTY input remapper modem(1) fixed baud rate wrapper + order(1) operator precedence pbd(1) macOS pasteboard daemon pngo(1) PNG optimizer psf2png(1) PSF2 to PNG renderer diff --git a/bin/bin.7 b/bin/bin.7 index 0c7c3184..ba1e7e7c 100644 --- a/bin/bin.7 +++ b/bin/bin.7 @@ -52,6 +52,9 @@ PTY input remapper .It Xr modem 1 fixed baud rate wrapper . +.It Xr order 1 +operator precedence +. .It Xr pbd 1 macOS pasteboard daemon . diff --git a/bin/man1/order.1 b/bin/man1/order.1 new file mode 100644 index 00000000..696a24d1 --- /dev/null +++ b/bin/man1/order.1 @@ -0,0 +1,34 @@ +.Dd May 15, 2019 +.Dt ORDER 1 +.Os +. +.Sh NAME +.Nm order +.Nd operator precedence +. +.Sh SYNOPSIS +.Nm +.Ar expr ... +. +.Sh DESCRIPTION +.Nm +parses C expressions +and prints them with parentheses +according to the precedence rules in +.Xr operator 7 . +. +.Sh EXAMPLES +.Bd -literal +$ order 'a & b << 1' +(a & (b << 1)) +.Ed +. +.Sh SEE ALSO +.Xr operator 7 +. +.Sh CAVEATS +.Nm +does not support the +.Sy (type) , +.Sy sizeof +or assignment operators. diff --git a/bin/order.y b/bin/order.y new file mode 100644 index 00000000..84fcc2cc --- /dev/null +++ b/bin/order.y @@ -0,0 +1,151 @@ +/* Copyright (C) 2019 C. McEnroe + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +%{ + +#include +#include +#include +#include +#include +#include + +static void yyerror(const char *str) { + errx(EX_DATAERR, "%s", str); +} + +#define YYSTYPE char * + +static char *fmt(const char *format, ...) { + char *str = NULL; + va_list ap; + va_start(ap, format); + vasprintf(&str, format, ap); + va_end(ap); + if (!str) err(EX_OSERR, "vasprintf"); + return str; +} + +static int yylex(void); + +%} + +%token Var Arr Inc Dec Shl Shr Le Ge Eq Ne And Or + +%left ',' +%right '?' ':' +%left Or +%left And +%left '|' +%left '^' +%left '&' +%left Eq Ne +%left '<' Le '>' Ge +%left Shl Shr +%left '+' '-' +%left '*' '/' '%' +%right '!' '~' Inc Dec +%left '[' ']' Arr '.' + +%% + +start: + expr { printf("%s\n", $1); } + ; + +expr: + Var + | '(' 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 { $$ = fmt("(!%s)", $2); } + | '~' expr { $$ = fmt("(~%s)", $2); } + | Inc expr { $$ = fmt("(++%s)", $2); } + | Dec expr { $$ = fmt("(--%s)", $2); } + | expr Inc { $$ = fmt("(%s++)", $1); } + | expr Dec { $$ = fmt("(%s--)", $1); } + | '-' expr { $$ = fmt("(-%s)", $2); } + | '*' expr { $$ = fmt("(*%s)", $2); } + | '&' expr { $$ = fmt("(&%s)", $2); } + | expr '*' expr { $$ = fmt("(%s * %s)", $1, $3); } + | expr '/' expr { $$ = fmt("(%s / %s)", $1, $3); } + | expr '%' expr { $$ = fmt("(%s %% %s)", $1, $3); } + | expr '+' expr { $$ = fmt("(%s + %s)", $1, $3); } + | expr '-' expr { $$ = fmt("(%s - %s)", $1, $3); } + | expr Shl expr { $$ = fmt("(%s << %s)", $1, $3); } + | expr Shr expr { $$ = fmt("(%s >> %s)", $1, $3); } + | expr '<' expr { $$ = fmt("(%s < %s)", $1, $3); } + | expr Le expr { $$ = fmt("(%s <= %s)", $1, $3); } + | expr '>' expr { $$ = fmt("(%s > %s)", $1, $3); } + | expr Ge expr { $$ = fmt("(%s >= %s)", $1, $3); } + | expr Eq expr { $$ = fmt("(%s == %s)", $1, $3); } + | expr Ne expr { $$ = fmt("(%s != %s)", $1, $3); } + | expr '&' expr { $$ = fmt("(%s & %s)", $1, $3); } + | expr '^' expr { $$ = fmt("(%s ^ %s)", $1, $3); } + | expr '|' expr { $$ = fmt("(%s | %s)", $1, $3); } + | expr And expr { $$ = fmt("(%s && %s)", $1, $3); } + | expr Or expr { $$ = fmt("(%s || %s)", $1, $3); } + | expr '?' expr ':' expr { $$ = fmt("(%s ? %s : %s)", $1, $3, $5); } + | expr ',' expr { $$ = fmt("(%s, %s)", $1, $3); } + ; + +%% + +#define T(a, b) ((int)(a) << 8 | (int)(b)) + +static const char *input; + +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) { + yylval = fmt("%.*s", len, input); + input += len; + return Var; + } + + int tok = 0; + 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; + } + if (tok) { + input += 2; + return tok; + } + + return *input++; +} + +int main(int argc, char *argv[]) { + for (int i = 1; i < argc; ++i) { + input = argv[i]; + yyparse(); + } +} -- cgit 1.4.1