I am attempting to define and call a subroutine:
autodefine "OFF"
DECLARE MAT()
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SUB MAT()
def x:float
RETURN
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OPENCONSOLE
MAT()
PRINT
PRINT "Press any key to close this program"
DO
UNTIL INKEY$ <> ""
CLOSECONSOLE
END
I get a compile error that says that MAT() is undefined.
???
In Creative BASIC there is no ENDSUB statement. So subroutines have to go at the end of the code, not the beginning.
autodefine "OFF"
DECLARE MAT()
OPENCONSOLE
MAT()
PRINT
PRINT "Press any key to close this program"
DO
UNTIL INKEY$ <> ""
CLOSECONSOLE
END
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SUB MAT()
def x:float
RETURN
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Of course you can do it though. You just have to direct the flow of execution around the subroutine:
autodefine "OFF"
DECLARE MAT()
goto start
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SUB MAT()
def x:float
RETURN
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
start:
OPENCONSOLE
MAT()
PRINT
PRINT "Press any key to close this program"
DO
UNTIL INKEY$ <> ""
CLOSECONSOLE
END
Paul.
Thanks, Paul.
Now for the next problem:
AUTODEFINE "OFF"
OPENCONSOLE
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TYPE MATRIX
DEF m_nr AS INT ' Number of rows.
DEF m_nc AS INT ' Number of columns.
DEF m_pa AS POINTER ' Pointer to MAT.
ENDTYPE
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DEF X AS MATRIX
PRINT
PRINT "Press any key to close this program"
DO
UNTIL INKEY$ <> ""
CLOSECONSOLE
END
I get a syntax error on line 12:
"DEF X AS MATRIX"
Also, can I also put the TYPE definition in a component?
Creative isn't as tolerant to comments on the same line as statements as Emergence is. Just put a colon before the comments in the type definition.
And yes you can put it in a component.
Semicolon also work as coment but in new line...
AUTODEFINE "OFF"
OPENCONSOLE
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TYPE MATRIX
DEF m_nr AS INT :' Number of rows.
; number of rows
DEF m_nc AS INT :' Number of columns.
DEF m_pa AS POINTER :' Pointer to MAT.
ENDTYPE
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DEF X AS MATRIX
PRINT
PRINT "Press any key to close this program"
DO
UNTIL INKEY$ <> ""
CLOSECONSOLE
END
Can anybody tell me:
Just how much expression can be put in a sub call argument?
I'm getting various objections to the code below,
and it's frustrating not knowing the rules.
I remember Paul mentioning no nested brackets,
presumably meaning no "[]" or "()" in an argument expression,
but that doesn't look like the issue here.
It seems to be accepting boolean operator "<" but rejecting boolean operator "=".
I wouldn't mind using "==" at odd times to get around it.
rem - from clock.cba
rem - replacing loading IF's w. sub "forbid" (like "assert")
AUTODEFINE "OFF"
DECLARE forbid( cond : int , warn$ : string )
def dx, bkimg : int
def msg$ : string
rem - this worked OK; I think its compact, tidy, readable.
msg$= "Could not create DirectX screen"
dx = CREATESCREEN( w1 , 800 , 600 ) : forbid(dx<0 , msg$)
rem - Problem: this cant be made to work:
msg$= "Cant load background image"
bkimg = DXNEWMAP(w1, GETSTARTPATH + "back.jpg" , 800 , 600 , 1 )
rem - DXNEWMAP() - quikref:"Returns 0 on failure"
'forbid( bkimg=0 , msg$) : ' box: "Variable Wrong Type"
forbid( (bkimg=0) , msg$) : ' box: "Cant load background image"
'forbid( (bkimg<>1) , msg$) : ' OK! clock runs... but I_m not supposed to know "1"
rem - if all forbids are commented out, image loads & displays & clock runs normally.
DXCREATEMAP w1, 1, 1, 0
DXDRAWMAP w1
run = 1 : WAITUNTIL run = 0
LABEL finis
CLOSEWINDOW w1 : CLOSECONSOLE
END
' ====================================================================
mainwindow:
SELECT @CLASS
CASE @IDDXUPDATE : GOSUB update
CASE @IDCLOSEWINDOW : run = 0
ENDSELECT
RETURN
' ====================================================================
SUB update : ' stuff
RETURN
' ====================================================================
SUB forbid( cond : int , warn$ : string )
if ( cond )
MESSAGEBOX w1, warn$ , "Error"
goto finis
ENDIF
RETURN
I'm using CreativeBasic v1.01 in XP-sp2. Had a lot of fun so far.
I would also like to point out that in a trailing comment
(that is, it's not the first statement on the line),
using a tick in one's diatribe can activate the whole comment,
resulting in attempted execution and errors.
Paste this code in your cba window,
and it should take on multiple colors: green, black, and blue.
a=3 : ' It's not safe to ... (black, w. blue "not" and "to")
: ' It's not safe to ... (black, w. blue "not" and "to")
' It's not safe to ... (green)
: ' It_s not safe to ... (green)
: ' It's not_ safe to_ ... (all black)
Wish it weren't so. I use trailing comments a lot.
crystal...
First of all , you mix all things together.
You open at same time console,window and dxscreen - of course that's not work
Second you also want close console and window together - not work
You also declare function forbid wich is directly executed on start ?- not work
And of course code wich is on picture is written in wrong way.
You cant use colon before comment in new line.
Aurel-
beg to differ on most counts.
- You can use a colon before a comment in a new line, at least in Creative Basic.
I've been doing it all day. It basically creates a harmless empty statement.
True it isn't usually useful, but here it helps detail the interpreter's behavior.
- Don't know what you see so wrong in the picture. (2nd_tick_cases.png)
Mostly it's just white-space and comment statements.
My belief is it should be hard to mess anything up using those two things.
- sub forbid was not executed directly on start, it was declared at the start,
then executed after trying to create a DirectX screen,
which apparently could fail, judging from this warning-box:
IF CREATESCREEN(w1,800,600) < 0
MESSAGEBOX w1, "Could not create DirectX screen","Error"
CLOSEWINDOW w1
END
ENDIF
in Graham's example program. Graham's program is now attached below...
- I opened the unneeded console window to let me print out variables for my debugging.
Both console and DX-window worked side-by side, just fine. I recommend it.
I even got them to both vanish at the same instant whenever the DX-window's closebox is clicked.
It quits nice and fast that way. The console-window's closebox does nothing, but no big deal.
- It seems the DX screen shows in the main-window's pane, in Creative-Basic. They're the same window.
Maybe EB or other basics differ, I haven't yet seen them enough to know.
- yes I tend to mix things together when they don't affect each other.
I think a trailing comment is sometimes the clearest place to record execution outcomes
of a long list of alternative statements.
Go ahead and delete those comments...it doesn't seem to affect the behavior in those cases.
I guess I was hoping to hear that a version 1.02 might happen someday with those two issues looked at.
I'm studying my Aurora and EB now, but I really wanted to go further with the easy 3D I was getting in CB.
First of all i try Graham example before 2 year and i must say that is exccelent :)
I think that you are to fast.
So try this:
'try this
'AUTODEFINE "OFF"
'DECLARE forbid( cond : int , warn$ : string )
DEF w1:WINDOW
def dx, bkimg : int
def msg$,msg2$: string
def run:int
rem - this is right aproach
WINDOW w1,0,0,800,600,@NOAUTODRAW,0,"Creative Basic Clock",main
msg$= "Could not create DirectX screen"
' check screen size
IF CREATESCREEN(w1,800,600) < 0
MESSAGEBOX w1,msg$,"Error"
Goto finish
ENDIF
msg2$= "Cant load background image"
'bkimg = DXNEWMAP(w1, GETSTARTPATH + "back.jpg" , 800 , 600 , 1 )
'check newmap
IF DXNEWMAP(w1,GETSTARTPATH + "Back.jpg",800,600,1) = 0
MESSAGEBOX w1,msg$,"Error"
Goto finish
ENDIF
'create a blank map filled with tile#0
DXCREATEMAP w1,1,1,0
DXDRAWMAP w1
run = 1
WAITUNTIL run = 0
CLOSEWINDOW w1
END
' ====================================================================
SUB main
SELECT @CLASS
CASE @IDDXUPDATE
Gosub dxupdate
CASE @IDCLOSEWINDOW
run = 0
ENDSELECT
RETURN
'SUB forbid( cond : int , warn$ : string )
'// cond is not changed // - so this not work
'if ( cond )
' MESSAGEBOX w1, warn$ , "Error"
' goto finis
'ENDIF
'RETURN
SUB dxupdate
DXDRAWMAP w1
'show the changes
DXFLIP w1
RETURN
finish:
Closewindow w1
END
Hello Cristal,
I noticed also the strange behaviour of the remark accent when it's not in the beginning of a line, to avoid this I like to use "rem" instead, that works just fine.
Change your example to this, then the colloring is OK...
a=3 : rem It's not safe to ... (black, w. blue "not" and "to")
: rem It's not safe to ... (black, w. blue "not" and "to")
' It's not safe to ... (green)
: rem It_s not safe to ... (green)
: rem It's not_ safe to_ ... (all black)
The use of "=",">=","<=" (in particular the equal sign) seems to be impossible inside a SUB call, but "<", ">" and "<>" do work fine.
It is easy to overcome this by inverting the comparision like this:
... X = Y ... becomes ...(X <> Y) - 1 ...
... X <= Y ... becomes ...(X > Y) - 1 ...
... X >= Y ... becomes ...(X < Y) - 1 ...
(The "- 1" after the compare part inverts true to false and false to true, thus inverting the comparisions results)
In your program...
forbid( bkimg = 0 , msg$) : ' box: "Cant load background image"
Becomes then...
forbid( (bkimg <> 0) - 1 , msg$) : ' box: "Cant load background image"
Don't shoot me! I'm only trying to offer a work around... ;)
Greetings to all,
Johnny
From user guide:
DXNEWMAP window, bitmapfile, width, height, tiles
there is no like:
bkimg=DXNEWMAP window, bitmapfile, width, height, tiles
Only this function work similiar:
tile = DXGETMAPTILE (window,x,y)
In this case work:
bkimg=0
IF DXNEWMAP(w1,GETSTARTPATH + "Back.jpg",800,600,1) = bkimg
MESSAGEBOX w1,msg$,"Error"
Goto finish
ENDIF
Aurel, Johnny, thanks for your replies.
I think I can use what Johnny suggested:
forbid( (bkimg<>0)-1 , msg$ )
" : REM " I like less because it fills the almost-white space I usually have, " : ' ",
in between my dense wordy code and my dense wordy comment.
And because I'm often running out of line-length.
Aurel, my reason for inventing the subroutine is: I just don't want to use those 4-line IF-ENDIF blocks.
They fill the page with housekeeping, pushing the main program sequence,
which I'm trying to see clearly and think about, off the top or bottom of the page.
And that IF block is used repeatedly in this program and others.
Right now I really want my programs to say everything only once,
and I see modern Basic getting pretty close to allowing me to reach that goal.
I admit, if I ever have occasion to really work with other programmers,
I might need to use your more-conventional style.
About all that DXNEWMAP stuff -
I understand there are usually two forms of a subroutine call:
the "statement" or "command" form:
thissub a, b, c
which does not return a value,
and the "function" form:
d = thissub( a, b, c )
which returns a value.
I've noticed that it's becoming common in interpretive languages to allow the use of either form
for any subroutine name that exists and returns a value.
If a function is used in the command form, it's return value is simply not used by the program.
The userguide quickref page shows DXNEWMAP in command form,
but then finishes with "Returns 0 on failure",
so I infer that the function form DXNEWMAP(...) must also work.
You gave me an idea of trying
0=bkimg
instead of
bkimg=0
the idea being that maybe the impossibility of assigning a new value to literal 0
might make the interpreter see "=" as the boolean operator, not the assignment command.
I might play around with stuff like that.
Thanks again, guys.
Hi again...
I'm not expert for declared subrutines(called functions).
And i dont use them very much in my programs ( read - 'i dont like them').
But i spend some time reading user guide and make one small example.
Little changes, i also add work with pointer .
I hope that is good.
Zlatko
DECLARE DrawMessage(w:WINDOW,msg$:STRING,x2:INT,y2:INT)
DECLARE DoCircle(x:INT,y:INT,size:INT)
DEF win:WINDOW
DEF cond:int
DEF run:int
DEF msg:pointer
Window win,0,0,400,400,@SIZE|@MINBOX|@MAXBOX|@CAPTION,0,"SUB Demo",mainwindow
Setwindowcolor win,rgb(200,200,230)
Docircle (100,100,25)
IF cond=1
DrawMessage(win,"Circle",100,150)
Endif
'read and show pointer in message box
MessageBox win,#msg,"Message with Pointer"
'-----------------------------------
run = 1
waituntil run = 0
closewindow win
end
'-------------------------------
mainwindow:
select @class
case @idclosewindow
run=0
endselect
return
'-----------------------------------------
REM window & string variable passed by reference
SUB DrawMessage(w:window,msg$:STRING,x2:INT,y2:INT)
move w,x2,y2
print w,msg$
'show string "Circle" in messagebox
IF cond=1 then MessageBox w,"IF cond = "+str$(cond)+"; "+ msg$,"Condition"
msg$="msg Pointer"
'set pointer to string msg$
msg=msg$
RETURN
'-----------------------------------------
'passed by value
SUB docircle(x,y,size)
CIRCLE win,x,y,size
cond=1
RETURN cond
Zlatko, is it? My name is Jim.
I ran your example.
Nice to know what pointers look like.
and to see how to print right inside the graphic window.
Guess what, if you delete the last word of your program: "cond",
it also works; it does exactly the same thing!
The line
RETURN cond
tries to send the value of cond (previously set to 1)
back to the main program.
The place this value goes to is right where the sub was called:
Docircle (100,100,25)
But there is no "=" there to catch the return value and put it into a variable,
such as:
DEF resultcode: int
...
resultcode= Docircle (100,100,25)
With no "=" present, the return value is simply ignored and forgotten.
That's OK, you didn't want to do anything with it then.
If nobody in the main program is using the value,
perhaps there is no need to send it.
That's why it's OK to delete the "cond" after "RETURN".
Creative Basic is quite tolerant of that kind of thing.
It allows you 3 ways to say docircle:
Docircle 100,100,25 : ' draws a circle
Docircle (100,100,25) : ' draws a circle
ItWorked = Docircle (100,100,25) : ' draws a circle and sets ItWorked to 1.
They all work OK, and do what the programmer probably meant to do.
Notice that "cond" and "win" are defined
in the main program, and not defined in the subroutine docircle.
So when docircle executes
cond=1
it finds the variable that was defined far above
and sets it to 1.
Then cond=1 for all the main program,
and there is no need to send it to the main program by using RETURN.
When would one need to use "RETURN xxx" ?
When there is an "=" in the place that called the subroutine, _and_:
a) variable xxx was DEF'd inside the subroutine, or
b) the sub is executed a bunch of times, and returns a different value each time,
and you want to make sure your main program doesn't use a stale old value
c) the return value is put in different variables by "=" on different times:
a1= docircle(50,50,20)
...
a2= docircle(70,70,30)
d) you want to make it obvious in your code that the value came from that subroutine.
If you say
docircle(...)
if cond=1 then ...
it can take much looking around to make sure that only docircle changed cond.
If, on the other hand, you say:
cond=docircle(...)
if cond=1 then ...
...
sub cond(...)
return 1
then you get to feel sure that cond came from docircle when IF uses it.
I talk too much. I better go to bed...
Jim
I see I have negative karma. :-[ ??? I know I'm not entirely tactful,
but if there's something specific, a message might help me out.
Jim
You want karma, you got karma! :D
Yes Jim you right i just forget delete cond after RETURN. ::)
And of course variable cond is global .
Thanks, Mike! That answers my question. :)
Zlatko, I never can tell exactly how much you know.
Sometime I'll look closer at your website.
No problem,Jim... :)
Just look at the website ;)
And i allways forget something(my old problem ::))
Just like to share another bug & workaround.
Sometimes when I'm programming I suddenly get to a point where further progress is blocked by unreasonable error messages that I can't figure out how to eliminate. I think I've found a helpful clue. Sometimes the error refers to a name in a subroutine, but it's really caused by a different error _after_ the subroutine returns.
In this example a "variable not found" message refers to inkey$ ??? in my subroutine "waitkey",
but the real error is an unbalanced quote a line or two after the "gosub waitkey" statement.
I provided alternative lines to enable or disable using comment-ticks (').
Using them you can add the missing close-quote and see the error message go away,
or disable the gosub and use a non-subroutine line with inkey$ instead,
in which case the error message refers correctly to the missing close-quote.
Anyway, if you have an error message that's just crazy, look around for other errors nearby.
rem Bug demo "inkey not found"
rem to show how an unrepresentative error message,
rem [variable not found], referring to a known keyword
rem in a subroutine, can be elicited by a real syntax error
rem in the program flow after the sub's return
rem CreativeBasic v1.01
rem Jim Swenson 2009-02
autodefine "OFF"
def fmt$ : string
def vwXspan : float : vwXspan = 4
OPENCONSOLE
gosub waitkey
'print "Press a key ###" : do : until ( inkey$ <> "" )
rem if "gosub waitkey" line above is replaced with
rem the "do:until" line, then a correct error message
rem refers to line 22 [fmt$=" ] below
rem intervening statement:
vwXspan = 5
'fmt$ = "" : rem with this line, program runs as expected
fmt$ = " : rem <-- the real error in main program.
rem At first gosub waitkey, an improper error-
rem message: "line 41: variable 'inkey$' not found"
print "view_span= ", vwXspan, " meters"
gosub waitkey
print "All done, quitting when you:"
gosub waitkey
Label finish
closeconsole
end
sub waitkey
print : print "Press any key to continue..."
do
until ( inkey$ <> "" )
print
return