Click here to Skip to main content
15,895,656 members
Articles / Programming Languages / C++

Crafting an interpreter Part 3 - Parse Trees and Syntax Trees

Rate me:
Please Sign up or sign in to vote.
4.77/5 (35 votes)
17 May 2005CPOL10 min read 100.1K   3.2K   85  
Third article on building a language interpreter describing the generation of parse trees and syntax trees.
/*	peg_tprint.h
	Created: 2005 Mai; Author: Martin.Holzherr@infobrain.com
	Copyright: This software is free of copyright's and is part of a work-in-progress
*/
/*  defines a print protocol for parse and syntax trees generated with the
	peg_tree module. 
	Tree printers should be derived from struct PrintNode.
	The 'PrintUCharNode' class covers a case where the Iterator 
	has type const unsigned char*
*/
#ifndef PEG_TPRINT_H_
#define PEG_TPRINT_H_

#include <map>
namespace peg_tprint{
using namespace peg_tree;
template<typename It >
struct PrintNode{
	virtual size_t  LenMaxLine	()=0;
	virtual bool	IsLeaf		(TNode<It>* p)=0;
	virtual bool	IsSkip		(TNode<It>* p){(p);return false;}
	virtual void	PrintNodeBeg(TNode<It>* p, bool bAlignVertical, 
								size_t& nOffsetLineBeg, size_t nLevel)=0;
	virtual void	PrintNodeEnd(TNode<It>* p, bool bAlignVertical, 
								 size_t& nOffsetLineBeg, size_t nLevel)=0;
	virtual size_t	LenNodeBeg	(TNode<It>* p)=0;
	virtual size_t	LenNodeEnd  (TNode<It>* p)=0;
	virtual void    PrintLeaf   (TNode<It>* p, size_t& nOffsetLineBeg, 
												bool bAlignVertical)=0;
	virtual size_t  LenLeaf		(TNode<It>* p)=0; 
	virtual size_t	LenDistNext	(TNode<It>* p, bool bAlignVertical,
									size_t& nOffsetLineBeg,int nLevel)=0;
	virtual void	PrintDistNext( TNode<It>* p, bool bAlignVertical,
									size_t& nOffsetLineBeg,int nLevel)=0;
};
struct PrintUCharNode : public PrintNode<const unsigned char*>{
	typedef const unsigned char* CUCharPtr;
	typedef std::pair<int,const char*> IdName;
	PrintUCharNode(std::ostream& os, size_t nMaxLineLen=60,
										IdName* pBeg=0,IdName* pEnd=0)
		:m_os(os),m_nMaxLineLen(nMaxLineLen),m_mapIdName(pBeg,pEnd)
	{
	}
	virtual size_t	LenMaxLine(){return m_nMaxLineLen;}
	virtual void	
		PrintNodeBeg(TNode<CUCharPtr>* p, bool bAlignVertical, 
								size_t& nOffsetLineBeg, size_t nLevel)
	{	
		(nLevel);
		PrintIdAsName(p);
		m_os << "<"; 
		if( bAlignVertical ){
			m_os << std::endl	<< std::string(nOffsetLineBeg+= 2,' ');
		}else{
			++nOffsetLineBeg;
		}
	}
	virtual void	
		PrintNodeEnd(TNode<CUCharPtr>* p, bool bAlignVertical, 
								size_t& nOffsetLineBeg, size_t nLevel)
	{
		(nLevel);(p);(nOffsetLineBeg);
		if( bAlignVertical ){
			m_os << std::endl	<<	std::string(nOffsetLineBeg-= 2,' ');
		}
		m_os << ">";
		if( !bAlignVertical ){
			++nOffsetLineBeg;
		}
	}
	virtual size_t	LenNodeBeg	(TNode<CUCharPtr>* p){return LenIdAsName(p)+1;}
	virtual size_t	LenNodeEnd  (TNode<CUCharPtr>* p){(p);return 1;}
	virtual void    PrintLeaf   (TNode<CUCharPtr>* p, 
								size_t& nOffsetLineBeg, bool bAlignVertical)
	{
		(nOffsetLineBeg);(bAlignVertical);
		int len= p->match.end - p->match.beg;
		m_os << "'";
		if( len > 0 ){
			m_os	<<	std::string((const char*)p->match.beg,len);
		}
		m_os << "'";
	}
	virtual size_t  LenLeaf(TNode<CUCharPtr>* p){
		return p->match.end - p->match.beg+2;
	}
	virtual bool	IsLeaf		(TNode<CUCharPtr>* p)
	{
		return p->child==0;
	}
	
	virtual void	
		PrintDistNext(TNode<CUCharPtr>* p, bool bAlignVertical,
								size_t& nOffsetLineBeg,int nLevel)
	{
		(p);(nLevel);
		if(bAlignVertical){
			m_os << std::endl	<<	std::string(nOffsetLineBeg,' ');
		}else{
			m_os << " ";++nOffsetLineBeg;
		}
	}

	virtual size_t	
		LenDistNext		(TNode<CUCharPtr>* p,  bool bAlignVertical,
									size_t& nOffsetLineBeg,int nLevel)
	{
		(p);(bAlignVertical);(nOffsetLineBeg);(nLevel);
		return 1;
	}
	virtual size_t LenIdAsName(TNode<CUCharPtr>* p)
	{
		MapIdName::const_iterator it= m_mapIdName.find(p->id);
		if( it!=m_mapIdName.end() ){return strlen(it->second);}
		return 0;
	}
	virtual void PrintIdAsName(TNode<CUCharPtr>* p)
	{
		MapIdName::const_iterator it= m_mapIdName.find(p->id);
		if( it!=m_mapIdName.end() ){m_os << it->second;}
	}
	typedef std::map<int,const char*> MapIdName;
	MapIdName m_mapIdName;
	std::ostream&	m_os;
	size_t			m_nMaxLineLen;
private:
	PrintUCharNode& operator=(const PrintUCharNode&);
};
template<typename It>
size_t DetermineLineLength(TNode<It>* pParent,PrintNode<It>& rp,
									size_t nOffsetLineBeg,size_t nLevel)
{
	(nLevel);
	size_t nLen= rp.LenNodeBeg(pParent);
	for(TNode<It>* p= pParent->child ;p;p= p->next){
		if( rp.IsSkip(p) )continue;
		if( rp.IsLeaf(p) ){
			nLen+= rp.LenLeaf(p);
		}else{
			nLen+= DetermineLineLength(p,rp,nOffsetLineBeg,nLevel);
		}
		if( nLen+nOffsetLineBeg > rp.LenMaxLine() ){
			return nLen+nOffsetLineBeg;
		}
	}
	nLen+= rp.LenNodeEnd(p);
	return nLen;
}
template<typename It>
void PrintTree(TNode<It>* pParent,PrintNode<It>& rp,
							size_t& nOffsetLineBeg,size_t nLevel=0)
{
	if( rp.IsLeaf(pParent) ){
		rp.PrintLeaf(pParent,nOffsetLineBeg, false);
		return;
	}
	bool bAlignVertical= 
		DetermineLineLength(pParent,rp,nOffsetLineBeg,nLevel)>rp.LenMaxLine();
	rp.PrintNodeBeg(pParent,bAlignVertical,nOffsetLineBeg,nLevel);
	size_t nOffset= nOffsetLineBeg;
	for(TNode<It>* p= pParent->child ;p;p= p->next){
		if( rp.IsSkip(p) )continue;
		
		if( rp.IsLeaf(p) ){
			rp.PrintLeaf(p, nOffsetLineBeg, bAlignVertical);
		}else{
			PrintTree(p, rp, nOffsetLineBeg, nLevel+1);
		}
		if( bAlignVertical ){
			nOffsetLineBeg= nOffset;
		}
		while(p->next && rp.IsSkip(p->next)){
			p= p->next;
		}
		if(p->next ){
			rp.PrintDistNext(p,bAlignVertical, nOffsetLineBeg, nLevel);
		}
	}
	rp.PrintNodeEnd(pParent,bAlignVertical,nOffsetLineBeg,nLevel);
}
}
#endif

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Switzerland Switzerland
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions