fbcadcam-macro

User contributed sources that have become inactive, deprecated, or generally unusable. But ... we don't really want to throw them away either.
owen
Posts: 555
Joined: Apr 19, 2006 10:55
Location: Kissimmee, FL
Contact:

Re: fbcadcam-macro

Post by owen »

The technique I employ in fbcadcam is about as crude as it gets.

Simply said, I afford the use of 9 (each) 1d, 2d and 3d arrays OF (each) numeric data type (Boolean, Byte, Short, Long, Integer, Double etc..)

In the event the users program (test.bas) does a REDIM

I let FB do the REDIM of that user declared array.

There is no shuffling and of course there is no faster process.

Note: this problem is similar to and has been addressed by the developers of Relational Data Bases. And it is in my thoughts that I might attempt to employ their use for this issue but then fbcadcam-macro would not be independent so to speak.
owen
Posts: 555
Joined: Apr 19, 2006 10:55
Location: Kissimmee, FL
Contact:

Re: fbcadcam-macro

Post by owen »

Yes, fbcadcam-macro is crude at best. I'm not being humble, I'm speaking practically.
For example I say I afford the use of 9 arrays... Well, that's not exactly correct because my SUBS and FUNCTION sucks up (use) some of those available 9 arrays.

declare sub test(t(1) as integer)
dim as integer a(2),b(3),c(4),d(5),e(6),f(7),g(8),h(9) and that's all you get.
dafhi
Posts: 1640
Joined: Jun 04, 2005 9:51

Re: fbcadcam-macro

Post by dafhi »

imnsho everyone should learn oop if the language supports it
owen
Posts: 555
Joined: Apr 19, 2006 10:55
Location: Kissimmee, FL
Contact:

Re: fbcadcam-macro

Post by owen »

It has been in the back of my mind that I would afford the user to use oop in the script (test.bas)
but as you can see i don't oop too much in fact the last thing i did regarding oop was to un-oop Ball collisions physics in the hope I could at the least, understand the physics.... but alas (LOL / IMNSHO/ ISIABSIMA)
dafhi
Posts: 1640
Joined: Jun 04, 2005 9:51

Re: fbcadcam-macro

Post by dafhi »

oop to shorten your own parser :D

you're far ahead of a lot of programmers. so no big deal really.

i think if there were ever to be another sub-forum, it should be about oop
owen
Posts: 555
Joined: Apr 19, 2006 10:55
Location: Kissimmee, FL
Contact:

Re: fbcadcam-macro

Post by owen »

I agree oop is awesome and if I ooped fbcadcam-macro.bas (which i probably will do eventually) then yes, it will shorten it from 30k LOC to something considerably less. I write code un-ooped for my benefit because it helps me keep things sorted (in my own mind). I'm kinda like an old dog that can't learn a new trick. That's not to say I can't write code with oop initially. I can. But if it's a complex (extensive bit of code) then un-oop works best for me.

so i was checking out the list of D.J.Peters FreeBASIC activities of the past 10 years which is absolutely impressive i might add
viewtopic.php?f=17&t=24043
and listed in his Tips and Tricks (source codes): another easy to understand EVAL() expression solver
viewtopic.php?f=7&t=16664
i was reminded about the precedence NEGATE and exponentiate
The correct precedence order is exponentiate first then negate.

ver. 6 had it backwards so i uploaded ver. 7 with this correction
http://fbcadcam.org/fbcadcam-macro/fbca ... ings-7.bas
dafhi
Posts: 1640
Joined: Jun 04, 2005 9:51

Re: fbcadcam-macro

Post by dafhi »

you don't have to oo the whole thing!

congrats on being able to keep track of all that
paul doe
Moderator
Posts: 1730
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: fbcadcam-macro

Post by paul doe »

Hi Owen,

dafhi is right, you don't need to rewrite the whole thing in OOP to be able to use objects effectively.
I took a look at your code. Uff. Seems that you would greatly benefit from some abstractions. First, you will find your code easier to write, easier to expand and hence, easier to maintain.
The first thing that I would recommend is that you split the lexing, parsing and evaluation phases of your scripting language. Then, it will be easier to add new features as you progress. Take a look at the following class, plucked from my Forth compiler/interpreter:

Code: Select all

/'
	very simple lexical scanner class (a.k.a. lexer)
	
	responsibility: splices a string into lexemes ('tokens') using single
		character delimiters
	
	mutability: immutable
		this was originally used in a concurrent system, so it ought to be thread-safe
		immutable classes are thread-safe by design
'/

type lexer
	'' public interface for the class
	public:
		declare constructor( byref inpString as const string, byref del as const string )	
		declare function getToken() as string
	
	'' private members for maintaining state
	private:				
		as string		m_lookChar	'' the current char that m_charPos points to				
		as string		m_delimiters	'' delimiters that are used for string splicing
		as string		m_inputString	'' the string to be spliced
		
		as uinteger	m_charPos		'' current char position on string
		as uinteger	m_stringLen	'' the input string length
		
		'' helper functions
		'' if one were to override these helpers in a derived classes, they should be declared protected
		declare sub m_getChar()		
		declare function m_inString( byref srchString as string, byref strng as string ) as integer
		declare function m_isDelimiter( byref c as string ) as integer
end type

constructor lexer( byref inpString as const string, byref del as const string )	
	/'
		the constructor for the class
		
		note that, as it is an immutable class, it makes no sense to create a default, empty
		constructor, for it needs data to perform its function. This form of passing data to
		immutable objects is called 'dependency injection'
	'/
	m_inputString = inpString
	m_stringLen = len( m_inputString )
	m_charPos = 0
	m_lookChar = ""
	m_delimiters = del
end constructor

function lexer.getToken() as string
	/'
		retrieves the next token on the input string
		if there are no more tokens to retrieve, it returns an empty string to signal
			that there are no more tokens to splice
	'/
	dim as string ret
	
	'' feed a char to the current char if it's empty
	if asc( m_lookChar ) = 0 then
		m_getChar()
	end if
	
	/'
		this is the only complicated piece of code of the class
		
		it works like this:
		
			IF the current char is a delimiter OR the char pos is beyond the string length THEN
				get the next char to advance the char position to the beginning of the next token
					(remember that, if there are no more chars in the string, getChar() returns an empty string)
				return the delimiter
			ELSE
				IF the current char is not a delimiter AND the char pos is less than the string length THEN
					WHILE the current character isn't a delimiter and the current character is not an empty string DO
						assemble the current char into the token
						get the next char
					LOOP
					
					return the assembled token
				END IF
			END IF
	'/
	if( m_isDelimiter( m_lookChar ) or m_charPos >= m_stringLen ) then
		ret = m_lookChar
		
		m_getChar()
		
		return( ret )
	else
		if( not m_isDelimiter( m_lookChar ) and m_charPos < m_stringLen ) then			
			do while( not m_isDelimiter( m_lookChar ) and m_lookChar <> "" )
				ret &= m_lookChar
				m_getChar()
			loop
			
			return( ret )
		end if
	end if
end function

sub lexer.m_getChar()
	'' if the char pos is still less than the input string length, read the next char
	if m_charPos < len( m_inputString ) then
		m_lookChar = chr( m_inputString[ m_charPos ] )
		
		m_charPos += 1
	else
		'' if not, this will signal the end of the string (as there are no more chars to read)
		m_lookChar = ""
	end if
end sub

function lexer.m_inString( byref srchString as string, byref strng as string ) as integer
	/'
		returns -1 if srchString is within strng
		
		note that this function and m_isDelimiter return numerical values because FB
		issues warnings if you return 'proper' boolean values
	'/
	if( inStr( strng, srchString ) > 0 ) then
		return( -1 )
	else
		return( 0 )
	end if
end function

function lexer.m_isDelimiter( byref c as string ) as integer
	'' returns true (any value but zero) if the string c is a delimiter
	return( m_inString( c, this.m_delimiters ) )
end function

This is the first phase of compiling code, also called 'lexical analyzer' or 'lexer'. What this class does is splice a string into small units of syntax (called 'lexemes' or 'tokens'), so you work with one token at a time during the parsing phase. Two very simple usage examples (the code assumes that you saved the previous code in the file 'lexer.bi')

Code: Select all

'' simple lexer example 1: basic usage of the lexer class
#include once "lexer.bi"

'' use white space as delimiters: space, LF, CR and tab
dim as string delimiters = chr( 32 ) & chr( 10 ) & chr( 13 ) & chr( 9 )
dim as string inputString = "This is a test"
dim as string token

'' as lexer is an immutable class, you have to instantiate it like this
dim as lexer lx = lexer( inputString, delimiters )

'' always get the first token before starting the loop
token = lx.getToken()

'' get all tokens (including delimiters)
do while( token <> "" )
	? token
	token = lx.getToken()
loop

sleep()

Code: Select all

'' simple lexer example 2: lexing a file
#include once "lexer.bi"

function isWhiteSpace( byref s as const string ) as boolean
	'' a simple helper function
	'' returns true if the string c is a whitespace char
	dim as string c = chr( 32 ) & chr( 10 ) & chr( 13 ) & chr( 9 )
	return( iif( inStr( c, s ) > 0, true, false ) )
end function

'' use white space as delimiters: space, LF, CR and tab
dim as string delimiters = chr( 32 ) & chr( 10 ) & chr( 13 ) & chr( 9 )
dim as string inputString = ""
dim as string token

'' open a file
dim as integer fh = freeFile()
dim as string fileName = "SmallWorld-all.svg" '' replace it for the plain-text file of your choice

if( open( fileName for input as fh ) = 0 ) then
	'' if the file was successfully opened, retrieve all tokens
	do while( not eof( fh ) )
		line input #fh, inputString
		
		'' as lexer is an immutable class, you have to instantiate it like this
		dim as lexer lx = lexer( inputString, delimiters )
		
		token = lx.getToken()
		
		'' get all tokens
		do while( token <> "" )
			'' print the token if it is not a delimiter (white space in this case)
			if( isWhiteSpace( token ) = false ) then
				? token
			end if
				
			token = lx.getToken()
		loop
	loop
end if

close( fh )

sleep()

As you can see, the first example just prints the tokens (including delimiters). The second one does the same thing, but loads the input string from a file and filters the delimiters when printing. It greatly simplifies the construction of the parser.
If you also plan to compile the code to bytecode, you will have to code a Virtual Machine. Here's one link that will help you:

https://compilers.iecc.com/crenshaw/tutorfinal.pdf

It is a very well known tutorial on compiler construction that will help you immensely. The code the author presents in the book is in Turbo Pascal 4.0, and the assembler code is for the 68000 (the old Macs), but the concepts and the rantings are invaluable.
As for the parser, the example that you mention before (the EVAL() solver by D. J. Peters) is what's called a Recursive Descent Parser. They are very easy to implement and understand, but be aware that you can't parse the entire syntax of FB with it. However, you can implement only a subset of the language and get by just fine.

Best of luck! Feel free to shout if you need assistance.
Paul
Last edited by paul doe on Oct 06, 2017 21:49, edited 2 times in total.
owen
Posts: 555
Joined: Apr 19, 2006 10:55
Location: Kissimmee, FL
Contact:

Re: fbcadcam-macro

Post by owen »

thank you very much for the info, i can use all the help i can get.
i understand what you are saying but haven't invested enough thought and time into the concept of writing the interpreter this way.
i purchased a book 3 weeks ago as is my intention of rewriting fbcadcam-macro this way in the near future.
Image

i do want to continue working on coding it the way i'm doing it now, at least till i finish adding the string variable and concatenation operator.
i am very close to completing this goal. in the process of adding the string variable over the last few weeks, i have discovered and corrected many mistakes that existed in my previous version of fbcadcam-macro (without strings). after i have completed this one last thing then i need to beta test the strings variable in fbcadcam. if all checks out, then i will give it go and rewrite fbcadcam-macro the way you suggest.

thank you fb community in advance for all your advise.
owen
Posts: 555
Joined: Apr 19, 2006 10:55
Location: Kissimmee, FL
Contact:

Re: fbcadcam-macro

Post by owen »

Strings with concatenation ( +, & ) should be working now.

http://fbcadcam.org/fbcadcam-macro/fbca ... ngs-10.bas
owen
Posts: 555
Joined: Apr 19, 2006 10:55
Location: Kissimmee, FL
Contact:

Re: fbcadcam-macro

Post by owen »

I added my latest modifications of fbcadcam-macro (with strings) to fbcadcam and did a few tests:
For example I ran the following script to plot text into fbcadcam drawing.

dim as integer i
for i = 1 to 26
text 10,i*20,5,10,chr(i+64)
next

In an effort to document fbcadcam-macro I have updated my User's Guide. Take a peek if you like but there is a lot of documentation pending. I will try to link to the fb wiki as much as possible.

from about half way down the page to the bottom of the page is a description or fbcadcam-macro's usage.
http://fbcadcam.com/fbcadcam_users_guide.html
Post Reply