Commits

Michael Granger  committed ddc50a8

* Checkpoint: First semi-useful version.

  • Participants

Comments (0)

Files changed (22)

File docs/CATALOG

+#
+# Title:  Ruby-LinkParser API Docs
+# Main:   README
+# Upload: ssh://yhaliwell/usr/local/www/devEiate.org/public/code/Ruby-LinkParser/
+# Webcvs: http://devEiate.org/projects/Ruby-LinkParser/browser/trunk/
+#
+ext/*.c
+lib/*.rb
+lib/**/*.rb
+README
+TODO

File docs/basic-api.rb

+#!/usr/bin/ruby 
+
+# The C equivalent:
+#   opts  = parse_options_create();
+#   dict  = dictionary_create("4.0.dict", "4.0.knowledge", NULL, "4.0.affix");
+#   sent = sentence_create(input_string[i], dict);
+#   num_linkages = sentence_parse(sent, opts);
+#   linkage = linkage_create(0, sent, opts);
+#   printf("%s\n", diagram = linkage_print_diagram(linkage));
+#   string_delete(diagram);
+#   linkage_delete(linkage);
+#   dictionary_delete(dict);
+#   parse_options_delete(opts);
+
+
+opts = {
+	:verbosity					=> 0,
+	:linkage_limit				=> 10000,
+	:min_null_count				=> 0,
+	:max_null_count				=> 0,
+	:null_block					=> 1,
+	:islands_ok					=> false,
+	:short_length				=> 6,
+	:all_short					=> false,
+	:display_short				=> true,
+	:display_word_subscripts 	=> true,
+	:display_link_subscripts 	=> true,
+	:display_walls				=> false,
+	:display_union				=> false,
+	:allow_null					=> true,
+	:echo_on					=> false,
+	:batch_mode					=> false,
+	:panic_mode					=> false,
+	:screen_width				=> 79,
+	:display_on					=> true,
+	:display_postscript			=> false,
+	:display_bad				=> false,
+	:display_links				=> false,
+}
+
+paths = [
+	dict_name,
+	pp_name,
+	cons_name,
+	affix_name
+]
+
+dict = LinkParser::Dict.create( opts )
+dict = LinkParser::Dict.create( paths )
+dict = LinkParser::Dict.create( "en" )
+dict = LinkParser::Dict.create( "en", opts )
+
+sentence = dict.parse( input_string, :verbosity => 3, :islands_ok => true )
+# -or-
+sentence = LinkParser::Sentence.new( input_string, dict )
+linkage_count = sentence.parse( :verbosity => 3, :islands_ok => true )
+
+sentence.linkages.each do |linkage|
+	puts linkage.diagram
+end
+sentence.each_linkage do |linkage|
+	puts linkage.diagram
+end
+
+

File docs/makedocs.rb

+#!/usr/bin/ruby
+#
+#	RDoc Documentation Generation Script
+#	$Id$
+#
+#	Copyright (c) 2001-2005 The FaerieMUD Consortium.
+#
+#	This is free software. You may use, modify, and/or redistribute this
+#	software under the terms of the Perl Artistic License. (See
+#	http://language.perl.com/misc/Artistic.html)
+#
+
+# Make sure we're in the correct directory, and if not, change there.
+BEGIN {
+	basedir = File::dirname(File::dirname( File::expand_path(__FILE__) ))
+	unless Dir::pwd == basedir
+		Dir::chdir( basedir ) 
+	end
+	$LOAD_PATH.unshift basedir
+}
+
+# Load modules
+require 'optparse'
+require 'rdoc/rdoc'
+require 'utils'
+include UtilityFunctions
+
+def makeDocs( docsdir, template='html', diagrams=false, upload=nil, ridocs=false )
+	debugMsg "docsdir = %p, template = %p, diagrams = %p, upload = %p, ridocs = %p" %
+		[docsdir, template, diagrams, upload, ridocs]
+
+	title = findRdocTitle()
+	docs = findRdocableFiles()
+	main = findRdocMain()
+	webcvs = findRdocCvsURL()
+	accessors = findRdocAccessors()
+
+	flags = [
+		'--all',
+		'--inline-source',
+		'--fmt', 'html',
+		'--include', 'docs',
+		'--template', template,
+		'--op', docsdir,
+		'--title', title,
+		'--tab-width', 4,
+	]
+
+	flags += [ '--quiet' ] unless $VERBOSE
+	flags += [ '--diagram' ] if diagrams
+	flags += [ '--main', main ] if main
+	flags += [ '--webcvs', webcvs ] if webcvs
+	for accessor in accessors
+		flags += [ '--accessor', accessor ]
+	end
+
+	if ridocs
+		header "Will create/install 'ri' source" if ridocs
+		buildRi( docs )
+	else
+		header "Making documentation in #{docsdir}."
+		header "Will upload to '#{upload}'\n" if upload
+		buildDocs( flags, docs )
+		uploadDocs( upload, docsdir ) if upload
+	end
+end
+
+
+def buildDocs( flags, docs )
+	message "Running 'rdoc #{flags.join(' ')} #{docs.join(' ')}'\n" if $VERBOSE
+	unless $DEBUG
+		begin
+			r = RDoc::RDoc.new
+			r.document( flags + docs )
+		rescue RDoc::RDocError => e
+			$stderr.puts e.message
+			exit(1)
+		end
+	end
+end
+
+
+def uploadDocs( url, docsdir )
+	header "Uploading new docs snapshot to #{url}."
+
+	case url
+	
+	# SSH target
+	when %r{^ssh://(.*)}
+		target = $1
+		if target =~ %r{^([^/]+)/(.*)}
+			host, path = $1, $2
+			path = "/" + path unless path =~ /^(\/|\.)/
+			cmd = "tar -C #{docsdir} -cf - . | ssh #{host} 'tar -C #{path} -xvf -'"
+			unless $DEBUG
+				system( cmd )
+			else
+				message "Would have uploaded using the command:\n    #{cmd}\n\n"
+			end
+		else
+			abort "--upload ssh://host/path"
+		end
+	when %r{^file://(.*)}
+		targetdir = $1
+		targetdir.gsub!( %r{^file://}, '' )
+
+		File.makedirs targetdir, true
+		Dir["#{docsdir}/**/*"].each {|file|
+			fname = file.gsub( %r:#{docsdir}/:, '' )
+			if File.directory? file
+				unless $DEBUG
+					File.makedirs File.join(targetdir, fname), true
+				else
+					message %{File.makedirs %s, true\n} % File.join(targetdir, fname)
+				end
+			else
+				unless $DEBUG
+					File.install( file, File.join(targetdir, fname), 0444, true )
+				else
+					message %{File.install( %s, %s, 0444, true )\n} % [
+						file,
+						File.join(targetdir, fname),
+					]
+				end
+			end
+		}
+
+	else
+		raise "I don't know how to upload to urls like '#{url}'."
+	end
+end
+
+def buildRi( docs )
+	message "Running 'rdoc -R #{docs.join(' ')}'\n" if $VERBOSE
+	unless $DEBUG
+		begin
+			r = RDoc::RDoc.new
+			r.document( ['-R'] + docs )
+		rescue RDoc::RDocError => e
+			$stderr.puts e.message
+			exit(1)
+		end
+	end
+	
+end
+
+
+if $0 == __FILE__
+	upload = nil
+	diagrams = false
+	template = 'html'
+	docsdir = "docs/html"
+	rimode = false
+	
+
+	# Read command-line options
+	ARGV.options do |oparser|
+		oparser.banner = "Usage: #$0 [options]\n"
+
+		oparser.separator "RDoc options:"
+		oparser.on( "--diagrams", "-d", TrueClass, "Generate diagrams" ) do
+			diagrams = true
+		end
+
+		oparser.on( "--output=DIR", "-o=DIR", String, "Set the output directory" ) do |val|
+			docsdir = val
+		end
+
+ 		oparser.on( "--ri", "-R", TrueClass, "Generate content for 'ri' instead of HTML" ) do
+ 			rimode = true
+		end
+
+		oparser.separator ""
+		oparser.separator "Post-generation options:"
+
+		oparser.on( "--upload=[URI]", "-u=[URI]", String, "Upload to the given URI" ) do |val|
+			upload = val
+			upload = findRdocUpload() if val.nil? || val.empty?
+		end
+
+		oparser.separator ""
+		oparser.separator "Output options:"
+
+		oparser.on( "--debug", "-d", TrueClass, "Output debugging information" ) do
+			$VERBOSE = true
+			debugMsg "Turned debugging on."
+		end
+
+		oparser.on( "--verbose", "-v", TrueClass, "Make progress verbose" ) do
+			$VERBOSE = true
+			debugMsg "Turned verbose on."
+		end
+
+		# Handle the 'help' option
+		oparser.on( "--help", "-h", "Display this text." ) do
+			$stderr.puts oparser
+			exit!(0)
+		end
+
+		oparser.parse!
+	end
+
+	makeDocs( docsdir, template, diagrams, upload, rimode )
+end

File docs/public-functions.h

+
+
+Dictionary dictionary_create(char *dict_name, char *post_process_file_name,
+  char *constituent_knowledge_name, char *affix_name);
+int dictionary_delete(Dictionary dict);
+int dictionary_get_max_cost(Dictionary dict);
+
+Parse_Options  parse_options_create();
+int parse_options_delete(Parse_Options opts);
+void parse_options_set_verbosity(Parse_Options opts, int verbosity);
+int  parse_options_get_verbosity(Parse_Options opts);
+void parse_options_set_linkage_limit(Parse_Options opts, int linkage_limit);
+int  parse_options_get_linkage_limit(Parse_Options opts);
+oid parse_options_set_disjunct_cost(Parse_Options opts, int disjunct_cost);
+int  parse_options_get_disjunct_cost(Parse_Options opts);
+void parse_options_set_min_null_count(Parse_Options opts, int null_count);
+int  parse_options_get_min_null_count(Parse_Options opts);
+void parse_options_set_max_null_count(Parse_Options opts, int null_count);
+int  parse_options_get_max_null_count(Parse_Options opts);
+void parse_options_set_null_block(Parse_Options opts, int null_block);
+int  parse_options_get_null_block(Parse_Options opts);
+void parse_options_set_short_length(Parse_Options opts, int short_length);
+int  parse_options_get_short_length(Parse_Options opts);
+void parse_options_set_islands_ok(Parse_Options opts, int islands_ok);
+int  parse_options_get_islands_ok(Parse_Options opts);
+void parse_options_set_max_parse_time(Parse_Options  opts, int secs);
+int  parse_options_get_max_parse_time(Parse_Options opts);
+void parse_options_set_max_memory(Parse_Options  opts, int mem);
+int  parse_options_get_max_memory(Parse_Options opts);
+int  parse_options_timer_expired(Parse_Options opts);
+int  parse_options_memory_exhausted(Parse_Options opts);
+int  parse_options_resources_exhausted(Parse_Options opts);
+void parse_options_reset_resources(Parse_Options opts);
+void parse_options_set_cost_model_type(Parse_Options opts, int cm);
+int  parse_options_get_cost_model_type(Parse_Options opts);
+void parse_options_set_screen_width(Parse_Options opts, int val);
+int  parse_options_get_screen_width(Parse_Options opts);
+void parse_options_set_allow_null(Parse_Options opts, int val);
+int  parse_options_get_allow_null(Parse_Options opts);
+void parse_options_set_display_walls(Parse_Options opts, int val);
+int  parse_options_get_display_walls(Parse_Options opts);
+void parse_options_set_all_short_connectors(Parse_Options opts, int val);
+int  parse_options_get_all_short_connectors(Parse_Options opts);
+
+Sentence sentence_create(char *input_string, Dictionary dict);
+void sentence_delete(Sentence sent);
+int sentence_parse(Sentence sent, Parse_Options opts);
+int sentence_length(Sentence sent);
+char * sentence_get_word(Sentence sent, int w);
+int sentence_null_count(Sentence sent);
+int sentence_num_linkages_found(Sentence sent);
+int sentence_num_valid_linkages(Sentence sent);
+int sentence_num_linkages_post_processed(Sentence sent);
+int sentence_num_violations(Sentence sent, int i);
+int sentence_disjunct_cost(Sentence sent, int i);
+
+Linkage  linkage_create(int index, Sentence sent, Parse_Options opts);
+int linkage_get_num_sublinkages(Linkage linkage);
+int linkage_set_current_sublinkage(Linkage linkage, int index);
+int linkage_compute_union(Linkage linkage);
+int linkage_get_num_words(Linkage linkage);
+int  linkage_get_num_links(Linkage linkage);
+int linkage_get_link_length(Linkage linkage, int index);
+int linkage_get_link_lword(Linkage linkage, int index);
+int linkage_get_link_rword(Linkage linkage, int index);
+char * linkage_print_diagram(Linkage linkage);
+char * linkage_print_postscript(Linkage linkage, int mode);
+char * linkage_print_links_and_domains(Linkage linkage);
+char * linkage_get_link_label(Linkage linkage, int index);
+char * linkage_get_link_llabel(Linkage linkage, int index);
+char * linkage_get_link_rlabel(Linkage linkage, int index);
+int     linkage_get_link_num_domains(Linkage linkage, int index);
+char ** linkage_get_link_domain_names(Linkage linkage, int index);
+char *  linkage_get_violation_name(Linkage linkage);
+char ** linkage_get_words(Linkage linkage);
+char *  linkage_get_word(Linkage linkage, int w);
+int linkage_unused_word_cost(Linkage linkage);
+int linkage_disjunct_cost(Linkage linkage);
+int linkage_and_cost(Linkage linkage);
+int linkage_link_cost(Linkage linkage);
+void linkage_delete(Linkage linkage);
+
+PostProcessor   post_process_open(char * name);
+void            post_process_close(PostProcessor postprocessor);
+void linkage_post_process(Linkage linkage, PostProcessor postprocessor);
+
+
+typedef struct CNode_s CNode;
+struct CNode_s {
+  char  * label;
+  CNode * child;
+  CNode * next;
+  int   start, end;
+};
+
+CNode * linkage_constituent_tree(Linkage linkage);
+void    linkage_free_constituent_tree(CNode * n);
+char *  linkage_print_constituent_tree(Linkage linkage, int mode);

File experiments/diagram_sentences.rb

+#!/usr/bin/ruby
+
+$LOAD_PATH.unshift "ext"
+
+require 'linkparser'
+require './utils.rb'
+
+include UtilityFunctions
+
+dict = LinkParser::Dictionary.new( :screen_width => 120 )
+loop do
+	input_string = prompt( "Sentence to diagram: " )
+	break if input_string.empty?
+
+	sent = dict.parse( input_string.chomp )
+
+	sent.linkages.each do |linkage|
+		puts linkage.diagram, linkage.links_and_domains
+	end
+end
+
+
+### Example output:
+# Sentence to diagram:  The bat left the cave just after sunset.
+# 
+#     +---------------------------Xp--------------------------+
+#     +-----Wd----+      +----Os----+                         |
+#     |      +-Ds-+--Ss--+    +--Ds-+--Ma--+-MVp-+---Jp--+    |
+#     |      |    |      |    |     |      |     |       |    |
+# LEFT-WALL the bat.n left.v the cave.n just.a after sunset.n . 
+# 
+#            LEFT-WALL      Xp      <---Xp---->  Xp        .
+#  (m)       LEFT-WALL      Wd      <---Wd---->  Wd        bat.n
+#  (m)       the            D       <---Ds---->  Ds        bat.n
+#  (m)       bat.n          Ss      <---Ss---->  S         left.v
+#  (m)       left.v         O       <---Os---->  Os        cave.n
+#  (m)       the            D       <---Ds---->  Ds        cave.n
+#  (m) (e)   cave.n         M       <---Ma---->  Ma        just.a
+#  (m) (e)   just.a         MV      <---MVp--->  MVp       after
+#  (m) (e)   after          J       <---Jp---->  Jp        sunset.n
+#            .              RW      <---RW---->  RW        RIGHT-WALL
+# 

File experiments/free_stuff.rb

+#!/usr/bin/ruby
+# 
+# A test script to check if dictionaries are freed before the program terminates
+# 
+
+BEGIN {
+	require 'pathname'
+	basedir = Pathname.new( __FILE__ ).dirname.parent.expand_path
+	extdir = basedir + "ext"
+	
+	$LOAD_PATH.unshift( extdir ) unless $LOAD_PATH.include?( extdir )
+	
+	require basedir + "utils.rb"
+	include UtilityFunctions
+}
+
+
+$DEBUG = 1
+require 'linkparser'
+
+$deferr.sync = true
+
+1000.times do
+	$deferr.print '.'
+	
+	dict = LinkParser::Dictionary.new
+	GC.start
+end
+

File ext/TEMPLATE.c.tpl

+/*
+ *  #{newfile.basename} - Ruby LinkParser
+ *  $Id$
+ *  
+ *  Authors:
+ *    * #{user.gecos} <#{tm[:user_email]}>
+ *  
+ *  Copyright (c) #{date.year} #{tm[:organization_name]}.
+ *  
+ *  This work is licensed under the Creative Commons Attribution License. To
+ *  view a copy of this license, visit
+ *  http://creativecommons.org/licenses/by/1.0 or send a letter to Creative
+ *  Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
+ *  
+ */
+
+#include "linkparser.h"
+
+
+/* --------------------------------------------------
+ *  Forward declarations
+ * -------------------------------------------------- */
+
+
+/* --------------------------------------------------
+ * Macros and constants
+ * -------------------------------------------------- */
+
+
+/* --------------------------------------------------
+ *	Memory-management functions
+ * -------------------------------------------------- */
+
+
+
+void
+rlink_init_#{newfile.basename('.c')}(void)
+{
+	
+}
+

File ext/dictionary.c

+/*
+ *  dict.c - Ruby LinkParser - Dictionary Class
+ *  $Id$
+ *  
+ *  Authors:
+ *    * Michael Granger <ged@FaerieMUD.org>
+ *  
+ *  Copyright (c) 2006 The FaerieMUD Consortium.
+ *  
+ *  This work is licensed under the Creative Commons Attribution License. To
+ *  view a copy of this license, visit
+ *  http://creativecommons.org/licenses/by/1.0 or send a letter to Creative
+ *  Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
+ *  
+ */
+
+#include <stdlib.h>  /* for workaround_locale_bug() */
+
+#include "linkparser.h"
+
+
+
+
+/* --------------------------------------------------
+ *  Forward declarations
+ * -------------------------------------------------- */
+void workaround_locale_bug();
+
+
+/* --------------------------------------------------
+ *  Memory management functions
+ * -------------------------------------------------- */
+
+/*
+ * Free function
+ */
+static void
+rlink_dict_gc_free( dict )
+	Dictionary dict;
+{
+	if ( dict ) dictionary_delete( dict );
+}
+
+
+/*
+ * Object validity checker. Returns the data pointer.
+ */
+static Dictionary
+check_dict( self )
+	 VALUE	self;
+{
+	debugMsg(( "Checking a LinkParser::Dictionary object (%d).", self ));
+	Check_Type( self, T_DATA );
+
+    if ( !IsDictionary(self) ) {
+		rb_raise( rb_eTypeError, "wrong argument type %s (expected LinkParser::Dictionary)",
+				  rb_class2name(CLASS_OF( self )) );
+    }
+	
+	return DATA_PTR( self );
+}
+
+
+/*
+ * Fetch the data pointer and check it for sanity.
+ */
+static Dictionary
+get_dict( self )
+	 VALUE self;
+{
+	Dictionary dict = check_dict( self );
+
+	debugMsg(( "Fetching a Dictionary (%p).", dict ));
+	if ( !dict )
+		rb_raise( rb_eRuntimeError, "uninitialized Dictionary" );
+
+	return dict;
+}
+
+
+/* 
+ * Get the Dictionary behind the LinkParser::Dictionary +object+ specified.
+ */ 
+Dictionary
+rlink_get_dict( obj )
+	VALUE obj;
+{
+	return get_dict( obj );
+}
+
+
+
+/* --------------------------------------------------
+ * Class Methods
+ * -------------------------------------------------- */
+
+/*
+ * allocate()
+ * --
+ * Allocate a new LinkParser::Dictionary object.
+ */
+static VALUE
+rlink_dict_s_alloc( klass )
+	 VALUE klass;
+{
+	debugMsg(( "Wrapping an uninitialized Dictionary pointer." ));
+	return Data_Wrap_Struct( klass, 0, rlink_dict_gc_free, 0 );
+}
+
+
+static Dictionary
+rlink_make_oldstyle_dict( dict_file, pp_file, cons_file, affix_file )
+	VALUE dict_file, pp_file, cons_file, affix_file;
+{
+	SafeStringValue( dict_file  );
+	SafeStringValue( pp_file    );
+	SafeStringValue( cons_file  );
+	SafeStringValue( affix_file );
+	
+	return dictionary_create(
+		STR2CSTR( dict_file  ),
+		STR2CSTR( pp_file    ),
+		STR2CSTR( cons_file  ),
+		STR2CSTR( affix_file )
+	);
+}
+
+
+/*
+ * new( options={} )
+ * new( language, options={} )
+ * new( dict, pp, ck, affix, option={} )
+ * --
+ * Create a new LinkParser::Dictionary with data files for the given +language+, or
+ * using the specified data files.
+ */
+static VALUE
+rlink_dict_initialize( argc, argv, self )
+	int argc;
+	VALUE *argv;
+	VALUE self;
+{
+	if ( !check_dict(self) ) {
+		int i = 0;
+		Dictionary dict = NULL;
+		VALUE arg1, arg2, arg3, arg4, arg5 = Qnil;
+		VALUE lang = Qnil;
+		VALUE opthash = Qnil;
+		
+		switch( i = rb_scan_args(argc, argv, "05", &arg1, &arg2, &arg3, &arg4, &arg5) ) {
+		  /* Dictionary.new */
+		  case 0:
+			debugMsg(( "No arguments" ));
+			break;
+
+		  /* Dictionary.new( lang )*/
+		  /* Dictionary.new( opthash )*/
+		  case 1:
+			if( TYPE(arg1) == T_HASH ) {
+				debugMsg(( "One arg: options hash."));
+				opthash = arg1;
+			} else {
+				debugMsg(( "One arg: language" ));
+				lang = arg1;
+			}
+			break;
+
+		  /* Dictionary.new( lang, opthash ) */
+		  case 2:
+			debugMsg(( "Two args: language and options hash."));
+			lang = arg1;
+			opthash = arg2;
+			break;
+
+		  /* Dictionary.new( dict, pp, cons, affix ) */
+		  /* Dictionary.new( dict, pp, cons, affix, opthash ) */
+		  case 4:
+		  case 5:
+			debugMsg(( "Four or five args: old-style explicit dict files." ));
+			dict = rlink_make_oldstyle_dict( arg1, arg2, arg3, arg4, arg5 );
+			break;
+		
+		  /* Anything else is an error */	
+		  default:
+			rb_raise( rb_eArgError, 
+				"wrong number of arguments (%d for 0,1,2,4, or 5)", i );
+		}
+
+		/* Create the dictionary if it hasn't been already */
+		if ( !dict && i < 4 ) {
+			if ( RTEST(lang) ) {
+				SafeStringValue( lang );
+				dict = dictionary_create_lang( STR2CSTR(lang) );
+			} else {
+				workaround_locale_bug();
+				dict = dictionary_create_default_lang();
+			}
+		}
+		
+		/* If the dictionary still isn't created, there was an error
+		   creating it */
+		if ( !dict ) rlink_raise_lp_error();
+
+		DATA_PTR( self ) = dict;
+
+		/* If they passed in an options hash, save it for later. */
+		if ( RTEST(opthash) ) rb_iv_set( self, "@options", opthash );
+		else rb_iv_set( self, "@options", rb_hash_new() );
+	}
+
+	else {
+		rb_raise( rb_eRuntimeError, "Cannot re-initialize a Dictionary object." );
+	}
+
+	return Qnil;
+}
+
+
+
+/*
+  The link-grammar library segfaults when you call
+  dictionary_create_default_lang() with ENV['LANG'] unset, so just set it to
+  English if it isn't already set.
+*/
+void
+workaround_locale_bug()
+{
+	setenv( "LANG", "en", 0 );
+}
+
+
+/*
+ * max_cost()
+ * --
+ * Returns the maximum cost (number of brackets []) that is placed on any
+ * connector in the dictionary. This is useful for designing a parsing
+ * algorithm that progresses in stages, first trying the cheap connectors.
+ */
+static VALUE 
+rlink_get_max_cost( self )
+	VALUE self;
+{
+	Dictionary dict = get_dict( self );
+	int cost = dictionary_get_max_cost( dict );
+	
+	debugMsg(( "Max cost is: %d", cost ));
+	
+	return INT2NUM( cost );
+}
+
+
+/*
+ * parse( sentence_string )
+ * --
+ * Parse the specified +sentence_string+ with the receiving Dictionary and
+ * return a LinkParser::Sentence.
+ */
+static VALUE 
+rlink_parse( argc, argv, self )
+	int argc;
+	VALUE *argv;
+	VALUE self;
+{
+	VALUE input_string, options, sentence;
+	VALUE args[2];
+	int i;
+
+	i = rb_scan_args( argc, argv, "11", &input_string, &options );
+
+	/* Create the new sentence */
+	args[0] = input_string;
+	args[1] = self;
+	sentence = rb_class_new_instance( 2, args, rlink_cSentence );
+	
+	/* Now call #parse on it */
+	if ( i == 1 )
+		rb_funcall( sentence, rb_intern("parse"), 0, 0 );
+	else
+		rb_funcall( sentence, rb_intern("parse"), 1, options );
+	
+	return sentence;
+}
+
+
+
+
+
+/* Initializer */
+void
+rlink_init_dict(void)
+{
+	rlink_cDictionary = rb_define_class_under( rlink_mLinkParser, "Dictionary",
+	 	rb_cObject );
+	
+	rb_define_alloc_func( rlink_cDictionary, rlink_dict_s_alloc );
+	rb_define_method( rlink_cDictionary, "initialize", rlink_dict_initialize, -1 );
+
+	rb_define_method( rlink_cDictionary, "max_cost", rlink_get_max_cost, 0 );
+	rb_define_method( rlink_cDictionary, "parse", rlink_parse, -1 );
+
+	rb_define_attr( rlink_cDictionary, "options", 1, 0 );
+}
+

File ext/extconf.rb

+#!/usr/bin/ruby
+#
+# $Id$
+# Time-stamp: <28-Nov-2004 00:30:32 ged>
+#
+# Authors:
+#   # Michael Granger <ged@FaerieMUD.org>
+#
+# Copyright (c) 2006 The FaerieMUD Consortium.
+#
+# This work is licensed under the Creative Commons Attribution License. To
+# view a copy of this license, visit
+# http://creativecommons.org/licenses/by/1.0 or send a letter to Creative
+# Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
+#
+
+require 'mkmf'
+
+def abort( msg )
+	$stderr.puts( msg )
+	exit 1
+end
+
+
+$CFLAGS << ' -Wall'
+$CFLAGS << ' -DDEBUG'
+
+dir_config( "linkparser" )
+have_header( "link-grammar/link-includes.h")
+have_header( "link-grammar/utilities.h")
+have_library( "link-grammar", "dictionary_create" ) or
+	abort( "Could not find link-grammar library." )
+
+create_makefile( "linkparser" )

File ext/linkage.c

+/*
+ *  linkage.c - Ruby LinkParser Linkage class
+ *  $Id$
+ *  
+ *  Authors:
+ *    * Michael Granger <ged@FaerieMUD.org>
+ *  
+ *  Copyright (c) 2006 The FaerieMUD Consortium.
+ *  
+ *  This work is licensed under the Creative Commons Attribution License. To
+ *  view a copy of this license, visit
+ *  http://creativecommons.org/licenses/by/1.0 or send a letter to Creative
+ *  Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
+ *  
+ */
+
+#include "linkparser.h"
+
+
+/* --------------------------------------------------
+ *  Forward declarations
+ * -------------------------------------------------- */
+
+
+/* --------------------------------------------------
+ * Macros and constants
+ * -------------------------------------------------- */
+
+
+/* --------------------------------------------------
+ *	Memory-management functions
+ * -------------------------------------------------- */
+/*
+ * Allocation function
+ */
+static rlink_LINKAGE *
+rlink_linkage_alloc()
+{
+	rlink_LINKAGE *ptr = ALLOC( rlink_LINKAGE );
+	
+	ptr->linkage	= NULL;
+	ptr->sentence	= Qnil;
+	
+	debugMsg(( "Initialized an rlink_LINKAGE <%p>", ptr ));
+	return ptr;
+}
+
+
+/*
+ * GC Mark function
+ */
+static void
+rlink_linkage_gc_mark( ptr )
+	rlink_LINKAGE *ptr;
+{
+	debugMsg(( "Marking LinkParser::Linkage %p", ptr ));
+	
+	if ( ptr ) {
+		rb_gc_mark( ptr->sentence );
+	}
+	
+	else {
+		debugMsg(( "Not marking uninitialized rlink_LINKAGE" ));
+	}
+}
+
+
+/*
+ * GC Free function
+ */
+static void
+rlink_linkage_gc_free( ptr )
+	rlink_LINKAGE *ptr;
+{
+	if ( ptr ) {
+		linkage_delete( (Linkage)ptr->linkage );
+		ptr->linkage = NULL;
+		ptr->sentence = Qnil;
+	}
+	
+	else {
+		debugMsg(( "Not freeing an uninitialized rlink_LINKAGE" ));
+	}
+}
+
+
+/*
+ * Object validity checker. Returns the data pointer.
+ */
+static rlink_LINKAGE *
+check_linkage( self )
+	 VALUE	self;
+{
+	debugMsg(( "Checking a LinkParser::Linkage object (%d).", self ));
+	Check_Type( self, T_DATA );
+
+    if ( !IsLinkage(self) ) {
+		rb_raise( rb_eTypeError, "wrong argument type %s (expected LinkParser::Linkage)",
+				  rb_class2name(CLASS_OF( self )) );
+    }
+	
+	return DATA_PTR( self );
+}
+
+
+/*
+ * Fetch the data pointer and check it for sanity.
+ */
+static rlink_LINKAGE *
+get_linkage( self )
+	 VALUE self;
+{
+	rlink_LINKAGE *ptr = check_linkage( self );
+
+	debugMsg(( "Fetching a Linkage (%p).", ptr ));
+	if ( !ptr )
+		rb_raise( rb_eRuntimeError, "uninitialized Linkage" );
+
+	return ptr;
+}
+
+
+/*
+ * Publicly-usable linkage-fetcher
+ */
+/*rlink_LINKAGE *
+rlink_get_linkage( self )
+{
+	return get_linkage( self );
+}
+*/
+
+
+/* --------------------------------------------------
+ * Class Methods
+ * -------------------------------------------------- */
+
+/*
+ * allocate()
+ * --
+ * Allocate a new LinkParser::Linkage object.
+ */
+static VALUE
+rlink_linkage_s_alloc( klass )
+	 VALUE klass;
+{
+	debugMsg(( "Wrapping an uninitialized Linkage pointer." ));
+	return Data_Wrap_Struct( klass, rlink_linkage_gc_mark, rlink_linkage_gc_free, 0 );
+}
+
+
+/* --------------------
+ * Instance methods
+ * -------------------- */
+
+
+/*
+ * initialize( index, sentence, options={} )
+ * --
+ * Create a new LinkParser::Linkage object out of the linkage indicated by
+ * +index+ (a positive Integer) from the specified sentence (a 
+ * LinkParser::Sentence). The optional options hash can be used to override
+ * the parse options of the Sentence for the new linkage.
+ */
+static VALUE
+rlink_linkage_init( argc, argv, self )
+	int argc;
+	VALUE *argv;
+	VALUE self;
+{
+	if ( !check_linkage(self) ) {
+		int i, link_index, max_index;
+		VALUE index, sentence, options, defopts;
+		rlink_SENTENCE *sent_ptr;
+		Linkage linkage;
+		Parse_Options opts;
+		rlink_LINKAGE *ptr;
+		
+		i = rb_scan_args( argc, argv, "21", &index, &sentence, &options );
+
+		defopts = rb_hash_new(); /*rb_funcall( sentence, rb_intern("options"), 0 );*/
+		options = rlink_make_parse_options( defopts, options );
+		opts = rlink_get_parseopts( options );
+
+		sent_ptr = (rlink_SENTENCE *)rlink_get_sentence( sentence );
+
+		link_index = NUM2INT(index);
+		max_index = sentence_num_linkages_found((Sentence)sent_ptr->sentence) - 1;
+		if ( link_index > max_index )
+			rb_raise( rlink_eLpError, "Invalid linkage %d (max is %d)", 
+				link_index, max_index );
+
+		linkage = linkage_create( link_index, (Sentence)sent_ptr->sentence, opts );
+		if ( !linkage ) rlink_raise_lp_error();
+
+		DATA_PTR( self ) = ptr = rlink_linkage_alloc();
+		
+		ptr->linkage = linkage;
+		ptr->sentence = sentence;
+	}
+	
+	else {
+		rb_raise( rb_eRuntimeError,
+				  "Cannot re-initialize a linkage once it's been created." );
+	}
+	
+	return Qnil;
+}
+
+
+
+/* 
+ * diagram
+ * --
+ * Return a String containing a diagram of the linkage.
+ */
+static VALUE
+rlink_linkage_diagram( self )
+	VALUE self;
+{
+	rlink_LINKAGE *ptr = get_linkage( self );
+	char *diagram_cstr;
+	VALUE diagram;
+	
+	diagram_cstr = linkage_print_diagram( (Linkage)ptr->linkage );
+	diagram = rb_str_new2( diagram_cstr );
+	string_delete( diagram_cstr );
+	
+	return diagram;
+}
+
+
+/* 
+ * links_and_domains
+ * --
+ * Return a String containing a lists all of the links and domain names for 
+ * the current sublinkage. For example, for the sentence "I eat, therefore I 
+ * think":
+ * 
+ *             /////          RW      <---RW---->  RW        /////
+ *   (m)       /////          Wd      <---Wd---->  Wd        I.p
+ *   (m)       I.p            CC      <---CC---->  CC        therefore
+ *   (m)       I.p            Sp*i    <---Sp*i-->  Sp        eat
+ *   (m)       ,              Xd      <---Xd---->  Xd        therefore
+ *   (m) (m)   therefore      Wd      <---Wd---->  Wd        I.p
+ *   (m) (m)   I.p            Sp*i    <---Sp*i-->  Sp        think.v
+ * 
+ * 
+ * 
+ */
+static VALUE
+rlink_linkage_links_and_domains( self )
+	VALUE self;
+{
+	rlink_LINKAGE *ptr = get_linkage( self );
+	char *diagram_cstr;
+	VALUE diagram;
+	
+	diagram_cstr = linkage_print_links_and_domains( (Linkage)ptr->linkage );
+	diagram = rb_str_new2( diagram_cstr );
+	string_delete( diagram_cstr );
+	
+	return diagram;
+}
+
+
+
+/* Class initializer */
+void
+rlink_init_linkage(void)
+{
+	rlink_cLinkage = rb_define_class_under( rlink_mLinkParser, "Linkage", rb_cObject );
+	
+	rb_define_alloc_func( rlink_cLinkage, rlink_linkage_s_alloc );
+	
+	rb_define_method( rlink_cLinkage, "initialize", rlink_linkage_init, -1 );
+	rb_define_method( rlink_cLinkage, "diagram", rlink_linkage_diagram, 0 );
+	rb_define_method( rlink_cLinkage, "diagram", rlink_linkage_diagram, 0 );
+	rb_define_method( rlink_cLinkage, "links_and_domains", 
+		rlink_linkage_links_and_domains, 0 );
+}
+

File ext/linkparser.c

+/*
+ *  linkparser.c - Ruby LinkParser
+ *  $Id$
+ *  
+ *  Authors:
+ *    * Michael Granger <ged@FaerieMUD.org>
+ *  
+ *  Copyright (c) 2006 The FaerieMUD Consortium.
+ *  
+ *  This work is licensed under the Creative Commons Attribution License. To
+ *  view a copy of this license, visit
+ *  http://creativecommons.org/licenses/by/1.0 or send a letter to Creative
+ *  Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
+ *  
+ */
+
+#include "linkparser.h"
+
+/*
+ * Globals
+ */
+
+VALUE rlink_mLinkParser;
+
+VALUE rlink_eLpError;
+
+VALUE rlink_cDictionary;
+VALUE rlink_cSentence;
+VALUE rlink_cLinkage;
+VALUE rlink_cParseOptions;
+
+
+/* --------------------------------------------------
+ * Utility functions
+ * -------------------------------------------------- */
+
+void
+#ifdef HAVE_STDARG_PROTOTYPES
+rlink_debug(const char *fmt, ...)
+#else
+rlink_debug(fmt, va_alist)
+	 const char *fmt;
+	 va_dcl
+#endif
+{
+	char		buf[BUFSIZ], buf2[BUFSIZ];
+	va_list	args;
+
+	if (!RTEST(ruby_debug)) return;
+
+	snprintf( buf, BUFSIZ, "LinkParser Debug>>> %s", fmt );
+
+	va_init_list( args, fmt );
+	vsnprintf( buf2, BUFSIZ, buf, args );
+	fputs( buf2, stderr );
+	fputs( "\n", stderr );
+	fflush( stderr );
+	va_end( args );
+}
+
+
+/*
+ * Raise a LinkParser::Error, either with the message in lperrmsg if it's
+ * set or a generic error if not.
+ */
+void
+rlink_raise_lp_error( void )
+{
+	if ( lperrno ) {
+		rb_raise( rlink_eLpError, lperrmsg );
+	} else {
+		rb_raise( rlink_eLpError, "Unknown error" );
+	}
+}
+
+
+/* Make a Parse_Options after merging the specified default_options with any 
+   new options given. */
+VALUE
+rlink_make_parse_options( default_options, options )
+	VALUE default_options, options;
+{
+	if ( NIL_P(options) ) options = rb_hash_new();
+	options = rb_funcall( default_options, rb_intern("merge"), 1, options );
+
+	return rb_class_new_instance( 1, &options, rlink_cParseOptions );
+}
+
+
+
+
+/* Library init function */
+void
+Init_linkparser(void)
+{
+	rlink_mLinkParser = rb_define_module( "LinkParser" );
+	rlink_eLpError = rb_define_class_under( rlink_mLinkParser, "Error", rb_eRuntimeError );
+	
+	rlink_init_dict();
+	rlink_init_sentence();
+	rlink_init_linkage();
+	rlink_init_parseoptions();
+}
+

File ext/linkparser.h

+/*
+ *		linkparser.h - Ruby-LinkParser Header
+ *		$Id$
+ *
+ *		Authors:
+ *		  * Michael Granger <ged@FaerieMUD.org>
+ *
+ *		Copyright (c) 2006 The FaerieMUD Consortium.
+ *
+ *		This work is licensed under the Creative Commons Attribution License. To
+ *		view a copy of this license, visit
+ *		http://creativecommons.org/licenses/by/1.0 or send a letter to Creative
+ *		Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
+ *
+ */
+
+
+#ifndef _R_LINKPARSER_H
+#define _R_LINKPARSER_H
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <ruby.h>
+#include <intern.h>				/* For rb_dbl2big() */
+
+#include <link-grammar/link-includes.h>
+
+
+
+/* Debugging functions/macros */
+#ifdef HAVE_STDARG_PROTOTYPES
+#include <stdarg.h>
+#define va_init_list(a,b) va_start(a,b)
+extern void rlink_debug(const char *fmt, ...);
+#else
+#include <varargs.h>
+#define va_init_list(a,b) va_start(a)
+extern void rlink_debug(fmt, va_alist);
+#endif
+
+extern void rlink_raise_lp_error _(( void ));
+extern VALUE rlink_make_parse_options _(( VALUE, VALUE ));
+
+
+/* -------------------------------------------------------
+ * Globals
+ * ------------------------------------------------------- */
+
+/*
+ * Modules
+ */
+extern VALUE rlink_mLinkParser;
+
+extern VALUE rlink_cDictionary;
+extern VALUE rlink_cSentence;
+extern VALUE rlink_cLinkage;
+extern VALUE rlink_cParseOptions;
+extern VALUE rlink_cPostProcessor;
+extern VALUE rlink_cConstituentTree;
+
+extern VALUE rlink_eLpError;
+
+
+/* 
+ * Structures
+ */ 
+typedef struct {
+	Sentence 	sentence;
+	VALUE	 	dictionary;
+	VALUE		parsed_p;
+	VALUE		options;
+} rlink_SENTENCE;
+
+typedef struct {
+	Linkage		linkage;
+	VALUE		sentence;
+} rlink_LINKAGE;
+
+
+
+/*
+ * Macros
+ */
+
+/* Debugging macro */
+#if DEBUG
+#  define debugMsg(f)	rlink_debug f
+#else /* ! DEBUG */
+#  define debugMsg(f) 
+#endif /* DEBUG */
+
+
+#define IsDictionary( obj ) rb_obj_is_kind_of( (obj), rlink_cDictionary )
+#define IsSentence( obj ) rb_obj_is_kind_of( (obj), rlink_cSentence )
+#define IsLinkage( obj ) rb_obj_is_kind_of( (obj), rlink_cLinkage )
+#define IsParseOptions( obj ) rb_obj_is_kind_of( (obj), rlink_cParseOptions )
+
+
+/* -------------------------------------------------------
+ * Initializer functions
+ * ------------------------------------------------------- */
+extern void rlink_init_dict						_(( void ));
+extern void rlink_init_sentence					_(( void ));
+extern void rlink_init_linkage					_(( void ));
+extern void rlink_init_parseoptions				_(( void ));
+
+/* Fetchers */
+extern Dictionary rlink_get_dict				_(( VALUE ));
+extern rlink_SENTENCE *rlink_get_sentence		_(( VALUE ));
+extern Parse_Options rlink_get_parseopts		_(( VALUE ));
+
+#endif /* _R_LINKPARSER_H */
+

File ext/parseoptions.c

+/*
+ *  parseoptions.c - Ruby LinkParser::ParseOptions class
+ *  $Id$
+ *  
+ *  Authors:
+ *    * Michael Granger <ged@FaerieMUD.org>
+ *  
+ *  Copyright (c) 2006 The FaerieMUD Consortium.
+ *  
+ *  This work is licensed under the Creative Commons Attribution License. To
+ *  view a copy of this license, visit
+ *  http://creativecommons.org/licenses/by/1.0 or send a letter to Creative
+ *  Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
+ *  
+ */
+
+#include "linkparser.h"
+
+
+/* --------------------------------------------------
+ *  Forward declarations
+ * -------------------------------------------------- */
+
+static VALUE rlink_parseopts_each_opthash_i _(( VALUE, VALUE ));
+
+
+/* --------------------------------------------------
+ * Macros and constants
+ * -------------------------------------------------- */
+
+
+/* --------------------------------------------------
+ *	Memory-management functions
+ * -------------------------------------------------- */
+
+/*
+ * Free function
+ */
+static void
+rlink_parseopts_gc_free( parseopts )
+	Parse_Options parseopts;
+{
+	if ( parseopts ) parse_options_delete( parseopts );
+}
+
+
+/*
+ * Object validity checker. Returns the data pointer.
+ */
+static Parse_Options
+check_parseopts( self )
+	 VALUE	self;
+{
+	debugMsg(( "Checking a LinkParser::ParseOptions object (%d).", self ));
+	Check_Type( self, T_DATA );
+
+    if ( !IsParseOptions(self) ) {
+		rb_raise( rb_eTypeError, "wrong argument type %s (expected LinkParser::ParseOptions)",
+				  rb_class2name(CLASS_OF( self )) );
+    }
+	
+	return DATA_PTR( self );
+}
+
+
+/*
+ * Fetch the data pointer and check it for sanity.
+ */
+static Parse_Options
+get_parseopts( self )
+	 VALUE self;
+{
+	Parse_Options parseopts = check_parseopts( self );
+
+	debugMsg(( "Fetching a Parse_Options (%p).", parseopts ));
+	if ( !parseopts )
+		rb_raise( rb_eRuntimeError, "uninitialized ParseOptions" );
+
+	return parseopts;
+}
+
+
+/* 
+ * Get the Parse_Options struct behind the LinkParser::ParseOptions +object+ 
+ * specified.
+ */ 
+Parse_Options
+rlink_get_parseopts( obj )
+	VALUE obj;
+{
+	return get_parseopts( obj );
+}
+
+
+/* --------------------------------------------------
+ * Class Methods
+ * -------------------------------------------------- */
+
+/*
+ * allocate()
+ * --
+ * Allocate a new LinkParser::ParseOptions object.
+ */
+static VALUE
+rlink_parseopts_s_alloc( klass )
+	 VALUE klass;
+{
+	debugMsg(( "Wrapping an uninitialized ParseOptions pointer." ));
+	return Data_Wrap_Struct( klass, 0, rlink_parseopts_gc_free, 0 );
+}
+
+
+
+/* ---------------------------------------------------
+ * Instance Methods
+ * --------------------------------------------------- */
+
+
+/*
+ * initialize( opthash={} )
+ * --
+ * Create a new ParseOptions object and set values from opthash.
+ */
+static VALUE
+rlink_parseopts_init( argc, argv, self )
+	int argc;
+	VALUE *argv;
+	VALUE self;
+{
+	if ( ! check_parseopts(self) ) {
+		Parse_Options opts;
+		VALUE opthash = Qnil;
+		
+		debugMsg(( "Initializing a ParseOptions: %p", self ));
+		DATA_PTR( self ) = opts = parse_options_create();
+
+		rb_scan_args( argc, argv, "01", &opthash );
+		if ( RTEST(opthash) ) {
+			debugMsg(( "Setting options from an opthash." ));
+			rb_iterate( rb_each, opthash, rlink_parseopts_each_opthash_i, self );
+		}
+	}
+	
+	else {
+		rb_raise( rb_eRuntimeError, "Cannot re-initialize a Dictionary object." );
+	}
+
+	return self;
+}
+
+
+static VALUE
+rlink_parseopts_each_opthash_i( pair, self )
+	VALUE pair, self;
+{
+	VALUE key, val, keystring;
+	char *method_name;
+	ID method;
+	
+	key = rb_ary_entry( pair, 0 );
+	val = rb_ary_entry( pair, 1 );
+
+	keystring = rb_obj_as_string( key );
+	
+	method_name = ALLOCA_N( char, RSTRING(keystring)->len + 1 );
+	strncpy( method_name, RSTRING(keystring)->ptr, RSTRING(keystring)->len + 1 );
+	strncat( method_name, "=", 1 );
+	
+	debugMsg(( "Calling method %s", method_name ));
+	method = rb_intern( method_name );
+	
+	return rb_funcall( self, method, 1, val );
+}
+
+
+/*
+ * merge( other )
+ * --
+ * Merge the receiving parse options with the given +other+ object, which can
+ * be either another LinkParser::ParseOptions object or a Hash of options.
+ */
+/*static VALUE
+rlink_parseopts_merge( self, other )
+	VALUE self, other;
+{
+	
+}
+*/
+
+
+/*
+ * verbosity=( int )
+ * --
+ * This sets the level of description printed to stderr/stdout about the 
+ * parsing process.
+ */
+static VALUE
+rlink_parseopts_set_verbosity( self, verbosity )
+	VALUE self, verbosity;
+{
+	Parse_Options opts = get_parseopts( self );
+	parse_options_set_verbosity( opts, NUM2INT(verbosity) );
+	return verbosity;
+}
+
+/*
+ * verbosity => int
+ * --
+ * This gets the level of description printed to stderr/stdout about the 
+ * parsing process.
+ */
+static VALUE
+rlink_parseopts_get_verbosity( self )
+	VALUE self;
+{
+	Parse_Options opts = get_parseopts( self );
+	int rval;
+
+	rval = parse_options_get_verbosity( opts );
+	return INT2FIX( rval );
+}
+
+/*
+ * linkage_limit=( int )
+ * --
+ * This parameter determines the maximum number of linkages that are 
+ * considered in post-processing. If more than +linkage_limit+ linkages are found, 
+ * then a random sample of +linkage_limit+ is chosen for post-processing. When 
+ * this happen a warning is displayed at verbosity levels greater than 1.
+ */
+static VALUE
+rlink_parseopts_set_linkage_limit( self, linkage_limit )
+	VALUE self, linkage_limit;
+{
+	Parse_Options opts = get_parseopts( self );
+	parse_options_set_linkage_limit( opts, NUM2INT(linkage_limit) );
+	return linkage_limit;
+}
+
+/*
+ * linkage_limit => int
+ * --
+ * This parameter determines the maximum number of linkages that are 
+ * considered in post-processing. If more than +linkage_limit+ linkages are found, 
+ * then a random sample of +linkage_limit+ is chosen for post-processing. When 
+ * this happen a warning is displayed at verbosity levels greater than 1.
+ */
+static VALUE
+rlink_parseopts_get_linkage_limit( self )
+	VALUE self;
+{
+	Parse_Options opts = get_parseopts( self );
+	int rval;
+
+	rval = parse_options_get_linkage_limit( opts );
+	return INT2FIX( rval );
+}
+
+/*
+ * disjunct_cost=( int )
+ * --
+ * Determines the maximum disjunct cost used during parsing, where the cost 
+ * of a disjunct is equal to the maximum cost of all of its connectors. The 
+ * default is that all disjuncts, no matter what their cost, are considered.
+ */
+static VALUE
+rlink_parseopts_set_disjunct_cost( self, disjunct_cost )
+	VALUE self, disjunct_cost;
+{
+	Parse_Options opts = get_parseopts( self );
+	parse_options_set_disjunct_cost( opts, NUM2INT(disjunct_cost) );
+	return disjunct_cost;
+}
+
+/*
+ * disjunct_cost => int
+ * --
+ * Get the maximum disjunct cost used during parsing.
+ */
+static VALUE
+rlink_parseopts_get_disjunct_cost( self )
+	VALUE self;
+{
+	Parse_Options opts = get_parseopts( self );
+	int rval;
+
+	rval = parse_options_get_disjunct_cost( opts );
+	return INT2FIX( rval );
+}
+
+/*
+ * min_null_count=( null_count )
+ * --
+ * Set the minimum of null links that a parse can have. A call to 
+ * LinkParser::Sentence#parse will find all linkages having the minimum 
+ * number of null links within the range specified by this parameter.
+ */
+static VALUE
+rlink_parseopts_set_min_null_count( self, null_count )
+	VALUE self, null_count;
+{
+	Parse_Options opts = get_parseopts( self );
+	parse_options_set_min_null_count( opts, NUM2INT(null_count) );
+	return null_count;
+}
+
+/*
+ * min_null_count => fixnum
+ * --
+ * Get the minimum of null links that a parse can have.
+ */
+static VALUE
+rlink_parseopts_get_min_null_count( self )
+	VALUE self;
+{
+	Parse_Options opts = get_parseopts( self );
+	int rval;
+
+	rval = parse_options_get_min_null_count( opts );
+	return INT2FIX( rval );
+}
+
+/*
+ * max_null_count=( null_count )
+ * --
+ * Set the max_null_count option to the specified value.
+ */
+static VALUE
+rlink_parseopts_set_max_null_count( self, null_count )
+	VALUE self, null_count;
+{
+	Parse_Options opts = get_parseopts( self );
+	parse_options_set_max_null_count( opts, NUM2INT(null_count) );
+	return null_count;
+}
+
+/*
+ * max_null_count
+ * --
+ * Get the value of the max_null_count option.
+ */
+static VALUE
+rlink_parseopts_get_max_null_count( self )
+	VALUE self;
+{
+	Parse_Options opts = get_parseopts( self );
+	int rval;
+
+	rval = parse_options_get_max_null_count( opts );
+	return INT2FIX( rval );
+}
+
+/*
+ * null_block=( null_block )
+ * --
+ * Set the null_block option to the specified value.
+ */
+static VALUE
+rlink_parseopts_set_null_block( self, null_block )
+	VALUE self, null_block;
+{
+	Parse_Options opts = get_parseopts( self );
+	parse_options_set_null_block( opts, NUM2INT(null_block) );
+	return null_block;
+}
+
+/*
+ * null_block
+ * --
+ * Get the value of the null_block option.
+ */
+static VALUE
+rlink_parseopts_get_null_block( self )
+	VALUE self;
+{
+	Parse_Options opts = get_parseopts( self );
+	int rval;
+
+	rval = parse_options_get_null_block( opts );
+	return INT2FIX( rval );
+}
+
+/*
+ * islands_ok=( islands_ok )
+ * --
+ * Set the islands_ok option to the specified value.
+ */
+static VALUE
+rlink_parseopts_set_islands_ok( self, islands_ok )
+	VALUE self, islands_ok;
+{
+	Parse_Options opts = get_parseopts( self );
+	parse_options_set_islands_ok( opts, RTEST(islands_ok) );
+	return islands_ok;
+}
+
+/*
+ * islands_ok
+ * --
+ * Get the value of the islands_ok option.
+ */
+static VALUE
+rlink_parseopts_get_islands_ok_p( self )
+	VALUE self;
+{
+	Parse_Options opts = get_parseopts( self );
+	int rval;
+
+	rval = parse_options_get_islands_ok( opts );
+	return rval ? Qtrue : Qfalse;
+}
+
+/*
+ * short_length=( short_length )
+ * --
+ * Set the short_length option to the specified value.
+ */
+static VALUE
+rlink_parseopts_set_short_length( self, short_length )
+	VALUE self, short_length;
+{
+	Parse_Options opts = get_parseopts( self );
+	parse_options_set_short_length( opts, NUM2INT(short_length) );
+	return short_length;
+}
+
+/*
+ * short_length
+ * --
+ * Get the value of the short_length option.
+ */
+static VALUE
+rlink_parseopts_get_short_length( self )
+	VALUE self;
+{
+	Parse_Options opts = get_parseopts( self );
+	int rval;
+
+	rval = parse_options_get_short_length( opts );
+	return INT2FIX( rval );
+}
+
+/*
+ * max_memory=( mem )
+ * --
+ * Set the max_memory option to the specified value.
+ */
+static VALUE
+rlink_parseopts_set_max_memory( self, mem )
+	VALUE self, mem;
+{
+	Parse_Options opts = get_parseopts( self );
+	parse_options_set_max_memory( opts, NUM2INT(mem) );
+	return mem;
+}
+
+/*
+ * max_memory
+ * --
+ * Get the value of the max_memory option.
+ */
+static VALUE
+rlink_parseopts_get_max_memory( self )
+	VALUE self;
+{
+	Parse_Options opts = get_parseopts( self );
+	int rval;
+
+	rval = parse_options_get_max_memory( opts );
+	return INT2FIX( rval );
+}
+
+/*
+ * max_sentence_length=( len )
+ * --
+ * Set the max_sentence_length option to the specified value.
+ */
+static VALUE
+rlink_parseopts_set_max_sentence_length( self, len )
+	VALUE self, len;
+{
+	Parse_Options opts = get_parseopts( self );
+	parse_options_set_max_sentence_length( opts, NUM2INT(len) );
+	return len;
+}
+
+/*
+ * max_sentence_length
+ * --
+ * Get the value of the max_sentence_length option.
+ */
+static VALUE
+rlink_parseopts_get_max_sentence_length( self )
+	VALUE self;
+{
+	Parse_Options opts = get_parseopts( self );
+	int rval;
+
+	rval = parse_options_get_max_sentence_length( opts );
+	return INT2FIX( rval );
+}
+
+/*
+ * max_parse_time=( secs )
+ * --
+ * Set the max_parse_time option to the specified value.
+ */
+static VALUE
+rlink_parseopts_set_max_parse_time( self, secs )
+	VALUE self, secs;
+{
+	Parse_Options opts = get_parseopts( self );
+	parse_options_set_max_parse_time( opts, NUM2INT(secs) );
+	return secs;
+}
+
+/*
+ * max_parse_time
+ * --
+ * Get the value of the max_parse_time option.
+ */
+static VALUE
+rlink_parseopts_get_max_parse_time( self )
+	VALUE self;
+{
+	Parse_Options opts = get_parseopts( self );
+	int rval;
+
+	rval = parse_options_get_max_parse_time( opts );
+	return INT2FIX( rval );
+}
+
+/*
+ * screen_width=( val )
+ * --
+ * Set the screen_width option to the specified value.
+ */
+static VALUE
+rlink_parseopts_set_screen_width( self, val )
+	VALUE self, val;
+{
+	Parse_Options opts = get_parseopts( self );
+	parse_options_set_screen_width( opts, NUM2INT(val) );
+	return val;
+}
+
+/*
+ * screen_width
+ * --
+ * Get the value of the screen_width option.
+ */
+static VALUE
+rlink_parseopts_get_screen_width( self )
+	VALUE self;
+{
+	Parse_Options opts = get_parseopts( self );
+	int rval;
+
+	rval = parse_options_get_screen_width( opts );
+	return INT2FIX( rval );
+}
+
+/*
+ * allow_null=( val )
+ * --
+ * Set the allow_null option to the specified value.
+ */
+static VALUE
+rlink_parseopts_set_allow_null( self, val )
+	VALUE self, val;
+{
+	Parse_Options opts = get_parseopts( self );
+	parse_options_set_allow_null( opts, RTEST(val) );
+	return val;
+}
+
+/*
+ * allow_null?
+ * --
+ * Get the value of the allow_null option.
+ */
+static VALUE
+rlink_parseopts_get_allow_null_p( self )
+	VALUE self;
+{
+	Parse_Options opts = get_parseopts( self );
+	int rval;
+
+	rval = parse_options_get_allow_null( opts );
+	return rval ? Qtrue : Qfalse;
+}
+
+/*
+ * display_walls=( val )
+ * --
+ * Set the display_walls option to the specified value.
+ */
+static VALUE
+rlink_parseopts_set_display_walls( self, val )
+	VALUE self, val;
+{
+	Parse_Options opts = get_parseopts( self );
+	parse_options_set_display_walls( opts, RTEST(val) );
+	return val;
+}
+
+/*
+ * display_walls
+ * --
+ * Get the value of the display_walls option.
+ */
+static VALUE
+rlink_parseopts_get_display_walls_p( self )
+	VALUE self;
+{
+	Parse_Options opts = get_parseopts( self );
+	int rval;
+
+	rval = parse_options_get_display_walls( opts );
+	return rval ? Qtrue : Qfalse;
+}
+
+/*
+ * all_short_connectors=( val )
+ * --
+ * Set the all_short_connectors option to the specified value.
+ */
+static VALUE
+rlink_parseopts_set_all_short_connectors( self, val )
+	VALUE self, val;
+{
+	Parse_Options opts = get_parseopts( self );
+	parse_options_set_all_short_connectors( opts, RTEST(val) );
+	return val;
+}
+
+/*
+ * all_short_connectors
+ * --
+ * Get the value of the all_short_connectors option.
+ */
+static VALUE
+rlink_parseopts_get_all_short_connectors_p( self )
+	VALUE self;
+{
+	Parse_Options opts = get_parseopts( self );
+	int rval;
+
+	rval = parse_options_get_all_short_connectors( opts );
+	return rval ? Qtrue : Qfalse;
+}
+
+/*
+ * cost_model_type=( cm )
+ * --
+ * Set the cost_model_type option to the specified value.
+ */
+static VALUE
+rlink_parseopts_set_cost_model_type( self, cm )
+	VALUE self, cm;
+{
+	Parse_Options opts = get_parseopts( self );
+	parse_options_set_cost_model_type( opts, NUM2INT(cm) );
+	return cm;
+}
+
+/*
+ * cost_model_type
+ * --
+ * Get the value of the cost_model_type option.
+ */
+/*
+
+There's no actual API function for getting the cost_model_type. I guess if
+there's ever more than one model type defined there will be.
+
+static VALUE
+rlink_parseopts_get_cost_model_type( self )
+	VALUE self;
+{
+	Parse_Options opts = get_parseopts( self );
+	int rval;
+
+	rval = parse_options_get_cost_model_type( opts );
+	return INT2FIX( rval );
+}
+*/
+
+/*
+ * batch_mode=( val )
+ * --
+ * Set the batch_mode option to the specified value.
+ */
+static VALUE
+rlink_parseopts_set_batch_mode( self, val )
+	VALUE self, val;
+{
+	Parse_Options opts = get_parseopts( self );
+	parse_options_set_batch_mode( opts, RTEST(val) );
+	return val;
+}
+
+/*
+ * batch_mode
+ * --
+ * Get the value of the batch_mode option.
+ */
+static VALUE
+rlink_parseopts_get_batch_mode_p( self )
+	VALUE self;
+{
+	Parse_Options opts = get_parseopts( self );
+	int rval;
+
+	rval = parse_options_get_batch_mode( opts );
+	return rval ? Qtrue : Qfalse;
+}
+
+/*
+ * panic_mode=( val )
+ * --
+ * Set the panic_mode option to the specified value.
+ */
+static VALUE
+rlink_parseopts_set_panic_mode( self, val )
+	VALUE self, val;
+{
+	Parse_Options opts = get_parseopts( self );
+	parse_options_set_panic_mode( opts, RTEST(val) );
+	return val;
+}
+
+/*
+ * panic_mode
+ * --
+ * Get the value of the panic_mode option.
+ */
+static VALUE
+rlink_parseopts_get_panic_mode_p( self )
+	VALUE self;
+{
+	Parse_Options opts = get_parseopts( self );
+	int rval;
+
+	rval = parse_options_get_panic_mode( opts );
+	return rval ? Qtrue : Qfalse;
+}
+
+/*
+ * display_on=( val )
+ * --
+ * Set the display_on option to the specified value.
+ */
+static VALUE
+rlink_parseopts_set_display_on( self, val )
+	VALUE self, val;
+{
+	Parse_Options opts = get_parseopts( self );
+	parse_options_set_display_on( opts, RTEST(val) );
+	return val;
+}
+
+/*
+ * display_on
+ * --
+ * Get the value of the display_on option.
+ */
+static VALUE
+rlink_parseopts_get_display_on_p( self )
+	VALUE self;
+{
+	Parse_Options opts = get_parseopts( self );
+	int rval;
+
+	rval = parse_options_get_display_on( opts );
+	return rval ? Qtrue : Qfalse;
+}
+
+/*
+ * display_postscript=( val )
+ * --
+ * Set the display_postscript option to the specified value.
+ */
+static VALUE
+rlink_parseopts_set_display_postscript( self, val )
+	VALUE self, val;
+{
+	Parse_Options opts = get_parseopts( self );
+	parse_options_set_display_postscript( opts, RTEST(val) );
+	return val;
+}
+
+/*
+ * display_postscript
+ * --
+ * Get the value of the display_postscript option.
+ */
+static VALUE
+rlink_parseopts_get_display_postscript_p( self )
+	VALUE self;
+{
+	Parse_Options opts = get_parseopts( self );
+	int rval;
+
+	rval = parse_options_get_display_postscript( opts );
+	return rval ? Qtrue : Qfalse;
+}
+
+/*
+ * display_constituents=( val )
+ * --
+ * Set the display_constituents option to the specified value.
+ */
+static VALUE
+rlink_parseopts_set_display_constituents( self, val )
+	VALUE self, val;
+{
+	Parse_Options opts = get_parseopts( self );
+	parse_options_set_display_constituents( opts, RTEST(val) );
+	return val;
+}
+
+/*
+ * display_constituents
+ * --
+ * Get the value of the display_constituents option.
+ */
+static VALUE
+rlink_parseopts_get_display_constituents_p( self )
+	VALUE self;
+{
+	Parse_Options opts = get_parseopts( self );
+	int rval;
+
+	rval = parse_options_get_display_constituents( opts );
+	return rval ? Qtrue : Qfalse;
+}
+
+/*
+ * display_bad=( val )
+ * --
+ * Set the display_bad option to the specified value.
+ */
+static VALUE
+rlink_parseopts_set_display_bad( self, val )
+	VALUE self, val;
+{
+	Parse_Options opts = get_parseopts( self );
+	parse_options_set_display_bad( opts, RTEST(val) );
+	return val;