Start with: dodec(d)|~(cube(a)&larger(f, a)) X 1. Remove all spaces following commas: dodec(d)|~(cube(a)&larger(f,a)) X 2. Convert grouping parentheses (but not predicate parentheses) into brackets: dodec(d)|~[cube(a)&larger(f,a)] X 3. Prefix every negation with a filler NULL dodec(d)|NULL~[cube(a)&larger(f,a)] X 4. Pad front, back, and all operators (including brackets) with a space: dodec(d) | NULL ~ [ cube(a) & larger(f,a) ] X 5. *** Transform to Prefix notation *** | dodec(d) ~ NULL & cube(a) larger(f,a) 6. Reduce extra whitespace | dodec(d) ~ NULL & cube(a) larger(f,a) / 7. Strip padding | dodec(d) ~ NULL & cube(a) larger(f,a) / 8. Split on space ['|', 'dodec(d)', '~', 'NULL', '&', 'cube(a)', 'larger(f,a)'] X 9. List2Tuple: Traverse array, reading each operator and gobbling up the next two subexpressions recursively (with special case for negation) into tuple format: ('|', 'dodec(d)', ('~', ('&', 'cube(a)', 'larger(f,a)'))) ('|', ('dodec', 'd'), ('~', ('&', ('cube', 'a'), ('larger', 'f', 'a')))) TO-DO: X Remove name unique-ing in fol2umrs / handle negation (already in prefix form; just one argument) X hallucinate NULL LHSs