BBC BASIC for Windows
« Variable names from strings »

Welcome Guest. Please Login or Register.
Apr 5th, 2018, 11:53pm



ATTENTION MEMBERS: Conforums will be closing it doors and discontinuing its service on April 15, 2018.
Ad-Free has been deactivated. Outstanding Ad-Free credits will be reimbursed to respective payment methods.

If you require a dump of the post on your message board, please come to the support board and request it.


Thank you Conforums members.

BBC BASIC for Windows Resources
Online BBC BASIC for Windows documentation
BBC BASIC for Windows Beginners' Tutorial
BBC BASIC Home Page
BBC BASIC on Rosetta Code
BBC BASIC discussion group
BBC BASIC for Windows Programmers' Reference

« Previous Topic | Next Topic »
Pages: 1  Notify Send Topic Print
 thread  Author  Topic: Variable names from strings  (Read 549 times)
Matt
Developer

member is offline

Avatar




PM

Gender: Male
Posts: 210
xx Variable names from strings
« Thread started on: Sep 21st, 2010, 7:32pm »

Hi,

Is there a way of using the result from an input to a string to gain access to another - say in a structure.

I'll try to explain that a little better with an example.

Code:
DIM objpos{x,y,z}
objpos.x = 1
objpos.y = 2
objpos.z = 3
...
required_output_from$="y"
...
result%=objpos.[required_output_from$]
REM square brackets to emphasize string 


The reason for this would be to be able to gather information from a DB which might include a sub heading such as:

Age="32"

Code:
...
INPUT#fn%,line$
REM split line into header$ and age$
...
data.[header$]=age$
... 


If this could be done, it would solve a few of my problems.

Matt
User IP Logged

JonR
New Member
Image


member is offline

Avatar




PM


Posts: 24
xx Re: Variable names from strings
« Reply #1 on: Sep 21st, 2010, 8:38pm »

You could use the EVAL function which takes a string containng a variabler name or an expression, evaluates it and returns the answer. I've taken the liberty of changing the variable result% into the same type as the items inside the objpos structure.

Code:
      result = EVAL("objpos."+required_output_from$) 


However this method is not recommended as it has complications. For instance you need to check that required_output_from$ contains a sensible value to avoid a no such variable error and allow you to deal with unexpected input. You also need to use a REM !Keep compiler directive to ensure that the variable names relating to the structure are kept intact when the program is crunched if you want to use the abbreviate names option. This gives you the rather following unweildy and hard to main code:

Code:
      REM!Keep objpos,x,y,z
      ...
      IF required_output_from$ = "x" OR required_output_from$ = "y" OR required_output_from$ = "z" THEN
        result = EVAL("objpos."+required_output_from$)
      ELSE
        REM handle unexpected error
      ENDIF
 


There's more in the Wiki article preventing structure member names being crunched. If you extend your structure to contain more members the code would become difficult to maintain very quickly.

A solution with none of the above complications is to check the value of required_output_from$ and return the appropriate structure member. You can use a CASE structure as follows:

Code:
      CASE required_output_from$ OF
        WHEN "x"
          result = objpos.x
        WHEN "y"
          result = objpos.y
        WHEN "z"
          result = objpos.z
        OTHERWISE
          REM handle unexpected input
      ENDCASE
 


This is a lot easier to maintain. You could even use this to create a pair of routines to get and set the fields:

Code:
      DEF FN_getResult(objpos{}, field$)
      LOCAL result
      CASE field$ OF
        WHEN "x"
          result = objpos.x
        WHEN "y"
          result = objpos.y
        WHEN "z"
          result = objpos.z
        OTHERWISE
          REM handle unexpected input
      ENDCASE
      = result
      
      
      DEF PROC_setResult(objpos{}, field$, number)
      CASE field$ OF
        WHEN "x"
          objpos.x = number
        WHEN "y"
          objpos.y = number
        WHEN "z"
          objpos.z = number
        OTHERWISE
          REM handle unexpected input
      ENDCASE
      ENDPROC
 


I tend to deal with structures as opaque objects that I create and interact with indrectly by creating a set of routines that I pass the structure to that manipulate it in various ways instead of accessing the memebrs of the structure directly. I find that taking an object oriented approach allows me to create cleaner self contained code. The above might be extended as follows:

Code:
      DIM OBJPOS{x,y,x}
      REM...
      DEF PROC_create(objpos{})
      DIM objpos{} = OBJPOS{}
      ENDPROC
      
      DEF FN_getX(objpos{})
      = objpos.x
      
      DEF PROC_setX(objpos{}, number)
      objpos.x = number{}
      ENDPROC
      
      DEF FN_getY(objpos{})
      = objpos.y
      
      DEF PROC_setY(objpos{}, number)
      objpos.x = number{}
      ENDPROC
      
      DEF FN_getZ(objpos{})
      = objpos.z
      
      DEF PROC_setZ(objpos{}, number)
      objpos.z = number{}
      ENDPROC
      
      DEF FN_getResult(objpos{}, field$)
      LOCAL result
      CASE field$ OF
        WHEN "x"
          result = FN_getX(objpos{})
        WHEN "y"
          result = FN_getY(objpos{})
        WHEN "z"
          result = FN_getZ(objpos{})
        OTHERWISE
          REM handle unexpected input
      ENDCASE
      = result
      
      DEF PROC_setResult(objpos{}, field$, number)
      CASE field$ OF
        WHEN "x"
          PROC_setX(objpos{})
        WHEN "y"
          PROC_setY(objpos{})
        WHEN "z"
          PROC_setZ(objpos{})
        OTHERWISE
          REM handle unexpected input
      ENDCASE
 

« Last Edit: Sep 21st, 2010, 8:56pm by JonR » User IP Logged

admin
Administrator
ImageImageImageImageImage


member is offline

Avatar




PM


Posts: 1145
xx Re: Variable names from strings
« Reply #2 on: Sep 21st, 2010, 9:26pm »

on Sep 21st, 2010, 8:38pm, JonR wrote:
However this method is not recommended as it has complications. For instance you need to check that required_output_from$ contains a sensible value to avoid a no such variable error and allow you to deal with unexpected input.

Although not generally to be recommended, this is one occasion when allowing the error to occur, and trapping it, might be the most straightforward solution:

Code:
      DEF FNresult(rof$)
      ON ERROR LOCAL = -1
      = EVAL("objpos."+rof$) 

This will return the value of the member whose name is passed to the function (e.g. "x" or "y") or -1 if an error occurs, such as the supplied name not being one of the structure's members.

Nevertheless, I agree that it's probably better to avoid using EVAL this way.

Richard.
User IP Logged

Matt
Developer

member is offline

Avatar




PM

Gender: Male
Posts: 210
xx Re: Variable names from strings
« Reply #3 on: Sep 22nd, 2010, 05:50am »

Thanks Guys,

I'll have to investigate the EVAL for this further as the structure may contain hundreds of members. Producing a CASE for all of them would be very time consuming and possibly erroneous in itself.

Matt
User IP Logged

JonR
New Member
Image


member is offline

Avatar




PM


Posts: 24
xx Re: Variable names from strings
« Reply #4 on: Sep 22nd, 2010, 07:18am »

The CASE is an easily automatable task ideal for doing programattically. You already have a list of all the names of the structure members so it should be simple to write a code generator to write the CASE for you:

Code:
      eol$=CHR$13+CHR$10
      DIM array$(...)
      REM initialise contents with list of items
      text$="CASE required_output_from$ OF"+eol$
      FOR i%=0 TO DIM(array$(),1)
        text$+="WHEN """+array$(i%)+""""+eol$
        text$+="result = objpos."+array$(i%)+eol$
      NEXT i%
      text$+="OTHERWISE"+eol$
      text$+="REM handle unexpected input"+eol$
      text$+="ENDCASE"
      
      REM set clipboard text
      SYS "GlobalAlloc", &2000, LEN(text$)+1 TO hdata%
      SYS "GlobalLock", hdata% TO tmp%
      $$tmp% = text$
      SYS "GlobalUnlock", hdata%
      SYS "OpenClipboard", @hwnd%
      SYS "EmptyClipboard"
      SYS "SetClipboardData", 1, hdata%
      SYS "CloseClipboard"
 

« Last Edit: Sep 22nd, 2010, 07:20am by JonR » User IP Logged

Pages: 1  Notify Send Topic Print
« Previous Topic | Next Topic »

| |

This forum powered for FREE by Conforums ©
Terms of Service | Privacy Policy | Conforums Support | Parental Controls