From 98225193b93906351dfe2ad594a390997e301584 Mon Sep 17 00:00:00 2001 From: Ben Longbons Date: Sat, 14 Dec 2013 19:53:52 -0800 Subject: Make a formatter for lex files --- tools/apply-filter | 3 +- tools/indent-cpp | 2 + tools/indent-ipp | 2 + tools/indent-lpp | 194 +++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/indent-ypp | 2 + 5 files changed, 202 insertions(+), 1 deletion(-) create mode 100755 tools/indent-cpp create mode 100755 tools/indent-ipp create mode 100755 tools/indent-lpp create mode 100755 tools/indent-ypp (limited to 'tools') diff --git a/tools/apply-filter b/tools/apply-filter index 6d36be4..a1cd79d 100755 --- a/tools/apply-filter +++ b/tools/apply-filter @@ -2,9 +2,10 @@ # Apply a filter command to a set of files filter=$1; shift +trap 'rm -f "$arg.tmp"' EXIT for arg do echo apply-filter "$filter" "$arg" - bash -c "$filter" < "$arg" > "$arg.tmp" + bash -c "set -o pipefail; $filter" < "$arg" > "$arg.tmp" maybe-mv "$arg.tmp" "$arg" done diff --git a/tools/indent-cpp b/tools/indent-cpp new file mode 100755 index 0000000..610d623 --- /dev/null +++ b/tools/indent-cpp @@ -0,0 +1,2 @@ +#!/bin/sh +pp-indent | bs-align diff --git a/tools/indent-ipp b/tools/indent-ipp new file mode 100755 index 0000000..d868679 --- /dev/null +++ b/tools/indent-ipp @@ -0,0 +1,2 @@ +#!/bin/sh +exec cat diff --git a/tools/indent-lpp b/tools/indent-lpp new file mode 100755 index 0000000..0d24faf --- /dev/null +++ b/tools/indent-lpp @@ -0,0 +1,194 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 +## indent - Top-level indenter for lex files +## +## Copyright ©2013 Ben Longbons +## +## This file is part of The Mana World (Athena server) +## +## This program is free software: you can redistribute it and/or modify +## it under the terms of the GNU 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 General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program. If not, see . + +''' +A lex file is a series of sections. + +In the initial section: + If it begins with whitespace, it is indented code + It might be a /* comment */ + It might be a #line + It might be a %s, %x, %pointer, %array, %option %[a-z][0-9].* + It might be a %{ codeblock %} + It might be a %top { codeblock } + It might be a name and an expansion + A %% switches to the second section + +In a comment: + */ is the end + +In a codeblock: + if it started with %{, %} ends it + if it started with %top{, } ends it if it matches the nesting + +In section 2's header: + there may be %{ %} sections, possibly nested + there may also be indented code + there may be unindented code if it's inside the %{ %} + +In section 2 proper: + pattern action + pattern action + { + pattern action + } + a %% switches to section 3 + +In section 3: + everything is just C code +''' + +# Settings. +pad = 2 +indent = 4 +brace = True + +# Code. +import subprocess +import sys + +class Table: + ''' Aligned output + ''' + def __init__(self): + self.buf = [] + self.size = 0 + def put1(self, line): + line = line.rstrip() + self.buf.append((line, '')) + def put2(self, left, right): + left = left.rstrip() + right = right.strip() + self.buf.append((left, right)) + if right and len(left) > self.size: + self.size = len(left) + def flush(self): + self.size += pad + if self.size % indent: + self.size += indent - self.size % indent + for l, r in self.buf: + if not r: + sys.stdout.writelines([l, '\n']) + else: + need = self.size - len(l) + sys.stdout.writelines([l, ' ' * need, r, '\n']) + del self.buf[:] + self.size = 0 + +table = Table() +# definitions section (mostly used for options actually) +in_code = False +code = bytearray() +for line in sys.stdin: + if line == '%%\n': + break + if line == '%{\n': + in_code = True + continue + if in_code: + if line == '%}\n': + in_code = False + continue + code += line + continue + if not line.strip() or line != line.lstrip(): + # starts with whitespace or is an empty line ('\n') + code += line + continue + if code.strip(): + if brace: + table.put1('%{') + for line2 in subprocess.Popen(['indent-cpp'], stdin=subprocess.PIPE, stdout=subprocess.PIPE).communicate(code)[0].strip().split('\n'): + # this looks bad actually + table.put1(0 * indent * ' ' + line2) + if brace: + table.put1('%}') + table.put1('') + code = bytearray() + elif code: + table.put1('') + + if line.startswith('%'): + if line.startswith('%top'): + raise NotImplementedError('top block not yet supported') + table.put1(line) + elif line[0].isalpha() or line[0] == '_': + table.put2(*line.split(None, 1)) + else: + table.put1(line) + +assert not in_code +del code +del in_code +table.flush() +sys.stdout.write('\n%%\n') + +# rule section +for line in sys.stdin: + if line == '%%\n': + break + if line.startswith('<') and not line.startswith('<<'): + raise NotImplementedError('start conditions not yet supported') + i = 0 + p = 0 + bs = False + while True: + if bs: + bs = False + i += 1 + continue + if line[i] == '\\': + bs = True + i += 1 + continue + if not p and line[i].isspace(): + break + if line[i] == '"': + i += 1 + while line[i] != '"': + if line[i] == '\\': + i += 1 + i += 1 + elif line[i] == '[': + i += 1 + if line[i] == '^': + i += 1 + while line[i] != ']': + i += 1 + elif line[i] == '(': + p += 1 + elif line[i] == ')': + assert p + p -= 1 + i += 1 + del bs + del p + pattern = line[:i] + rule = line[i:].strip() + del i + + sys.stdout.write(line) + +sys.stdout.write('%%\n') + +# 3rd section is just copied verbatim ... IF it exists +tail = subprocess.Popen(['indent-cpp'], stdin=subprocess.PIPE, stdout=None) +tail.stdin.writelines(sys.stdin) diff --git a/tools/indent-ypp b/tools/indent-ypp new file mode 100755 index 0000000..d868679 --- /dev/null +++ b/tools/indent-ypp @@ -0,0 +1,2 @@ +#!/bin/sh +exec cat -- cgit v1.2.3-70-g09d2