'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', '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'),
# 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'),
'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.
- '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()).
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
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_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':
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."""
- out_file.write("""\
+ sys.stdout.write("""\
/*
Local Variables:
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:
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:
- 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_
- 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':
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]
stack = op.returns.stack
- out_file.write('case %s:\n' % op.opname)
+ sys.stdout.write('case %s:\n' % op.opname)
if decls:
- out_file.write(' {\n')
+ sys.stdout.write(' {\n')
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
- out_file.write(' *%s++ = force_sysmis ? %s : %s;\n'
+ sys.stdout.write(' *%s++ = force_sysmis ? %s : %s;\n'
% (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:
- 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():
- 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':
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')
- 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'):
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:]:
- out_file.write(' %s,\n' % name)
+ sys.stdout.write(' %s,\n' % name)
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):
- 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):
- 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':
- 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))
- out_file.write('}\n')
+ sys.stdout.write('}\n')
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 = []
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:
% (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:
- out_file.write(' {\n')
+ sys.stdout.write(' {\n')
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:
- 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']
- 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')
- out_file.write('{%s},\n' % ', '.join(members))
+ sys.stdout.write('{%s},\n' % ', '.join(members))
for op in order:
members = []
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
-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)
- -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)
'(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()
- if out_file_name.endswith('evaluate.h'):
+ if out_file_name == 'evaluate.h':
generate_evaluate_h()
- elif out_file_name.endswith('evaluate.inc'):
+ elif out_file_name == 'evaluate.inc':
generate_evaluate_inc()
- elif out_file_name.endswith('operations.h'):
+ elif out_file_name == 'operations.h':
generate_operations_h()
- elif out_file_name.endswith('optimize.inc'):
+ elif out_file_name == '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)