/** * Dump/print a slang_operation tree */ #include "imports.h" #include "slang_compile.h" #include "slang_print.h" static void spaces(int n) { while (n--) printf(" "); } static void print_type(const slang_fully_specified_type *t) { switch (t->qualifier) { case slang_qual_none: /*printf("");*/ break; case slang_qual_const: printf("const "); break; case slang_qual_attribute: printf("attrib "); break; case slang_qual_varying: printf("varying "); break; case slang_qual_uniform: printf("uniform "); break; case slang_qual_out: printf("output "); break; case slang_qual_inout: printf("inout "); break; case slang_qual_fixedoutput: printf("fixedoutput"); break; case slang_qual_fixedinput: printf("fixedinput"); break; default: printf("unknown qualifer!"); } switch (t->specifier.type) { case slang_spec_void: printf("void"); break; case slang_spec_bool: printf("bool"); break; case slang_spec_bvec2: printf("bvec2"); break; case slang_spec_bvec3: printf("bvec3"); break; case slang_spec_bvec4: printf("bvec4"); break; case slang_spec_int: printf("int"); break; case slang_spec_ivec2: printf("ivec2"); break; case slang_spec_ivec3: printf("ivec3"); break; case slang_spec_ivec4: printf("ivec4"); break; case slang_spec_float: printf("float"); break; case slang_spec_vec2: printf("vec2"); break; case slang_spec_vec3: printf("vec3"); break; case slang_spec_vec4: printf("vec4"); break; case slang_spec_mat2: printf("mat2"); break; case slang_spec_mat3: printf("mat3"); break; case slang_spec_mat4: printf("mat4"); break; case slang_spec_sampler1D: printf("sampler1D"); break; case slang_spec_sampler2D: printf("sampler2D"); break; case slang_spec_sampler3D: printf("sampler3D"); break; case slang_spec_samplerCube: printf("samplerCube"); break; case slang_spec_sampler1DShadow: printf("sampler1DShadow"); break; case slang_spec_sampler2DShadow: printf("sampler2DShadow"); break; case slang_spec_struct: printf("struct"); break; case slang_spec_array: printf("array"); break; default: printf("unknown type"); } /*printf("\n");*/ } static void print_variable(const slang_variable *v, int indent) { spaces(indent); printf("VAR "); print_type(&v->type); printf(" %s", (char *) v->a_name); if (v->initializer) { printf(" :=\n"); slang_print_tree(v->initializer, indent + 3); } else { printf(";\n"); } } static void print_binary(const slang_operation *op, const char *oper, int indent) { assert(op->num_children == 2); slang_print_tree(&op->children[0], indent + 3); spaces(indent); printf("%s\n", oper); slang_print_tree(&op->children[1], indent + 3); } static void print_generic2(const slang_operation *op, const char *oper, const char *s, int indent) { int i; if (oper) { spaces(indent); printf("[%p locals %p] %s %s\n", (void*) op, (void*) op->locals, oper, s); } for (i = 0; i < op->num_children; i++) { spaces(indent); printf("//child %d:\n", i); slang_print_tree(&op->children[i], indent); } } static void print_generic(const slang_operation *op, const char *oper, int indent) { print_generic2(op, oper, "", indent); } static const slang_variable_scope * find_scope(const slang_variable_scope *s, slang_atom name) { GLuint i; for (i = 0; i < s->num_variables; i++) { if (s->variables[i].a_name == name) return s; } if (s->outer_scope) return find_scope(s->outer_scope, name); else return NULL; } static const slang_variable * find_var(const slang_variable_scope *s, slang_atom name) { GLuint i; for (i = 0; i < s->num_variables; i++) { if (s->variables[i].a_name == name) return &s->variables[i]; } if (s->outer_scope) return find_var(s->outer_scope, name); else return NULL; } void slang_print_tree(const slang_operation *op, int indent) { int i; switch (op->type) { case slang_oper_none: spaces(indent); printf("slang_oper_none\n"); break; case slang_oper_block_no_new_scope: spaces(indent); printf("{ locals %p\n", (void*)op->locals); print_generic(op, NULL, indent+3); spaces(indent); printf("}\n"); break; case slang_oper_block_new_scope: spaces(indent); printf("{{ // new scope locals %p\n", (void*)op->locals); print_generic(op, NULL, indent+3); spaces(indent); printf("}}\n"); break; case slang_oper_variable_decl: assert(op->num_children == 0 || op->num_children == 1); { slang_variable *v; v = _slang_locate_variable(op->locals, op->a_id, GL_TRUE); if (v) { spaces(indent); printf("DECL (locals=%p outer=%p) ", (void*)op->locals, (void*) op->locals->outer_scope); print_type(&v->type); printf(" %s (%p)", (char *) op->a_id, (void *) find_var(op->locals, op->a_id)); printf(" (in scope %p) ", (void *) find_scope(op->locals, op->a_id)); if (op->num_children == 1) { printf(" :=\n"); slang_print_tree(&op->children[0], indent + 3); } else if (v->initializer) { printf(" := INITIALIZER\n"); slang_print_tree(v->initializer, indent + 3); } else { printf(";\n"); } /* spaces(indent); printf("TYPE: "); print_type(&v->type); spaces(indent); printf("ADDR: %d size: %d\n", v->address, v->size); */ } else { abort(); spaces(indent); printf("DECL %s (anonymous variable!!!!)\n", (char *) op->a_id); /*abort();*/ } } break; case slang_oper_asm: spaces(indent); printf("ASM: %s\n", (char*) op->a_id); print_generic(op, NULL, indent+3); break; case slang_oper_break: spaces(indent); printf("BREAK\n"); break; case slang_oper_continue: spaces(indent); printf("CONTINUE\n"); break; case slang_oper_discard: spaces(indent); printf("DISCARD\n"); break; case slang_oper_return: spaces(indent); printf("RETURN\n"); if (op->num_children > 0) slang_print_tree(&op->children[0], indent + 3); break; case slang_oper_goto: spaces(indent); printf("GOTO %s\n", (char *) op->a_id); break; case slang_oper_label: spaces(indent); printf("LABEL %s\n", (char *) op->a_id); break; case slang_oper_expression: spaces(indent); printf("EXPR: locals %p\n", (void*) op->locals); /*print_generic(op, "slang_oper_expression", indent);*/ slang_print_tree(&op->children[0], indent + 3); break; case slang_oper_if: spaces(indent); printf("IF\n"); slang_print_tree(&op->children[0], indent + 3); spaces(indent); printf("THEN\n"); slang_print_tree(&op->children[1], indent + 3); spaces(indent); printf("ELSE\n"); slang_print_tree(&op->children[2], indent + 3); spaces(indent); printf("ENDIF\n"); break; case slang_oper_while: assert(op->num_children == 2); spaces(indent); printf("WHILE cond:\n"); slang_print_tree(&op->children[0], indent + 3); spaces(indent); printf("WHILE body:\n"); slang_print_tree(&op->children[1], indent + 3); break; case slang_oper_do: spaces(indent); printf("DO body:\n"); slang_print_tree(&op->children[0], indent + 3); spaces(indent); printf("DO cond:\n"); slang_print_tree(&op->children[1], indent + 3); break; case slang_oper_for: spaces(indent); printf("FOR init:\n"); slang_print_tree(&op->children[0], indent + 3); spaces(indent); printf("FOR while:\n"); slang_print_tree(&op->children[1], indent + 3); spaces(indent); printf("FOR step:\n"); slang_print_tree(&op->children[2], indent + 3); spaces(indent); printf("FOR body:\n"); slang_print_tree(&op->children[3], indent + 3); spaces(indent); printf("ENDFOR\n"); /* print_generic(op, "FOR", indent + 3); */ break; case slang_oper_void: spaces(indent); printf("(oper-void)\n"); break; case slang_oper_literal_bool: spaces(indent); /*printf("slang_oper_literal_bool\n");*/ printf("%s\n", op->literal[0] ? "TRUE" : "FALSE"); break; case slang_oper_literal_int: spaces(indent); /*printf("slang_oper_literal_int\n");*/ printf("(%d %d %d %d)\n", (int) op->literal[0], (int) op->literal[1], (int) op->literal[2], (int) op->literal[3]); break; case slang_oper_literal_float: spaces(indent); /*printf("slang_oper_literal_float\n");*/ printf("(%f %f %f %f)\n", op->literal[0], op->literal[1], op->literal[2], op->literal[3]); break; case slang_oper_identifier: spaces(indent); if (op->var && op->var->a_name) printf("VAR %s (in scope %p)\n", (char *) op->var->a_name, (void *) find_scope(op->locals, op->a_id)); else printf("VAR' %s (in scope %p)\n", (char *) op->a_id, (void *) find_scope(op->locals, op->a_id)); break; case slang_oper_sequence: print_generic(op, "COMMA-SEQ", indent+3); break; case slang_oper_assign: spaces(indent); printf("ASSIGNMENT locals %p\n", (void*)op->locals); print_binary(op, ":=", indent); break; case slang_oper_addassign: spaces(indent); printf("ASSIGN\n"); print_binary(op, "+=", indent); break; case slang_oper_subassign: spaces(indent); printf("ASSIGN\n"); print_binary(op, "-=", indent); break; case slang_oper_mulassign: spaces(indent); printf("ASSIGN\n"); print_binary(op, "*=", indent); break; case slang_oper_divassign: spaces(indent); printf("ASSIGN\n"); print_binary(op, "/=", indent); break; /*slang_oper_modassign,*/ /*slang_oper_lshassign,*/ /*slang_oper_rshassign,*/ /*slang_oper_orassign,*/ /*slang_oper_xorassign,*/ /*slang_oper_andassign,*/ case slang_oper_select: spaces(indent); printf("slang_oper_select n=%d\n", op->num_children); assert(op->num_children == 3); slang_print_tree(&op->children[0], indent+3); spaces(indent); printf("?\n"); slang_print_tree(&op->children[1], indent+3); spaces(indent); printf(":\n"); slang_print_tree(&op->children[2], indent+3); break; case slang_oper_logicalor: print_binary(op, "||", indent); break; case slang_oper_logicalxor: print_binary(op, "^^", indent); break; case slang_oper_logicaland: print_binary(op, "&&", indent); break; /*slang_oper_bitor*/ /*slang_oper_bitxor*/ /*slang_oper_bitand*/ case slang_oper_equal: print_binary(op, "==", indent); break; case slang_oper_notequal: print_binary(op, "!=", indent); break; case slang_oper_less: print_binary(op, "<", indent); break; case slang_oper_greater: print_binary(op, ">", indent); break; case slang_oper_lessequal: print_binary(op, "<=", indent); break; case slang_oper_greaterequal: print_binary(op, ">=", indent); break; /*slang_oper_lshift*/ /*slang_oper_rshift*/ case slang_oper_add: print_binary(op, "+", indent); break; case slang_oper_subtract: print_binary(op, "-", indent); break; case slang_oper_multiply: print_binary(op, "*", indent); break; case slang_oper_divide: print_binary(op, "/", indent); break; /*slang_oper_modulus*/ case slang_oper_preincrement: spaces(indent); printf("PRE++\n"); slang_print_tree(&op->children[0], indent+3); break; case slang_oper_predecrement: spaces(indent); printf("PRE--\n"); slang_print_tree(&op->children[0], indent+3); break; case slang_oper_plus: spaces(indent); printf("slang_oper_plus\n"); break; case slang_oper_minus: spaces(indent); printf("slang_oper_minus\n"); break; /*slang_oper_complement*/ case slang_oper_not: spaces(indent); printf("NOT\n"); slang_print_tree(&op->children[0], indent+3); break; case slang_oper_subscript: spaces(indent); printf("slang_oper_subscript\n"); print_generic(op, NULL, indent+3); break; case slang_oper_call: #if 0 slang_function *fun = _slang_locate_function(A->space.funcs, oper->a_id, oper->children, oper->num_children, &A->space, A->atoms); #endif spaces(indent); printf("CALL %s(\n", (char *) op->a_id); for (i = 0; i < op->num_children; i++) { slang_print_tree(&op->children[i], indent+3); if (i + 1 < op->num_children) { spaces(indent + 3); printf(",\n"); } } spaces(indent); printf(")\n"); break; case slang_oper_field: spaces(indent); printf("FIELD %s of\n", (char*) op->a_id); slang_print_tree(&op->children[0], indent+3); break; case slang_oper_postincrement: spaces(indent); printf("POST++\n"); slang_print_tree(&op->children[0], indent+3); break; case slang_oper_postdecrement: spaces(indent); printf("POST--\n"); slang_print_tree(&op->children[0], indent+3); break; default: printf("unknown op->type %d\n", (int) op->type); } } void slang_print_function(const slang_function *f, GLboolean body) { int i; #if 0 if (_mesa_strcmp((char *) f->header.a_name, "main") != 0) return; #endif printf("FUNCTION %s (\n", (char *) f->header.a_name); for (i = 0; i < f->param_count; i++) { print_variable(&f->parameters->variables[i], 3); } printf(")\n"); if (body && f->body) slang_print_tree(f->body, 0); } /* operation */ #define OP_END 0 #define OP_BLOCK_BEGIN_NO_NEW_SCOPE 1 #define OP_BLOCK_BEGIN_NEW_SCOPE 2 #define OP_DECLARE 3 #define OP_ASM 4 #define OP_BREAK 5 #define OP_CONTINUE 6 #define OP_DISCARD 7 #define OP_RETURN 8 #define OP_EXPRESSION 9 #define OP_IF 10 #define OP_WHILE 11 #define OP_DO 12 #define OP_FOR 13 #define OP_PUSH_VOID 14 #define OP_PUSH_BOOL 15 #define OP_PUSH_INT 16 #define OP_PUSH_FLOAT 17 #define OP_PUSH_IDENTIFIER 18 #define OP_SEQUENCE 19 #define OP_ASSIGN 20 #define OP_ADDASSIGN 21 #define OP_SUBASSIGN 22 #define OP_MULASSIGN 23 #define OP_DIVASSIGN 24 /*#define OP_MODASSIGN 25*/ /*#define OP_LSHASSIGN 26*/ /*#define OP_RSHASSIGN 27*/ /*#define OP_ORASSIGN 28*/ /*#define OP_XORASSIGN 29*/ /*#define OP_ANDASSIGN 30*/ #define OP_SELECT 31 #define OP_LOGICALOR 32 #define OP_LOGICALXOR 33 #define OP_LOGICALAND 34 /*#define OP_BITOR 35*/ /*#define OP_BITXOR 36*/ /*#define OP_BITAND 37*/ #define OP_EQUAL 38 #define OP_NOTEQUAL 39 #define OP_LESS 40 #define OP_GREATER 41 #define OP_LESSEQUAL 42 #define OP_GREATEREQUAL 43 /*#define OP_LSHIFT 44*/ /*#define OP_RSHIFT 45*/ #define OP_ADD 46 #define OP_SUBTRACT 47 #define OP_MULTIPLY 48 #define OP_DIVIDE 49 /*#define OP_MODULUS 50*/ #define OP_PREINCREMENT 51 #define OP_PREDECREMENT 52 #define OP_PLUS 53 #define OP_MINUS 54 /*#define OP_COMPLEMENT 55*/ #define OP_NOT 56 #define OP_SUBSCRIPT 57 #define OP_CALL 58 #define OP_FIELD 59 #define OP_POSTINCREMENT 60 #define OP_POSTDECREMENT 61 void slang_print_opcode(unsigned int opcode) { switch (opcode) { case OP_PUSH_VOID: printf("OP_PUSH_VOID\n"); break; case OP_PUSH_BOOL: printf("OP_PUSH_BOOL\n"); break; case OP_PUSH_INT: printf("OP_PUSH_INT\n"); break; case OP_PUSH_FLOAT: printf("OP_PUSH_FLOAT\n"); break; case OP_PUSH_IDENTIFIER: printf("OP_PUSH_IDENTIFIER\n"); break; case OP_SEQUENCE: printf("OP_SEQUENCE\n"); break; case OP_ASSIGN: printf("OP_ASSIGN\n"); break; case OP_ADDASSIGN: printf("OP_ADDASSIGN\n"); break; case OP_SUBASSIGN: printf("OP_SUBASSIGN\n"); break; case OP_MULASSIGN: printf("OP_MULASSIGN\n"); break; case OP_DIVASSIGN: printf("OP_DIVASSIGN\n"); break; /*case OP_MODASSIGN:*/ /*case OP_LSHASSIGN:*/ /*case OP_RSHASSIGN:*/ /*case OP_ORASSIGN:*/ /*case OP_XORASSIGN:*/ /*case OP_ANDASSIGN:*/ case OP_SELECT: printf("OP_SELECT\n"); break; case OP_LOGICALOR: printf("OP_LOGICALOR\n"); break; case OP_LOGICALXOR: printf("OP_LOGICALXOR\n"); break; case OP_LOGICALAND: printf("OP_LOGICALAND\n"); break; /*case OP_BITOR:*/ /*case OP_BITXOR:*/ /*case OP_BITAND:*/ case OP_EQUAL: printf("OP_EQUAL\n"); break; case OP_NOTEQUAL: printf("OP_NOTEQUAL\n"); break; case OP_LESS: printf("OP_LESS\n"); break; case OP_GREATER: printf("OP_GREATER\n"); break; case OP_LESSEQUAL: printf("OP_LESSEQUAL\n"); break; case OP_GREATEREQUAL: printf("OP_GREATEREQUAL\n"); break; /*case OP_LSHIFT:*/ /*case OP_RSHIFT:*/ case OP_ADD: printf("OP_ADD\n"); break; case OP_SUBTRACT: printf("OP_SUBTRACT\n"); break; case OP_MULTIPLY: printf("OP_MULTIPLY\n"); break; case OP_DIVIDE: printf("OP_DIVIDE\n"); break; /*case OP_MODULUS:*/ case OP_PREINCREMENT: printf("OP_PREINCREMENT\n"); break; case OP_PREDECREMENT: printf("OP_PREDECREMENT\n"); break; case OP_PLUS: printf("OP_PLUS\n"); break; case OP_MINUS: printf("OP_MINUS\n"); break; case OP_NOT: printf("OP_NOT\n"); break; /*case OP_COMPLEMENT:*/ case OP_SUBSCRIPT: printf("OP_SUBSCRIPT\n"); break; case OP_CALL: printf("OP_CALL\n"); break; case OP_FIELD: printf("OP_FIELD\n"); break; case OP_POSTINCREMENT: printf("OP_POSTINCREMENT\n"); break; case OP_POSTDECREMENT: printf("OP_POSTDECREMENT\n"); break; default: printf("UNKNOWN OP %d\n", opcode); } } const char * slang_asm_string(slang_assembly_type t) { switch (t) { /* core */ case slang_asm_none: return "none"; case slang_asm_float_copy: return "float_copy"; case slang_asm_float_move: return "float_move"; case slang_asm_float_push: return "float_push"; case slang_asm_float_deref: return "float_deref"; case slang_asm_float_add: return "float_add"; case slang_asm_float_multiply: return "float_multiply"; case slang_asm_float_divide: return "float_divide"; case slang_asm_float_negate: return "float_negate"; case slang_asm_float_less: return "float_less"; case slang_asm_float_equal_exp: return "float_equal"; case slang_asm_float_equal_int: return "float_equal"; case slang_asm_float_to_int: return "float_to_int"; case slang_asm_float_sine: return "float_sine"; case slang_asm_float_arcsine: return "float_arcsine"; case slang_asm_float_arctan: return "float_arctan"; case slang_asm_float_power: return "float_power"; case slang_asm_float_log2: return "float_log2"; case slang_asm_vec4_floor: return "vec4_floor"; case slang_asm_float_ceil: return "float_ceil"; case slang_asm_float_noise1: return "float_noise1"; case slang_asm_float_noise2: return "float_noise2"; case slang_asm_float_noise3: return "float_noise3"; case slang_asm_float_noise4: return "float_noise4"; case slang_asm_int_copy: return "int_copy"; case slang_asm_int_move: return "int_move"; case slang_asm_int_push: return "int_push"; case slang_asm_int_deref: return "int_deref"; case slang_asm_int_to_float: return "int_to_float"; case slang_asm_int_to_addr: return "int_to_addr"; case slang_asm_bool_copy: return "bool_copy"; case slang_asm_bool_move: return "bool_move"; case slang_asm_bool_push: return "bool_push"; case slang_asm_bool_deref: return "bool_deref"; case slang_asm_addr_copy: return "addr_copy"; case slang_asm_addr_push: return "addr_push"; case slang_asm_addr_deref: return "addr_deref"; case slang_asm_addr_add: return "addr_add"; case slang_asm_addr_multiply: return "addr_multiply"; case slang_asm_vec4_tex1d: return "vec4_tex1d"; case slang_asm_vec4_tex2d: return "vec4_tex2d"; case slang_asm_vec4_tex3d: return "vec4_tex3d"; case slang_asm_vec4_texcube: return "vec4_texcube"; case slang_asm_vec4_shad1d: return "vec4_shad1d"; case slang_asm_vec4_shad2d: return "vec4_shad2d"; case slang_asm_jump: return "jump"; case slang_asm_jump_if_zero: return "jump_if_zero"; case slang_asm_enter: return "enter"; case slang_asm_leave: return "leave"; case slang_asm_local_alloc: return "local_alloc"; case slang_asm_local_free: return "local_free"; case slang_asm_local_addr: return "local_addr"; case slang_asm_global_addr: return "global_addr"; case slang_asm_call: return "call"; case slang_asm_return: return "return"; case slang_asm_discard: return "discard"; case slang_asm_exit: return "exit"; /* GL_MESA_shader_debug */ case slang_asm_float_print: return "float_print"; case slang_asm_int_print: return "int_print"; case slang_asm_bool_print: return "bool_print"; /* vec4 */ case slang_asm_float_to_vec4: return "float_to_vec4"; case slang_asm_vec4_add: return "vec4_add"; case slang_asm_vec4_subtract: return "vec4_subtract"; case slang_asm_vec4_multiply: return "vec4_multiply"; case slang_asm_vec4_divide: return "vec4_divide"; case slang_asm_vec4_negate: return "vec4_negate"; case slang_asm_vec4_dot: return "vec4_dot"; case slang_asm_vec4_copy: return "vec4_copy"; case slang_asm_vec4_deref: return "vec4_deref"; case slang_asm_vec4_equal_int: return "vec4_equal"; default: return "??asm??"; } } const char * slang_type_qual_string(slang_type_qualifier q) { switch (q) { case slang_qual_none: return "none"; case slang_qual_const: return "const"; case slang_qual_attribute: return "attribute"; case slang_qual_varying: return "varying"; case slang_qual_uniform: return "uniform"; case slang_qual_out: return "out"; case slang_qual_inout: return "inout"; case slang_qual_fixedoutput: return "fixedoutput"; case slang_qual_fixedinput: return "fixedinputk"; default: return "qual?"; } } static const char * slang_type_string(slang_type_specifier_type t) { switch (t) { case slang_spec_void: return "void"; case slang_spec_bool: return "bool"; case slang_spec_bvec2: return "bvec2"; case slang_spec_bvec3: return "bvec3"; case slang_spec_bvec4: return "bvec4"; case slang_spec_int: return "int"; case slang_spec_ivec2: return "ivec2"; case slang_spec_ivec3: return "ivec3"; case slang_spec_ivec4: return "ivec4"; case slang_spec_float: return "float"; case slang_spec_vec2: return "vec2"; case slang_spec_vec3: return "vec3"; case slang_spec_vec4: return "vec4"; case slang_spec_mat2: return "mat2"; case slang_spec_mat3: return "mat3"; case slang_spec_mat4: return "mat4"; case slang_spec_sampler1D: return "sampler1D"; case slang_spec_sampler2D: return "sampler2D"; case slang_spec_sampler3D: return "sampler3D"; case slang_spec_samplerCube: return "samplerCube"; case slang_spec_sampler1DShadow: return "sampler1DShadow"; case slang_spec_sampler2DShadow: return "sampler2DShadow"; case slang_spec_struct: return "struct"; case slang_spec_array: return "array"; default: return "type?"; } } static const char * slang_fq_type_string(const slang_fully_specified_type *t) { static char str[1000]; sprintf(str, "%s %s", slang_type_qual_string(t->qualifier), slang_type_string(t->specifier.type)); return str; } void slang_print_type(const slang_fully_specified_type *t) { printf("%s %s", slang_type_qual_string(t->qualifier), slang_type_string(t->specifier.type)); } static char * slang_var_string(const slang_variable *v) { static char str[1000]; sprintf(str, "%s : %s", (char *) v->a_name, slang_fq_type_string(&v->type)); return str; } void slang_print_variable(const slang_variable *v) { printf("Name: %s\n", (char *) v->a_name); printf("Type: %s\n", slang_fq_type_string(&v->type)); } void _slang_print_var_scope(const slang_variable_scope *vars, int indent) { GLuint i; spaces(indent); printf("Var scope %p %d vars\n", (void *) vars, vars->num_variables); for (i = 0; i < vars->num_variables; i++) { spaces(indent + 3); printf("%s\n", (char *) vars->variables[i].a_name); } if (vars->outer_scope) { spaces(indent + 3); printf("outer_scope = %p\n", (void*) vars->outer_scope); _slang_print_var_scope(vars->outer_scope, indent + 3); } } int slang_checksum_tree(const slang_operation *op) { int s = op->num_children; int i; for (i = 0; i < op->num_children; i++) { s += slang_checksum_tree(&op->children[i]); } return s; }