r3wp [groups: 83 posts: 189283]
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

World: r3wp

[I'm new] Ask any question, and a helpful person will try to answer.

Pekr
19-Apr-2009
[1779]
Steeve - why a waste? REBOL's parse allows even lamers like me to 
produce the result, which in the end does what I want it to do, but 
you surely would not like to see my parse rules :-) I can't write 
single piece of regexp, yet REBOL's parse is usefull to me.
Henrik
19-Apr-2009
[1780x2]
it would be interesting if the config file could be loaded, by making 
unloadable parts like $FW_OUTSIDE$ loadable using simple string replacable. 
Then you could just 'load the file into a block and it would be considerably 
easier to parse.
string replacable = string replacement
Steeve
19-Apr-2009
[1782]
Pekr, I'm just disapointed by what mhinson produced after getting 
so many advices from Rebolers like you.

The read/line trick is very useless, why doesn't he use the standard 
way of traversing newlines with parse ? 
And why using code (inside parents) to manage optional rules.

Are commands like SOME, ANY, OPT not enough to manage simple rules 
like that ?
Henrik
19-Apr-2009
[1783]
I'm just admiring that mhinson wasn't scared of jumping into PARSE 
so soon. :-)
mhinson
19-Apr-2009
[1784]
Thanks for the feed back, all is most welcome. I will try to avoid 
read/line if it is bad, is there a list of things I can't expect 
to load?  Should I convert them to some symbolic value & then convert 
them back again for the final output?

I don't yet understand why a block would be easier to parse than 
lines, by easier do you mean more efficient or easier to create the 
code?

The optional rules (inside parents) are to change the behavior based 
on lines read previously so I don't yet understand any concept that 
would let me avoid those. 

I need the code to be very simple (like me) so I can understand how 
it is operating. I know my implementation goes against the Rebol 
ethos of  small & efficient but perhaps in time I can understand 
enough to make it so & also start using relative expressions properly 
so it can be simple to understand.
Henrik
19-Apr-2009
[1785]
I don't yet understand why a block would be easier to parse than 
lines, by easier do you mean more efficient or easier to create the 
code?


Yes, it's easier, because REBOL is based around this concept. Without 
this concept, dialects wouldn't make much sense. Your configuration 
file shown above is a good candidate for a dialect with some tweaks.


I suggest, you read again what I wrote above about the basics of 
words, context and meaning. I can't emphasize enough how important 
this is to REBOL and especially for block parsing. It's important 
to understand this before moving on, or REBOL will remain difficult 
to use for you. Or drop your parse project for now and stick with 
the basics until you understand more of REBOL.

is there a list of things I can't expect to load?


The LOAD function will error out, if a string (such as a file you 
read) can't be loaded into a block of data. 

Try these in the console, and see which ones work:

load "hello"

load "hello,"

load "hello."

load "%"

load "1 2 3 4"


load "hostname pig interface Null0 ! interface Loopback58 description 
SLA changed this"

load %/c/temp/cisco.txt
sqlab
19-Apr-2009
[1786x2]
I am against loading this configuation files. Why?
-you can not control what is inside 
we know already, that there are elements unloadable by Rebol
and the description almost always needs string parsing 

What would I change?

I would either use only one temp variable in the parse rule and after 
just set to the new variable, as there is already a copy involved 
 or I would use a meaningfull variable name in the first place
Another reason against loading
- we can not determine, if "interface" is at the start of a line
mhinson
19-Apr-2009
[1788]
Good point about my temp1 temp2 etc. that was sloppy.

It is true I cannot control what is inside the config files. They 
can contain any printable chars (eg in encrypted password fields 
or remarks/descriptions or embedded TCL code) and sometimes I am 
going to want to capture that text. 

I don't mind trying to do both methods as it will help me learn. 
Since I can't load the file directly I am thinking I will need to 
do a read %file.txt & replace the /\,[]%$()@:? with %xx etc.  then 
load the result?   I cant find a list of all the chars that I would 
need to treat like this yet.

Henrik, I do continue to read what you have written, it is helpful 
& I think I am beginning to appreciate the concepts. I am probably 
not as clear as I should be about the specification of what I am 
trying to do so the code has tended towards listing the requirements 
rather than being elegant.  Thanks /\/\
sqlab
19-Apr-2009
[1789]
further enhancements
I would try to extract the rule parts into single rule e.g.
interfacerule: [--]
descriptionrule: [--]
etc. (names are debatable.)


better than [copy ..   [" ip address" to end]] is probably  [to "ip 
address" copy temp to end], 
unless you know, that there is always one space
Sunanda
19-Apr-2009
[1790]
'read/lines is not bad.
It enables you to easily split the problem inyto smaller phases.
It makes it harder to solve the problem in one huge 'parse.

But maybe one big 'parse is not the best approach -- especially if 
you need (say)backtracking for error recovery, or line-numbers of 
points of failure.


You are getting several people's views on how to tackle your problem 
here. Take their advice seriously, but remember you are the domain 
specialist, so you get to choose which solution fits best. Not us 
:-)
mhinson
19-Apr-2009
[1791]
ok. I follow your extraction of rules idea & this is what you had 
in your original suggestion.  Now I am getting more familiar with 
what I am looking at I can understand the benefit of that & will 
start to work that way now.

[copy .. [" ip address" to end]]  was to get the interface address 
in the interface section of the file. It is identified by
1) some line after the line containing "interface"

2) at the begining of the line always starting with one space before 
the word "ip address"

3) before any line with a non-blank first char unless it is a new 
instance of "interface" (hence my IntFlag which Steeve didn't like 
my method of use)


I found from testing that [to "ip address" copy temp to end] or [to 
" ip address" copy temp to end] found the string anywhere in the 
line, but [copy .. [" ip address" to end]] only finds the string 
if it is at the start of the line which is what I was trying to achieve. 
Have I made a mistake here & need to retest my assumptions perhaps?


I always appreciate lots of different views on issues so I am loving 
the multiple responses. 

Sunanda you have reminded me about line numbers. I will tackle them 
after the extraction of rules I think, as I want them in my output 
for data output quality & validation checking.


I have been looking at your parse-ini.r to see how you have read 
a file into a Rebol block, but I may stick with read/line for a bit 
longer while get my head round parsing each line in turn.  I get 
the impression that once I have a final block of code there will 
be someone who can turn it into 2 short lines including a built in 
Easter egg game.
sqlab
19-Apr-2009
[1792]
No, you are right. 

If there is always one leading space after newline identifying a 
valid ip address, your approach  is the best. I just don't know anything 
about the stringent syntax rules of your config files, hence my suggestion.
mhinson
19-Apr-2009
[1793x2]
Thanks.  These files are getting better with more recent versions 
of Cisco IOS but sometimes trial and error is the only way to find 
the formats used.
I am still new and confused.   where can I read about how to do this 
please?
file: "%file.txt"
host: "Router1"
interface: "fa0"
i: 25
description: []
ipaddr: "1.1.1.1 255.255.255.0"


write/append/string %/c/temp/result.log [file tab i tab host tab 
interface tab description tab  ipaddr newline]


I want the output file to be a tab-seperated set of values but all 
I get is the text 
filetabitabhosttabinterfacetabdescriptiontabipaddrnewline
Oldes
19-Apr-2009
[1795x3]
write/append/string %/c/temp/result.log rejoin [file tab i tab host 
tab interface tab description tab  ipaddr newline]
andor just simple  REDUCE instead of REJOIN should be enough in this 
case
Also you must use MOLD for the values, if you want to keep the type 
(for example the block as the description)
mhinson
19-Apr-2009
[1798x2]
Thanks very much I have seen reduce & rejoin & mold but didnt realise 
it was relevant to writing a file.. this is the first time I have 
ever written to a file.
I have tried to understand & take on what I have been told, thanks. 
Is this worse or better. It does what I was looking to do & I know 
how to extend it in the same structure.  I am sure it would be educational 
for me if anyone has time to tear it to shreds please.


Should I stop using read/line now?  Would I get the benefit still? 
Or is the requirement too fragmented for this approach now?
Should I use functions anywhere instead?
Have I initialised my variables in the right & appropriate way?

filename: copy %/c/temp/cisco.txt   ;; cisco config file
outFile: copy %/c/temp/outFile.log  ;; tab separated output
hostname: copy []
interface: copy []
intDesc: copy []
intIpaddr: []
ipRoute: []
IntFlag: false
spacer: charset " ^/"
name-char: complement spacer

lines: read/lines filename


outInterface: [ write/append outFile reduce 

 [filename tab i tab hostname tab interface tab intDesc tab intIpaddr 
 newline]
]

clearInterface: [
	interface: copy []
	intDesc: copy []
	intIpaddr: []
]


interfaceRule: [ ["interface " copy temp-interface to end] (   ;; 
captures point-point as well

  if IntFlag outInterface           ;; start of new interface section 
  so output data collected previously.
		if IntFlag clearInterface        
		interface: copy temp-interface
		print ["! found at line " i]      ;; debug
		print current-line                ;; debug
		IntFlag: true
	)
]

descRule: [ [" description " copy intDesc to end] (  
		if IntFlag [print current-line]     ;; debug
	)
]
	
ipAddrRule: [[" ip address " copy intIpaddr to end] ( 
		print current-line                  ;; debug
	)
]

hostnameRule: [["hostname " copy hostname to end] ( ;; "hostname"
		print current-line                  ;; debug
	)
]

iprouteRule: [copy iproute ["ip route" to end] ( ;; "ip route"
		print current-line                  ;; debug
	)
]



IntFlagRule: [copy tempZZ [name-char to end] ( ;; not space or newline. 
this must be out of the int section

  if IntFlag outInterface      ;; end of interface section so output 
  data collected.
		if IntFlag clearInterface
		if IntFlag [print "!"]       ;; debug
		IntFlag: false               ;; 
	)
]

i: 0


foreach line lines [i: i + 1 ;; move through lines & track line number
	current-line: line       ;; for debug output
	parse/all line [         ;; parse only using rules below

  interfaceRule        ;; evaluated if "interface" found preceeded 
  by nothing else

  | descRule           ;; evaluate if " desc" found preceeded by nothing 
  else
		| ipAddrRule         ;; " ip address"
		| hostnameRule       ;; " hostname"
		| iprouteRule        ;; "ip route"

  | IntFlagRule        ;; unset interface flag if no longer in interface 
  section (no " ^/")
	] 
]
Graham
19-Apr-2009
[1800x7]
filename: copy %/c/temp/cisco.txt   ;; cisco config file
outFile: copy %/c/temp/outFile.log  ;; tab separated output
don't need 'copy there
what's this?
outInterface: [ write/append outFile reduce 

 [filename tab i tab hostname tab interface tab intDesc tab intIpaddr 
 newline]
]
should that be a function and not just a block?
same with clearinterface
which needs a 'copy on the last  [ ]
Steeve
19-Apr-2009
[1807]
What the need of flags and splitted lines, uh ?
you can't write simple semantic ?
Reading, your example file , you've got these simple rules.

1/ counting the lines
line: [ thru newline (n: n + 1)]


2/ one interface mays contain several lines (infos) and is terminated 
by a line beginning by "!"  
interface: [
	"interface" copy interface* line 
	any [infos | #"!" line break]
]

3/ infos may be description, ip-adrr, ip-tables
infos: [
	  " description " copy desc* line 
	| " ip route " copy route* line
	| "ip address" copy ip-add* line 
]

That''s all folks, just parse the whole file with:
parse/all [any [interface | line]]


Please don't use read/lines or internal flags for such simple rules.
BrianH
20-Apr-2009
[1808]
The problem with that method is managing backtracking. If your lines 
are really separate, you will have to be careful in writing your 
rules to make sure that you don't inadvertantly backtrack to a previous 
line when you don't want to.
Steeve
20-Apr-2009
[1809x2]
No, Backtracking is a wonderfull feature, it's not a problem.

People who get unwanted backtracking, just don't know how to use 
parse correctly.
but imho, it's easy to learn.
BrianH
20-Apr-2009
[1811x2]
Hello, welcome to the "I'm new" group. Let's assume that someone 
who is asking questions about parse here doesn't know parse :)
I find it pretty easy to manage backtracking too, but I used to use 
Icon before REBOL. Most people without a background in backtracking 
parsers or languages tend to have a bit of trouble with backtracking.
mhinson
20-Apr-2009
[1813x2]
Thanks for pointing out the errors.


The lines I want to group together are not all together in the file. 
But for the interface details they are.

IP routes are grouped together under a vrf & the interfaces will 
relate to a particular vrf.

The end of a section might be a "!" or might just be the beginning 
of the next section, or any non space or anything  that does not 
match a pattern.. It depends on the particular section.


I will try to reduce the number of rules I need and get a very clear 
view of what I am trying to achieve. I don't find the semantics of 
this very easy to grasp and I am still struggling to find any documentation 
that makes sense to me.


Sorry to be asking so many questions but I not done any programming 
to speak of since Pascal the mid 1980s so I am sort of like a complete 
idiot as you see.  Thanks for taking the time to suggest how much 
improvement is possible.
another very basic question.
how can I pass a filename from the command line please?


filename: %/c/temp/file.txt works fine, but if I pass the filename 
from the command line it get surrounded by ""

do I have to parse the result to get the filename, or is there a 
simpler way for something so common?
The only reference I could find was here
http://www.rebol.com/docs/sdk/custom.html#section-3


It seems there is a great deal of Rebol documentation, but simple 
questions can be had to find answers to.
BrianH
20-Apr-2009
[1815]
Try passing the string to TO-REBOL-FILE and then that will let you 
specify filenames with local file syntax.
Sunanda
20-Apr-2009
[1816]
assuming the file name is a string in system/options/args
  filename: to-file system/options/args

Though you may want to error trap that -- in case the command line 
is malformed. One way:
   filename: none
  attempt [ filename: to-file system/options/args]
  if none? file-name [print "Bad command line" halt]
BrianH
20-Apr-2009
[1817]
Sunanda, you're showing your Unix or Linux usage there. TO-FILE doesn't 
make sense to use on Windows (note %/c/ in his example).
mhinson
20-Apr-2009
[1818]
Thanks, that worked exactly as I needed, either way, & now it has 
helped me find the documentation for "datatype functions" which I 
am sure I will need more of later.
Sunanda
20-Apr-2009
[1819x2]
Thanks for the correction, Brian.
Mike, REBOL has some built-in help. Sometimes it can jog the memory, 
or point you to a function you never dreamed came as standard .... 
Try these in the console  
   help file
   help "to"
mhinson
20-Apr-2009
[1821]
Thanks Sunanda,  that is very handy, I didnt realise help searched 
like that, I thought you had to give it an exact command.  very good.
Oldes
20-Apr-2009
[1822]
Instead of:
  filename: none
  attempt [ filename: to-file system/options/args]
  if none? file-name [print "Bad command line" halt]
I would use:
if error? try [filename: to-file system/options/args][
	print "Bad command line" halt
]

I really don't like that people use the attemp in cases where they 
expect error. I use own attempt in cases where I don't expect error 
but still want to continue with execution (display and log the error).
Sunanda
21-Apr-2009
[1823]
Help is even better in R3 -- worth getting a copy just for that:
http://www.rebol.com/article/0404.html
mhinson
21-Apr-2009
[1824]
That is very good and usefull thanks.  Is there any way to get help 
on things like 

view layout [ slider ]   please.   I am paticularly keen to find 
how the data is returned from these controls.  something like

view layout [ h2 slider ]   but that dosn't work..  there are hundreds 
of examples of how pretty the vid functions are, but I have failed 
to find much about using the results returned.
Geomol
21-Apr-2009
[1825x3]
view layout [h: h2 "data shows here" slider [h/text: value show h]]
A block after a style is being evaluated, when you operate the style.
The name of the variable holding the data for slider is called value. 
You have to look at docs to figure that out:
http://www.rebol.com/docs/easy-vid.html

Or you can look into the styles yourself, like:
>> layout [s: slider]
>> ? s
mhinson
21-Apr-2009
[1828]
Thanks Geomol, the docs dont seem to explain all the functions of 
the returned object.  Is this detail recorded anywhere please?

The object for slider is value, but value seems to be an object with 
lots of  data & functions in it, how does it return the position 
I cant see how that is to be expected.