Forums | Admin

Discussion Forums: help

Start New Thread Start New Thread

 

By: Mushfeq Khan
RE: Parsing a tnsnames.ora file [ reply ]  
2007-03-24 01:08
Dan,

I'm not familiar the .ora file format, but here's what I could hack
together after looking at some samples. It's meant to give you an
idea of how to go about this.

====begin code=====

require 'dhaka'

class LexerSpecification < Dhaka::LexerSpecification
KEYWORDS = %w| DESCRIPTION ADDRESS PROTOCOL TCP UDP SERVER HOST PORT CONNECT_DATA SID |
DOMAIN_SEGMENT = ''

for_pattern('\s') do
# ignore whitespace
end

for_pattern('=') do
create_token('=')
end

for_pattern('\(') do
create_token('(')
end

for_pattern('\)') do
create_token(')')
end

for_pattern("[A-Za-z_]+(\\.[A-Za-z_]+)*") do
if KEYWORDS.include? current_lexeme.value
create_token(current_lexeme.value)
else
create_token('identifier')
end
end

for_pattern('\d+') do
create_token('integer')
end

for_pattern("(http:\\/\\/)?\\w+(\\.\\w+)*") do
create_token('domain')
end

end

class Grammar < Dhaka::Grammar

collect_block = proc { left_children = child_nodes[0].child_nodes; child_nodes.replace(left_children + [child_nodes[1]]); self }

for_symbol(Dhaka::START_SYMBOL_NAME) do
connection_specification %w| identifier = description |
end

for_symbol('description') do
description %w| ( DESCRIPTION = details ) |
end

for_symbol('details') do
single_detail %w| detail |
multiple_details %w| details detail |, &collect_block
end

for_symbol('detail') do
address_info %w| ( ADDRESS = address_details ) |
connect_data %w| ( CONNECT_DATA = connect_data_details ) |
end

for_symbol('address_details') do
single_address_detail %w| address_detail|
multiple_address_details %w| address_details address_detail |, &collect_block
end

for_symbol('address_detail') do
protocol_spec %w| ( PROTOCOL = protocol ) |
port_spec %w| ( PORT = integer ) |
host_spec %w| ( HOST = domain ) |
end

for_symbol('protocol') do
tcp %w| TCP |
udp %w| UDP |
end

for_symbol('connect_data_details') do
single_connect_data_detail %w| connect_data_detail |
multiple_connect_data_detail %w| connect_data_details connect_data_detail |, &collect_block
end

for_symbol('connect_data_detail') do
sid_spec %w| ( SID = identifier ) |
server_spec %w| ( SERVER = identifier ) |
end
end

lexer = Dhaka::Lexer.new(LexerSpecification)
parser = Dhaka::Parser.new(Grammar)

input = "foo_db.whatever =

(DESCRIPTION =

(ADDRESS =

(PROTOCOL=TCP)

(HOST=http://somehost.foo.com)

(PORT=1523)

)

(CONNECT_DATA =

(SID=bar)

)

)"

parse_result = parser.parse(lexer.lex(input))
case parse_result
when Dhaka::TokenizerErrorResult
puts "Unexpected character:"
puts input.insert(parse_result.unexpected_char_index, ">>>")
when Dhaka::ParseErrorResult
puts "Unexpected token:"
puts input.insert(parse_result.unexpected_token.input_position, ">>>")
else
puts parse_result.to_dot
end


====end code=====

It's a pretty strict specification. You can mess with the input string and
it'll show where there are parsing errors. I'm not especially fond of the case statement at the end and this will become a lot neater in the next version.

Let me know if you have other questions.

Mushfeq.

By: Daniel Berger
Parsing a tnsnames.ora file [ reply ]  
2007-03-23 20:57
Hi,

I'm new to writing grammars and parsers and I've read the examples, but I just do not get it. How, for example, would you write a grammar for, parse and lex a typical tnsnames.ora file? These are roughly the equivalent of /etc/hosts entries, but for Oracle databases. Here's a typical entry:

# This is a comment
# This is another comment
foo_db =
(DESCRIPTION =
(ADDRESS =
(PROTOCOL=TCP)
(HOST=somehost.foo.com)
(PORT=1523)
)
(CONNECT_DATA =
(SID=bar)
)
)

Where do I start?

Thanks,

Dan