parallel members to arrays
[pspp] / src / language / expressions / generate.py
index e530cd8208a11542c71e62f364e98890258aa974..ffe780a3c35ab9cbfdd07f016dcc857890605a06 100644 (file)
@@ -46,6 +46,8 @@ def init_all_types():
                      'string', 'ss', 'empty_string'),
         Type.new_any('boolean', 'double', 'number', 'n',
                      'boolean', 'ns', 'SYSMIS'),
                      'string', 'ss', 'empty_string'),
         Type.new_any('boolean', 'double', 'number', 'n',
                      'boolean', 'ns', 'SYSMIS'),
+        Type.new_any('integer', 'int', 'number', 'n',
+                     'integer', 'ns', 'SYSMIS'),
 
         # Format types.
         Type.new_atom('format'),
 
         # Format types.
         Type.new_atom('format'),
@@ -55,8 +57,6 @@ def init_all_types():
                       'format', 'f', 'num_output_format'),
 
         # Integer types.
                       'format', 'f', 'num_output_format'),
 
         # Integer types.
-        Type.new_leaf('integer', 'int', 'integer', 'n',
-                      'integer'),
         Type.new_leaf('pos_int', 'int', 'integer', 'n',
                       'positive_integer_constant'),
 
         Type.new_leaf('pos_int', 'int', 'integer', 'n',
                       'positive_integer_constant'),
 
@@ -72,6 +72,12 @@ def init_all_types():
         # Vectors.
         Type.new_leaf('vector', 'const struct vector *',
                       'vector', 'v', 'vector'),
         # Vectors.
         Type.new_leaf('vector', 'const struct vector *',
                       'vector', 'v', 'vector'),
+        Type.new_any('num_vec_elem', 'double', 'number', 'n',
+                     'number', 'ns', 'SYSMIS'),
+
+        # Types as leaves or auxiliary data.
+        Type.new_leaf('expr_node', 'const struct expr_node *',
+                      'expr_node', 'e', 'expr_node'),
 
         # Types that appear only as auxiliary data.
         Type.new_auxonly('expression', 'struct expression *', 'e'),
 
         # Types that appear only as auxiliary data.
         Type.new_auxonly('expression', 'struct expression *', 'e'),
@@ -118,14 +124,14 @@ class Type:
 
         'c_type' is the type used for C objects of this type.
 
 
         'c_type' is the type used for C objects of this type.
 
+        'atom' should be the name of the member of "union
+        operation_data" that holds a value of this type.
+
         'mangle' should be a short string for name mangling purposes,
         to allow overloading functions with the same name but
         different argument types.  Use the same 'mangle' for two
         different types if those two types should not be overloaded.
 
         'mangle' should be a short string for name mangling purposes,
         to allow overloading functions with the same name but
         different argument types.  Use the same 'mangle' for two
         different types if those two types should not be overloaded.
 
-        'atom' should be the name of the member of "union
-        operation_data" that holds a value of this type.
-
         'human_name' should be a name to use when describing this type
         to the user (see Op.prototype()).
 
         'human_name' should be a name to use when describing this type
         to the user (see Op.prototype()).
 
@@ -236,7 +242,7 @@ class Op:
             for arg in self.args:
                 arg_name = 'arg_%s' % arg.name
                 if arg.idx is None:
             for arg in self.args:
                 arg_name = 'arg_%s' % arg.name
                 if arg.idx is None:
-                    if arg.type_.name in ['number', 'boolean']:
+                    if arg.type_.name in ['number', 'boolean', 'integer']:
                         sysmis_cond += ['!is_valid (%s)' % arg_name]
                 elif arg.type_.name == 'number':
                     a = arg_name
                         sysmis_cond += ['!is_valid (%s)' % arg_name]
                 elif arg.type_.name == 'number':
                     a = arg_name
@@ -313,6 +319,10 @@ class Op:
             flags += ['OPF_PERM_ONLY']
         if self.no_abbrev:
             flags += ['OPF_NO_ABBREV']
             flags += ['OPF_PERM_ONLY']
         if self.no_abbrev:
             flags += ['OPF_NO_ABBREV']
+        for aux in self.aux:
+            if aux['TYPE'].name == 'expr_node':
+                flags += ['OPF_EXPR_NODE']
+                break
         return ' | '.join(flags) if flags else '0'
 
 
         return ' | '.join(flags) if flags else '0'
 
 
@@ -361,7 +371,7 @@ def parse_input():
         return_type = Type.parse()
         if return_type is None:
             return_type = types['number']
         return_type = Type.parse()
         if return_type is None:
             return_type = types['number']
-        if return_type.name not in ['number', 'string', 'boolean']:
+        if return_type.name not in ['number', 'string', 'boolean', 'num_vec_elem']:
             die('%s is not a valid return type' % return_type.name)
 
         if token == 'operator':
             die('%s is not a valid return type' % return_type.name)
 
         if token == 'operator':
@@ -665,17 +675,14 @@ class Arg:
 
 def print_header():
     """Prints the output file header."""
 
 def print_header():
     """Prints the output file header."""
-    out_file.write("""\
-/* %s
-   Generated from %s by generate.py.
-   Do not modify! */
-
-""" % (out_file_name, in_file_name))
+    sys.stdout.write("""\
+/* Generated by generate.py. Do not modify! */
+""")
 
 
 def print_trailer():
     """Prints the output file trailer."""
 
 
 def print_trailer():
     """Prints the output file trailer."""
-    out_file.write("""\
+    sys.stdout.write("""\
 
 /*
    Local Variables:
 
 /*
    Local Variables:
@@ -687,7 +694,7 @@ def print_trailer():
 
 
 def generate_evaluate_h():
 
 
 def generate_evaluate_h():
-    out_file.write('#include "helpers.h"\n\n')
+    sys.stdout.write('#include "helpers.h"\n\n')
 
     for op in order:
         if op.unimplemented:
 
     for op in order:
         if op.unimplemented:
@@ -710,26 +717,34 @@ def generate_evaluate_h():
         else:
             statements = '  return %s;\n' % op.expression
 
         else:
             statements = '  return %s;\n' % op.expression
 
-        out_file.write('static inline %s\n' % op.returns.c_type)
-        out_file.write('eval_%s (%s)\n' % (op.opname, ', '.join(args)))
-        out_file.write('{\n')
-        out_file.write(statements)
-        out_file.write('}\n\n')
+        sys.stdout.write('static inline %s\n' % op.returns.c_type)
+        sys.stdout.write('eval_%s (%s)\n' % (op.opname, ', '.join(args)))
+        sys.stdout.write('{\n')
+        sys.stdout.write(statements)
+        sys.stdout.write('}\n\n')
 
 
 def generate_evaluate_inc():
     for op in order:
         if op.unimplemented:
 
 
 def generate_evaluate_inc():
     for op in order:
         if op.unimplemented:
-            out_file.write('case %s:\n' % op.opname)
-            out_file.write('  NOT_REACHED ();\n\n')
+            sys.stdout.write('case %s:\n' % op.opname)
+            sys.stdout.write('  NOT_REACHED ();\n\n')
             continue
 
         decls = []
         args = []
         for arg in op.args:
             type_ = arg.type_
             continue
 
         decls = []
         args = []
         for arg in op.args:
             type_ = arg.type_
-            c_type = type_.c_type
-            args += ['arg_%s' % arg.name]
+            if type_.c_type == 'int ':
+                c_type = 'double '
+                if op.absorb_miss:
+                    args += ['arg_%s == SYSMIS ? INT_MIN : arg_%s'
+                             % (arg.name, arg.name)]
+                else:
+                    args += ['arg_%s' % arg.name]
+            else:
+                c_type = type_.c_type
+                args += ['arg_%s' % arg.name]
             if arg.idx is None:
                 decl = '%sarg_%s' % (c_type, arg.name)
                 if type_.role == 'any':
             if arg.idx is None:
                 decl = '%sarg_%s' % (c_type, arg.name)
                 if type_.role == 'any':
@@ -755,6 +770,10 @@ def generate_evaluate_inc():
                 decls += ['%saux_%s = op++->%s'
                           % (type_.c_type, name, type_.atom)]
                 args += ['aux_%s' % name]
                 decls += ['%saux_%s = op++->%s'
                           % (type_.c_type, name, type_.atom)]
                 args += ['aux_%s' % name]
+            elif type_.name == 'expr_node':
+                decls += ['%saux_%s = op++->node'
+                          % (type_.c_type, name)]
+                args += ['aux_%s' % name]
             elif type_.role == 'auxonly':
                 args += [type_.auxonly_value]
 
             elif type_.role == 'auxonly':
                 args += [type_.auxonly_value]
 
@@ -766,29 +785,29 @@ def generate_evaluate_inc():
 
         stack = op.returns.stack
 
 
         stack = op.returns.stack
 
-        out_file.write('case %s:\n' % op.opname)
+        sys.stdout.write('case %s:\n' % op.opname)
         if decls:
         if decls:
-            out_file.write('  {\n')
+            sys.stdout.write('  {\n')
             for decl in decls:
             for decl in decls:
-                out_file.write('    %s;\n' % decl)
+                sys.stdout.write('    %s;\n' % decl)
             if sysmis_cond is not None:
                 miss_ret = op.returns.missing_value
             if sysmis_cond is not None:
                 miss_ret = op.returns.missing_value
-                out_file.write('    *%s++ = force_sysmis ? %s : %s;\n'
+                sys.stdout.write('    *%s++ = force_sysmis ? %s : %s;\n'
                                % (stack, miss_ret, result))
             else:
                                % (stack, miss_ret, result))
             else:
-                out_file.write('    *%s++ = %s;\n' % (stack, result))
-            out_file.write('  }\n')
+                sys.stdout.write('    *%s++ = %s;\n' % (stack, result))
+            sys.stdout.write('  }\n')
         else:
         else:
-            out_file.write('  *%s++ = %s;\n' % (stack, result))
-        out_file.write('  break;\n\n')
+            sys.stdout.write('  *%s++ = %s;\n' % (stack, result))
+        sys.stdout.write('  break;\n\n')
 
 
 def generate_operations_h():
 
 
 def generate_operations_h():
-    out_file.write('#include <stdlib.h>\n')
-    out_file.write('#include <stdbool.h>\n\n')
+    sys.stdout.write('#include <stdlib.h>\n')
+    sys.stdout.write('#include <stdbool.h>\n\n')
 
 
-    out_file.write('typedef enum')
-    out_file.write('  {\n')
+    sys.stdout.write('typedef enum')
+    sys.stdout.write('  {\n')
     atoms = []
     for type_ in types.values():
         if type_.role != 'auxonly':
     atoms = []
     for type_ in types.values():
         if type_.role != 'auxonly':
@@ -800,10 +819,10 @@ def generate_operations_h():
     print_operations('operator', 'OP_function_last + 1',
                      [o.opname for o in opers])
     print_range('OP_composite', 'OP_function_first', 'OP_operator_last')
     print_operations('operator', 'OP_function_last + 1',
                      [o.opname for o in opers])
     print_range('OP_composite', 'OP_function_first', 'OP_operator_last')
-    out_file.write(',\n\n')
+    sys.stdout.write(',\n\n')
     print_range('OP', 'OP_atom_first', 'OP_composite_last')
     print_range('OP', 'OP_atom_first', 'OP_composite_last')
-    out_file.write('\n  }\n')
-    out_file.write('operation_type, atom_type;\n')
+    sys.stdout.write('\n  }\n')
+    sys.stdout.write('operation_type, atom_type;\n')
 
     print_predicate('is_operation', 'OP')
     for key in ('atom', 'composite', 'function', 'operator'):
 
     print_predicate('is_operation', 'OP')
     for key in ('atom', 'composite', 'function', 'operator'):
@@ -811,37 +830,37 @@ def generate_operations_h():
 
 
 def print_operations(type_, first, names):
 
 
 def print_operations(type_, first, names):
-    out_file.write('    /* %s types. */\n' % type_.title())
-    out_file.write('    %s = %s,\n' % (names[0], first))
+    sys.stdout.write('    /* %s types. */\n' % type_.title())
+    sys.stdout.write('    %s = %s,\n' % (names[0], first))
     for name in names[1:]:
     for name in names[1:]:
-        out_file.write('    %s,\n' % name)
+        sys.stdout.write('    %s,\n' % name)
     print_range('OP_%s' % type_, names[0], names[-1])
     print_range('OP_%s' % type_, names[0], names[-1])
-    out_file.write(',\n\n')
+    sys.stdout.write(',\n\n')
 
 
 def print_range(prefix, first, last):
 
 
 def print_range(prefix, first, last):
-    out_file.write('    %s_first = %s,\n' % (prefix, first))
-    out_file.write('    %s_last = %s,\n' % (prefix, last))
-    out_file.write('    n_%s = %s_last - %s_first + 1'
+    sys.stdout.write('    %s_first = %s,\n' % (prefix, first))
+    sys.stdout.write('    %s_last = %s,\n' % (prefix, last))
+    sys.stdout.write('    n_%s = %s_last - %s_first + 1'
                    % (prefix, prefix, prefix))
 
 
 def print_predicate(function, category):
                    % (prefix, prefix, prefix))
 
 
 def print_predicate(function, category):
-    out_file.write('\nstatic inline bool\n')
-    out_file.write('%s (operation_type op)\n' % function)
-    out_file.write('{\n')
+    sys.stdout.write('\nstatic inline bool\n')
+    sys.stdout.write('%s (operation_type op)\n' % function)
+    sys.stdout.write('{\n')
     if function != 'is_operation':
     if function != 'is_operation':
-        out_file.write('  assert (is_operation (op));\n')
-    out_file.write('  return op >= %s_first && op <= %s_last;\n'
+        sys.stdout.write('  assert (is_operation (op));\n')
+    sys.stdout.write('  return op >= %s_first && op <= %s_last;\n'
                    % (category, category))
                    % (category, category))
-    out_file.write('}\n')
+    sys.stdout.write('}\n')
 
 
 def generate_optimize_inc():
     for op in order:
         if not op.optimizable or op.unimplemented:
 
 
 def generate_optimize_inc():
     for op in order:
         if not op.optimizable or op.unimplemented:
-            out_file.write('case %s:\n' % op.opname)
-            out_file.write('  NOT_REACHED ();\n\n')
+            sys.stdout.write('case %s:\n' % op.opname)
+            sys.stdout.write('  NOT_REACHED ();\n\n')
             continue
 
         decls = []
             continue
 
         decls = []
@@ -881,9 +900,8 @@ def generate_optimize_inc():
         for aux in op.aux:
             type_ = aux['TYPE']
             if type_.role == 'leaf':
         for aux in op.aux:
             type_ = aux['TYPE']
             if type_.role == 'leaf':
-                func = 'get_%s_arg' % type_.atom
-                args += '%s (node, %s)' % (func, arg_idx)
-                arg_idx += 1
+                assert type_.name == 'expr_node'
+                args += ['node']
             elif type_.role == 'auxonly':
                 args += [type_.auxonly_value]
             else:
             elif type_.role == 'auxonly':
                 args += [type_.auxonly_value]
             else:
@@ -896,28 +914,28 @@ def generate_optimize_inc():
                       % (op.returns.c_type, miss_ret, result)]
             result = 'result'
 
                       % (op.returns.c_type, miss_ret, result)]
             result = 'result'
 
-        out_file.write('case %s:\n' % op.opname)
+        sys.stdout.write('case %s:\n' % op.opname)
         alloc_func = 'expr_allocate_%s' % op.returns.name
         if decls:
         alloc_func = 'expr_allocate_%s' % op.returns.name
         if decls:
-            out_file.write('  {\n')
+            sys.stdout.write('  {\n')
             for decl in decls:
             for decl in decls:
-                out_file.write('    %s;\n' % decl)
-            out_file.write('    return %s (e, %s);\n' % (alloc_func, result))
-            out_file.write('  }\n')
+                sys.stdout.write('    %s;\n' % decl)
+            sys.stdout.write('    return %s (e, %s);\n' % (alloc_func, result))
+            sys.stdout.write('  }\n')
         else:
         else:
-            out_file.write('  return %s (e, %s);\n' % (alloc_func, result))
-        out_file.write('\n')
+            sys.stdout.write('  return %s (e, %s);\n' % (alloc_func, result))
+        sys.stdout.write('\n')
 
 
 def generate_parse_inc():
     members = ['""', '""', '0', '0', '0', '{}', '0', '0']
 
 
 def generate_parse_inc():
     members = ['""', '""', '0', '0', '0', '{}', '0', '0']
-    out_file.write('{%s},\n' % ', '.join(members))
+    sys.stdout.write('{%s},\n' % ', '.join(members))
 
     for type_ in types.values():
         if type_.role != 'auxonly':
             members = ('"%s"' % type_.name, '"%s"' % type_.human_name,
                        '0', 'OP_%s' % type_.name, '0', '{}', '0', '0')
 
     for type_ in types.values():
         if type_.role != 'auxonly':
             members = ('"%s"' % type_.name, '"%s"' % type_.human_name,
                        '0', 'OP_%s' % type_.name, '0', '{}', '0', '0')
-            out_file.write('{%s},\n' % ', '.join(members))
+            sys.stdout.write('{%s},\n' % ', '.join(members))
 
     for op in order:
         members = []
 
     for op in order:
         members = []
@@ -939,15 +957,16 @@ def generate_parse_inc():
 
         members += ['%s' % (op.array_arg().times if op.array_arg() else 0)]
 
 
         members += ['%s' % (op.array_arg().times if op.array_arg() else 0)]
 
-        out_file.write('{%s},\n' % ', '.join(members))
+        sys.stdout.write('{%s},\n' % ', '.join(members))
 
 
 def usage():
     print("""\
 %s, for generating expression parsers and evaluators from definitions
 
 
 def usage():
     print("""\
 %s, for generating expression parsers and evaluators from definitions
-usage: generate.py -o OUTPUT [-i INPUT] [-h]
+usage: generate.py -o OUTPUT_TYPE [-i INPUT] [-h] > OUTPUT
   -i INPUT    input file containing definitions (default: operations.def)
   -i INPUT    input file containing definitions (default: operations.def)
-  -o OUTPUT   output file
+  -o OUTPUT   output file type, one of: evaluate.h, evaluate.inc,
+              operations.h, optimize.inc, parse.inc    
   -h          display this help message
 """ % argv0)
     sys.exit(0)
   -h          display this help message
 """ % argv0)
     sys.exit(0)
@@ -979,21 +998,20 @@ if __name__ == '__main__':
             '(use --help for help)' % argv0)
 
     in_file = open(in_file_name, 'r')
             '(use --help for help)' % argv0)
 
     in_file = open(in_file_name, 'r')
-    out_file = open(out_file_name, 'w')
 
     init_all_types()
     parse_input()
 
     print_header()
 
     init_all_types()
     parse_input()
 
     print_header()
-    if out_file_name.endswith('evaluate.h'):
+    if out_file_name == 'evaluate.h':
         generate_evaluate_h()
         generate_evaluate_h()
-    elif out_file_name.endswith('evaluate.inc'):
+    elif out_file_name == 'evaluate.inc':
         generate_evaluate_inc()
         generate_evaluate_inc()
-    elif out_file_name.endswith('operations.h'):
+    elif out_file_name == 'operations.h':
         generate_operations_h()
         generate_operations_h()
-    elif out_file_name.endswith('optimize.inc'):
+    elif out_file_name == 'optimize.inc':
         generate_optimize_inc()
         generate_optimize_inc()
-    elif out_file_name.endswith('parse.inc'):
+    elif out_file_name == 'parse.inc':
         generate_parse_inc()
     else:
         die('%s: unknown output type' % argv0)
         generate_parse_inc()
     else:
         die('%s: unknown output type' % argv0)