From 98225193b93906351dfe2ad594a390997e301584 Mon Sep 17 00:00:00 2001
From: Ben Longbons <b.r.longbons@gmail.com>
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 <b.r.longbons@gmail.com>
+##
+##    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 <http://www.gnu.org/licenses/>.
+
+'''
+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
+    <sc>pattern     action
+    <sc>{
+        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