Preprocessor Tree Implementation

Post your FreeBASIC tips and tricks here. Please don’t post your code without including an explanation.
Hexadecimal Dude!
Posts: 360
Joined: Jun 07, 2005 20:59
Location: england, somewhere around the middle
Contact:

Preprocessor Tree Implementation

Postby Hexadecimal Dude! » Jul 20, 2009 22:27

Hi, as part of a bigger, top-secret, project, I needed to make a tree in the preprocessor which has children added to it in a BASIC-like way. This is the child of that need. Warning: you may go insane if you read this code :)

Thanks to Mysoft for showing me a cool trick for making "variables" on the preprocessor.

Huggs and kisses,

Hexadecimal Dude!
xx

Code: Select all

'''A Tree for the FreeBASIC Preprocessor
'''Written by J. A. B. Razavi
'''
'''Insofar as I have rights to restrict the use of this code, and to the extent
'''permitted by the law, I relinquish those rights.
'''In future this code will be incorporated in a larger project, which will be
'''under a CC0 public domain dedication.

'Introduction:
'
'The goal of this file is to provide a preprocessor based tree implementation
'which is populated in a BASIC-like Child...EndChild block style.
'Our method of attack is to view the tree in progress as a stack, where the
'bottom of the stack represents most of the tree, while the rest represents
'tree nodes "to be merged into the tree at a later time", in other words the
'stack stores all nodes on the tree which are on the way to the "currently
'live" node (i.e. those node which contain it).
'We will ceate and make use of preprocessor "classes" to represent: mutable
'objects (ppVar), stacks (ppStack), tree nodes (ppTNode) and finally trees
'(ppTree).
'We will make use of the FreeBASIC Extended Library to provide stack and
'tuple functionality.

#include "ext/preprocessor/seq.bi"
#include "ext/preprocessor/tuple.bi"

''ppVar

'The ppVar class is designed to represent mutable objects on the preprocessor.
'This is achieved by providing a "set" method which can take a value depending
'on the previous value of the object as the next value.
'Many thanks to Mysoft for teaching me this trick.

#macro ppVar(ppVar_name, ppVar_init)
   
   'constructor
   #define ppVar_name ppVar_init
   
   'mutator
   #macro ppVar_name##_set(ppVar_newValue)
      #undef ppVar_name
      #define ppVar_name ppVar_newValue
   #endmacro
   
   'destructor
   #macro ppVar_name##_destroy()
      #undef ppVar_name##_set
      #undef ppVar_name##_destroy
      #undef ppVar_name
   #endmacro

#endmacro

''ppStack

'The ppStack class is designed to represent stack objects on the preprocessor.
'It is basically a ppVar which leverages the power of fbext's sequence
'operations.
'Note: the "pop" method does not return a value, it merely discards the head!

#macro ppStack(ppStack_name, ppStack_init)
   
   'constructor
   ppVar(ppStack_name##_state,ppStack_init)
   
   'value (inspector)
   #define ppStack_name##_value() ppStack_name##_state
   
   'head (inspector)
   #define ppStack_name##_head() fbextPP_SeqHead(ppStack_name##_state)
   
   'push (mutator)
   #define ppStack_name##_push(ppStack_value) _
      ppStack_name##_state_set(fbextPP_SeqPushFront(ppStack_name##_state,ppStack_value))
   
   'pop (mutator)
   #define ppStack_name##_pop() _
      ppStack_name##_state_set(fbextPP_SeqPopFront(ppStack_name##_state))
   
   'destructor
   #macro ppStack_name##_destroy()
      #undef ppStack_name##_value
      #undef ppStack_name##_head
      #undef ppStack_name##_push
      #undef ppStack_name##_pop
      #undef ppStack_name##_destroy
      ppStack_name##_state_destroy()
   #endmacro
   
#endmacro

''ppTNode - a node for the tree

'The ppTNode class is designed to represent nodes of a tree object.
'Concretely, a ppTNode is a triple of the form (noChildFlag,data,children)
'where "noChildFlag" is "1" if the ppTNode has no children, data is the data of
'the ppTNode, and children is a stack, suitable to be treated as the value of a
'ppStack, of ppTNodes-- the children of the current ppTNode.
'Note: the empty ppTNode has form (1,data,0)

#macro ppTNode(ppTNode_name, ppTNode_init)
   
   'constructor
   ppVar(ppTNode_name##_state, ppTNode_init)
   
   'value (inspector)
   #define ppTNode_name##_value() ppTNode_name##_state
   
   'data (inspector)
   #define ppTNode_name##_data() fbextPP_TupleElem(3, 1, ppTNode_name##_state)
   
   'children (inspector)
   #define ppTNode_name##_children() fbextPP_TupleElem(3, 2, ppTNode_name##_state)
     
   'hasNoChildren (inspector)
   #define ppTNode_name##_hasNoChildren() fbextPP_TupleElem(3, 0, ppTNode_name##_state)
   
   'addChild (mutator)
   #macro ppTNode_name##_addChild(ppTNode_childValue)
      #if ppTNode_name##_hasNoChildren()
         'If there are no children, simply replace the placeholder child value
    'with the to-be-added child.
         ppTNode_name##_state_set((0, ppTNode_name##_data(), (ppTNode_childValue)))
      #else
         'If there are other children already, then treat them as a ppStack,
    'pop the to-be-added child onto this, and replace the old stack with
    'the new one.
         ppStack(ppTNode_name##_temp, ppTNode_name##_children())
         ppTNode_name##_temp_push(ppTNode_childValue)
         ppTNode_name##_state_set((0, ppTNode_name##_data(), ppTNode_name##_temp_value()))
         ppTNode_name##_temp_destroy()
      #endif
   #endmacro
   
   'destructor
   #macro ppTNode_name##_destroy()
      #undef ppTNode_name##_value
      #undef ppTNode_name##_data
      #undef ppTNode_name##_children
      #undef ppTNode_name##_hasNoChildren
      #undef ppTNode_name##_addChild
      #undef ppTNode_name##_destroy
      ppTNode_name##_state_destroy()
   #endmacro
   
#endmacro

''ppTree

'The ppTree completes the mission of this file by providing a tree
'implementation to which children are added in a BASIC-like block style.

#macro ppTree(ppTree_name, ppTree_headData)
   
   'constructor
   ppStack(ppTree_name##_state,(ppTree_initial))
      'stack of nodes which are ancestors of the current node.
   ppVar(ppTree_name##_working,(1,ppTree_headData,0))
      'current node of the tree: when the tree is complete, this will be the
      'whole tree.
   
   'value (inspector)
   #define ppTree_name##_value() ppTree_name##_working
   
   'begin child
   #macro ppTree_name##_child(ppTree_childValue)
      'push current working
      ppTree_name##_state_push(ppTree_name##_working)
      'clear current working
      ppTree_name##_working_set((1, ppTree_childValue, 0))
   #endmacro
   
   'end child
   #macro ppTree_name##_endChild()
      'create a temporary tree node with the current value of the current
      'node's direct parent (which will be the head, i.e. most recently
      'added node, of the stack).
      'Then pop the original parent off the stack.
      'Then add the current node as a child of the temporary node.
      'Finally let the former parent become the new currently-worked-on node.
      ppTNode(ppTree_name##_temp, ppTree_name##_state_head())
      ppTree_name##_state_pop()
      ppTree_name##_temp_addChild(ppTree_name##_working)
      ppTree_name##_working_set(ppTree_name##_temp_value())
      ppTree_name##_temp_destroy()
   #endmacro
   
   'destructor
   #macro ppTree_name##_destroy()
      #undef ppTree_name##_value
      #undef ppTree_name##_child
      #undef ppTree_name##_endChild
      ppTree_name##_working_destroy()
      ppTree_name##_state_destroy()
   #endmacro
   
#endmacro

''testing

ppTree(tree, testTree)

tree_child(A)
   tree_child(AA)
      tree_child(AA1)
      tree_endChild()
      tree_child(AA2)
      tree_endChild()
   tree_endChild()
   tree_child(AB)
   tree_endChild()
tree_endChild()

#print tree_value()
KristopherWindsor
Posts: 2428
Joined: Jul 19, 2006 19:17
Location: Sunnyvale, CA
Contact:

Postby KristopherWindsor » Jul 21, 2009 4:09

Probably nice, but it needs Ext. =p
Hexadecimal Dude!
Posts: 360
Joined: Jun 07, 2005 20:59
Location: england, somewhere around the middle
Contact:

Postby Hexadecimal Dude! » Jul 21, 2009 11:34

Kris, I can't believe a hardcore Fb'er like you doesn't have ext installed! imho it's about time FB shipped with it!
Voltage
Posts: 110
Joined: Nov 19, 2005 7:36
Location: Sydney, Australia
Contact:

Postby Voltage » Jul 21, 2009 23:40

Very cool use of the preprocessor.... but why?
McLovin
Posts: 82
Joined: Oct 21, 2008 1:15
Contact:

Postby McLovin » Jul 22, 2009 0:12

I was going to ask "why" as well, but I didn't want to look stupid for asking the question in case there was an obvious answer. :-)
Hexadecimal Dude!
Posts: 360
Joined: Jun 07, 2005 20:59
Location: england, somewhere around the middle
Contact:

Postby Hexadecimal Dude! » Jul 22, 2009 11:05

Voltage wrote:Very cool use of the preprocessor


Thanks :)

Voltage and McLovin wrote:why?


Oh, there's a reason.... but I'm afraid I'd have to kill you if I told you!

I wrote:[it's] part of a bigger, top-secret , project


Muhahaha...

Anyway, if anyone has the time I'd like some comments on the code style that would be cool, despite being proprocessor code, I've tried to make it as readable as possible.

Return to “Tips and Tricks”

Who is online

Users browsing this forum: No registered users and 2 guests