Projects
Threads by month
- ----- 2025 -----
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
October 2004
- 11 participants
- 41 discussions
Index: ChangeLog
from Nicolas Pouillard <ertai(a)lrde.epita.fr>
* rcs-wrapper/src, rcs-wrapper, rcs-wrapper/src/news.rb,
* rcs-wrapper/bin/rcsw, rcs-wrapper/bin, rcs-wrapper/src/cvs.rb,
* rcs-wrapper/src/changelog.rb, rcs-wrapper/src/revision.rb,
* rcs-wrapper/src/rcs.rb, rcs-wrapper/src/prcs.rb,
* rcs-wrapper/src/svn.rb, rcs-wrapper/src/message.rb,
* rcs-wrapper/src/mycommit.rb, rcs-wrapper/src/mail.rb,
* rcs-wrapper/src/tools.rb: New.
---
Intro: >
Bon voilà je n'ai pas trop le temps en ce moment de m'occuper de cet outil.
Il est bien commencé et à mon goût déjà utilisable.
Je vais continuer à le debugger, mais en attendant vous pouvez vous amuser
avec.
C'est un wrapper pour les systèmes de versions comme Svn, Cvs, Prcs, Arch...
Il permet donc au minimum de faire tout ce que le système sous-jacent propose,
mais l'avantage est de pouvoir l'étendre facilement.
Exemples d'utilisation:
- Pour plus de transparence on va faire des alias:
genre: alias svn=...../rcsw, idem pour cvs, prcs...
pour cela taper simplement: >
`le_chemin_vers_rcsw/bin/rcsw --mk-alias`
- Les commandes de svn fonctionnent toujours: >
placez vous dans un répertoire svn.
ex: svn status
- Les commandes de base peuvent être surchargées: >
par exemple `svn commit' a un comportement non interactif par défaut.
Mais l'on peut tout de même appeler le véritable `svn commit'.
Pour cela il y a une convention: toutes les méthodes terminant par `_'
sont directement celles du système.
Avec cela on peut vérifier que l'outil est bien devant le vrai svn:
svn status_
- Quelques fonctionnalités:
- Un des principaux avantages est la gestion des erreurs: >
Par exemple on utilise une commande qui commit puis poste une news.
Si le commit réussit et que la news ne passe pas, il suffit de
relancer l'envoi de la news: svn news
En effet chaque méthode peut conserver des fichiers, ces fichiers
commencent par `,'.
- Les alias de méthodes: >
Tout comme svn et cvs il existe des raccourcis pour certaines méthodes
et bien sûr lorsque l'on surcharge une méthode, le raccourci pointe
vers la nouvelle méthode.
- Quelques nouvelles méthodes:
- svn revision: Renvoie le numéro de révision courante
alias: rev
- svn mkchangelog: Génère une entrée de ChangeLog à partir de `status'
alias: mkcl
- svn changelog: Concatène la nouvelle entrée au véritable ChangeLog
alias: cl
- svn message: Crée le contenu du message du mail ou de la news
alias: msg
- svn mail: Envoie un mail.
- svn news: Poste une news.
- Plus facile d'écrire des scripts: >
Lorsque l'on veut automatiser un traitement fait avec un Rcs,
il est généralement plus simple de le faire en script shell
lorsque cela n'excède pas une dixaine de lignes. Après cela certains
avantages des langages de script évolués nous manquent.
Pourtant certaines choses très faciles peuvent devenir plus lourdes:
svn commit => system("svn commit")
Heureusement avec le modèle objet déjà posé cela devient plus
raisonnable, comparez par exemple:
svn commit => svn.commit
svn info | grep '^Revision' | sed s/^Revision: //
=>
svn.info.readlines.grep(/^Revision/)[0].sub(/^Revision: /, '').to_i
- Exemple final: commit complet pour les lrde tools.
commande: svn lrdetools_commit 'votre sujet pour la news'
ensuite: laissez vous guider.
- S'il y a des questions il y aura des réponses.
Index: rcs-wrapper/src/revision.rb
--- rcs-wrapper/src/revision.rb (revision 0)
+++ rcs-wrapper/src/revision.rb (revision 0)
@@ -0,0 +1,19 @@
+# Author:: Nicolas Pouillard <ertai(a)lrde.epita.fr>.
+# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
+# License:: GNU General Public License (GPL).
+
+# $LastChangedBy: ertai $
+# $Id: header 98 2004-09-29 12:07:43Z ertai $
+
+require 'svn'
+require 'stringio'
+
+class Svn
+
+ def revision ( *args )
+ StringIO.new(info.readlines.grep(/^Revision:/)[0].sub(/^Revision: /, ''))
+ end
+
+ alias_command :rev, :revision
+
+end # class Svn
Index: rcs-wrapper/src/mycommit.rb
--- rcs-wrapper/src/mycommit.rb (revision 0)
+++ rcs-wrapper/src/mycommit.rb (revision 0)
@@ -0,0 +1,69 @@
+# Author:: Nicolas Pouillard <ertai(a)lrde.epita.fr>.
+# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
+# License:: GNU General Public License (GPL).
+
+# $LastChangedBy: ertai $
+# $Id: header 98 2004-09-29 12:07:43Z ertai $
+
+require 'rcs'
+
+class Rcs
+
+ def edit! ( *files )
+ system(ENV['EDITOR'], *files)
+ end
+
+ def common_commit! ( *args )
+
+ begin
+ changelog!(*args)
+ rescue MustBeFilled => ex
+ edit! ex.file
+ end
+
+ message!(*args)
+
+ edit! @@message
+
+ changelog!(*args)
+
+ #pager! diff
+ #pager! status
+
+ args << 'ChangeLog' unless args.grep(/^[^-]/).empty?
+
+ commit!(*args)
+
+ return self.revision.readline.to_i
+
+ end
+ protected :common_commit!
+
+
+ def lrdetools_commit! ( s, *args )
+
+ rev = common_commit!(*args)
+
+ s = "LT #{rev}: #{s}"
+
+ news(:groups => ['lrde.proj'], :subject => s)
+
+ @@message.delete
+
+ end
+ alias_command :ltci, :lrdetools_commit
+
+ def test_commit! ( s, *args )
+
+ rev = common_commit!(*args)
+
+ s = "Test #{rev}: #{s}"
+
+# news(:groups => ['local.test'], :subject => s)
+ mail(:to => ['ertai(a)lrde.epita.fr'], :subject => s)
+
+ @@message.delete
+
+ end
+
+end # class Rcs
Index: rcs-wrapper/src/tools.rb
--- rcs-wrapper/src/tools.rb (revision 0)
+++ rcs-wrapper/src/tools.rb (revision 0)
@@ -0,0 +1,51 @@
+# Author:: Nicolas Pouillard <ertai(a)lrde.epita.fr>.
+# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
+# License:: GNU General Public License (GPL).
+
+# $LastChangedBy: ertai $
+# $Id: header 98 2004-09-29 12:07:43Z ertai $
+
+
+module WarnAndError
+
+ def warn ( aString )
+ print "#{RCSW}: warning: ", aString, "\n"
+ end
+
+ def error ( aString )
+ print "#{RCSW}: error: ", aString, "\n"
+ end
+
+ def debug ( aString )
+ print "#{RCSW}: debug: ", aString, "\n"
+ end
+
+end # module WarnAndError
+
+
+class IO
+ include WarnAndError
+end # class IO
+
+
+require 'stringio'
+class StringIO
+ include WarnAndError
+end # class StringIO
+
+
+require 'yaml'
+module YAML
+
+ def self.chop_header ( io )
+ aStr = io.gets
+ raise Exception, "First line is not valid: `#{aLine}'" unless aStr =~ /^---/
+ io.each do |aLine|
+ break if aLine =~ /^---/
+ aStr += aLine
+ end
+ YAML::load(aStr)
+ end
+
+end # module YAML
+
Index: rcs-wrapper/src/mail.rb
--- rcs-wrapper/src/mail.rb (revision 0)
+++ rcs-wrapper/src/mail.rb (revision 0)
@@ -0,0 +1,77 @@
+# Author:: Nicolas Pouillard <ertai(a)lrde.epita.fr>.
+# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
+# License:: GNU General Public License (GPL).
+
+# $LastChangedBy: ertai $
+# $Id: header 98 2004-09-29 12:07:43Z ertai $
+
+require 'rcs'
+require 'tools'
+
+class Rcs
+
+ @@mail = Pathname.new(',mail')
+
+ def parse_mail_options ( *args )
+ require 'optparse'
+ result =
+ {
+ :from => EMAIL, #FULL_EMAIL,
+ :to => [],
+ :server => ENV['SMTPSERVER'] || 'localhost',
+ }
+ if !args.nil? and !args.empty? and args[0].is_a?(Hash)
+ args[0].each do |k,v|
+ result[k] = v
+ end
+ return result
+ end
+ OptionParser.new do |opts|
+ opts.separator ''
+ opts.on('-t', '--mail-to NAME', 'Choose a recipient') do |aString|
+ result[:to] << aString
+ end
+ opts.on('-s', '--server NAME', 'Choose a mail server') do |aString|
+ result[:server] = aString
+ end
+ opts.on('-S', '--subject NAME', 'Choose your mail subject') do |aString|
+ result[:subject] = aString.sub(/\.?$/, '.')
+ end
+ opts.on_tail('-h', '--help', 'Show this message') do
+ puts opts
+ exit
+ end
+ end.parse!(args)
+ raise Failure, 'No recipents' if result[:to].empty?
+ raise Failure, 'No mail server' if result[:server].nil?
+ raise Failure, 'No mail subject' if result[:subject].nil?
+ result
+ end
+ protected :parse_mail_options
+
+ #
+ # Mail.
+ #
+ def mail ( *args )
+
+ print_body(@@mail, parse_mail_options(*args)) unless @@mail.exist?
+
+ @@mail.open('r') do |file|
+ opt = YAML::chop_header(file)
+ STDERR.puts "Smtp Server: #{opt[:server]}"
+ require 'net/smtp'
+ Net::SMTP.start(opt[:server], 25) do |smtp|
+ smtp.open_message_stream(EMAIL, opt[:to]) do |f|
+ f.print "From: #{opt[:from]}\n"
+ f.print "Subject: #{opt[:subject]}\n"
+ f.print "To: #{opt[:to].join(', ')}\n"
+ f.print "\n"
+ file.each { |line| f.print line }
+ end
+ end
+ end
+ @@mail.delete
+ ['Mail: Sent.']
+ end
+
+end # class Rcs
Index: rcs-wrapper/src/message.rb
--- rcs-wrapper/src/message.rb (revision 0)
+++ rcs-wrapper/src/message.rb (revision 0)
@@ -0,0 +1,44 @@
+# Author:: Nicolas Pouillard <ertai(a)lrde.epita.fr>.
+# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
+# License:: GNU General Public License (GPL).
+
+# $LastChangedBy: ertai $
+# $Id: header 98 2004-09-29 12:07:43Z ertai $
+
+require 'rcs'
+require 'changelog'
+
+class Rcs
+
+ @@message = Pathname.new(',message')
+
+ def print_body ( file, options )
+ STDERR.warn "Creating a new `#{file}' file"
+ file.open('w') do |f|
+ f.puts options.to_yaml
+ f.puts '---'
+ f.puts
+ message.each do |line|
+ f.print line
+ end
+ end
+ end
+ private :print_body
+
+ def message ( *args )
+ unless @@message.exist?
+ cl = mkchangelog
+ @@message.open('w') do |f|
+ f.puts 'Index: ChangeLog'
+ cl.each { |line| f.print line.sub(/^\d+-\d+-\d+/, 'from') }
+ f.puts
+ # FIXME: need to remove the ChangeLog entry in diff.
+ diff.each { |line| f.print line unless line =~ /^=+$/ }
+ end
+ end
+ @@message.open('r')
+ end
+
+ alias_command :msg, :message
+
+end # class Rcs
Index: rcs-wrapper/src/svn.rb
--- rcs-wrapper/src/svn.rb (revision 0)
+++ rcs-wrapper/src/svn.rb (revision 0)
@@ -0,0 +1,41 @@
+# Author:: Nicolas Pouillard <ertai(a)lrde.epita.fr>.
+# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
+# License:: GNU General Public License (GPL).
+
+# $LastChangedBy: ertai $
+# $Id: header 98 2004-09-29 12:07:43Z ertai $
+
+require 'rcs'
+require 'tools'
+
+class Svn < Rcs
+
+ class Failure < Rcs::Failure
+ end
+
+ def initialize ( aCmd='svn' )
+ super
+ end
+
+ %w[ blame copy list move switch revert info
+ propdel propget proplist propset mkdir ].each do |m|
+ add_basic_method(m)
+ end
+
+ add_basic_method!(:propedit)
+
+ def commit! ( *args )
+
+ changelog!
+
+ if run!('commit', '--non-interactive', '-F', @@add_cl, *args)
+ STDERR.puts "Deleting junk files..."
+ @@add_cl.delete
+ @@tmp_cl.delete if @@tmp_cl.exist?
+ else
+ raise Failure, 'commit failed'
+ end
+
+ end
+
+end # class Svn
Index: rcs-wrapper/src/changelog.rb
--- rcs-wrapper/src/changelog.rb (revision 0)
+++ rcs-wrapper/src/changelog.rb (revision 0)
@@ -0,0 +1,108 @@
+# Author:: Nicolas Pouillard <ertai(a)lrde.epita.fr>.
+# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
+# License:: GNU General Public License (GPL).
+
+# $LastChangedBy: ertai $
+# $Id: header 98 2004-09-29 12:07:43Z ertai $
+
+require 'rcs'
+require 'svn'
+
+class Svn
+
+ @@file_st =
+ {
+ 'A' => 'New',
+ 'D' => 'Remove',
+ 'M' => ''
+ }
+
+ @@prop_st =
+ {
+ 'M' => 'Changed property'
+ }
+
+ def mkchangelog_from_status ( *args )
+ result = {}
+ status(*args).each do |line|
+ line =~ /^(.)(.).(.).\s*(.*)$/
+ if $1 != '?'
+ file_st, prop_st, copy_st, file = @@file_st[$1], @@prop_st[$2], $3, $4
+ str = ''
+ str += file_st if file_st
+ str += (file_st.nil?) ? prop_st : (', ' + prop_st.downcase) if prop_st
+ result[file] = str
+ end
+ end
+ raise Failure, 'No changes, so no ChangeLog entry.' if result.empty?
+ result
+ end
+ private :mkchangelog_from_status
+
+end # class Svn
+
+class Rcs
+
+ @@cl = Pathname.new('ChangeLog')
+ @@add_cl = Pathname.new(',ChangeLog')
+ @@tmp_cl = Pathname.new(',,ChangeLog')
+
+ class MustBeFilled < Exception
+ attr_reader :file
+ def initialize ( file )
+ @file = file
+ super("You must fill this file: `#{file.to_s}'")
+ end
+ end
+
+ def mkchangelog ( *args )
+ cl = @@add_cl
+
+ if cl.exist?
+ f = cl.open('r')
+ if f.readline !~ /^===/
+ f.rewind
+ return f
+ end
+ f.close
+ else
+ cl_add = mkchangelog_from_status(*args)
+ STDERR.warn "Creating a new `#{cl}' file"
+ cl.open('w') do |f|
+ f.puts '=== Fill this file correctly and remove this line ==='
+ f.puts `date +"%Y-%m-%d #{FULL_EMAIL}"`
+ f.puts
+ cl_add.each do |file, str|
+ f.puts "\t* #{file}: #{str}."
+ end
+ end
+ end
+
+ raise MustBeFilled, cl
+ end
+
+ def changelog! ( *args )
+ unless @@cl.exist?
+ raise Failure, 'No ChangeLog, you are probably not in a valid directory.'
+ end
+
+ if cl = mkchangelog(*args)
+
+ unless @@tmp_cl.exist?
+ STDERR.warn "Move ChangeLog to `#{@@tmp_cl}'"
+ @@cl.rename(@@tmp_cl)
+ end
+
+ @@cl.open('w') do |file|
+ cl.each { |line| file.print line }
+ file.puts
+ IO.foreach(@@tmp_cl) { |line| file.print line }
+ end
+
+ end
+ end
+
+ alias_command :mkcl, :mkchangelog
+ alias_command :cl, :changelog
+
+end # class Rcs
Index: rcs-wrapper/src/prcs.rb
--- rcs-wrapper/src/prcs.rb (revision 0)
+++ rcs-wrapper/src/prcs.rb (revision 0)
@@ -0,0 +1,21 @@
+# Author:: Nicolas Pouillard <ertai(a)lrde.epita.fr>.
+# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
+# License:: GNU General Public License (GPL).
+
+# $LastChangedBy: ertai $
+# $Id: header 98 2004-09-29 12:07:43Z ertai $
+
+require 'rcs'
+
+class Prcs < Rcs
+
+ def initialize ( aCmd='prcs' )
+ super
+ end
+
+ %w[ admin ].each do |m|
+ add_basic_method(m)
+ end
+
+end # class Prcs
+
Index: rcs-wrapper/src/rcs.rb
--- rcs-wrapper/src/rcs.rb (revision 0)
+++ rcs-wrapper/src/rcs.rb (revision 0)
@@ -0,0 +1,155 @@
+# Author:: Nicolas Pouillard <ertai(a)lrde.epita.fr>.
+# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
+# License:: GNU General Public License (GPL).
+
+# $LastChangedBy: ertai $
+# $Id: header 98 2004-09-29 12:07:43Z ertai $
+
+class Class # :nodoc:
+
+ def add_basic_method ( meth )
+ class_eval <<-end_eval
+ def #{meth} ( *args )
+ run("#{meth}", *args)
+ end
+ def #{meth}_ ( *args )
+ run("#{meth}", *args)
+ end
+ end_eval
+ end
+
+ def add_basic_method! ( meth )
+ class_eval <<-end_eval
+ def #{meth}! ( *args )
+ run!("#{meth}", *args)
+ end
+ def #{meth}_! ( *args )
+ run!("#{meth}", *args)
+ end
+ end_eval
+ end
+
+ def alias_command ( m1, m2 )
+ class_eval <<-end_eval
+ def #{m1} ( *args )
+ #{m2}(*args)
+ end
+ def #{m1}_ ( *args )
+ #{m2}_(*args)
+ end
+ def #{m1}! ( *args )
+ #{m2}!(*args)
+ end
+ def #{m1}_! ( *args )
+ #{m2}_!(*args)
+ end
+ end_eval
+ end
+
+end # class Class
+
+# The abstract class for a Rcs wrapper.
+# Conventions:
+# example:
+# svn checkout http://foo.bar/proj # normal command
+# xrcs checkout http://foo.bar/proj # normal
+#
+# checkout
+# checkout_
+# checkout!
+# checkout_!
+#
+class Rcs
+
+ class Failure < Exception
+ end
+
+ def initialize ( aCmd )
+ @cmd = aCmd
+ end
+
+ def common_run ( args )
+ cmd = @cmd + ' ' + args.join(' ')
+ STDERR.debug "running: #{cmd}" if $debug > 1
+ cmd
+ end
+ private :common_run
+
+ def run ( *args )
+ IO.popen(common_run(args))
+ end
+
+ def run! ( *args )
+ system(common_run(args))
+ end
+
+ %w[ checkout delete diff help status log add update ].each do |m|
+ add_basic_method(m)
+ end
+
+ add_basic_method!(:commit)
+
+ def method_missing ( meth, *args )
+ meth = meth.to_s
+ if meth =~ /^(.*)!$/
+ if respond_to? $1
+ send($1, *args).each do |line|
+ puts line
+ end
+ else
+ STDERR.warn "unknown method #{meth}"
+ run!($1.sub(/_$/, ''), *args)
+ end
+ else
+ STDERR.warn "unknown method #{meth}"
+ run(meth.sub(/_$/, ''), *args)
+ end
+ end
+
+ alias_command :ann, :blame
+ alias_command :annotate, :blame
+ alias_command :praise, :blame
+ alias_command :co, :checkout
+ alias_command :ci, :commit
+ alias_command :cp, :copy
+ alias_command :del, :delete
+ alias_command :remove, :delete
+ alias_command :rm, :delete
+ alias_command :di, :diff
+ alias_command :h, :help
+ alias_command :ls, :list
+ alias_command :mv, :move
+ alias_command :rename, :move
+ alias_command :ren, :move
+ alias_command :pdel, :propdel
+ alias_command :pd, :propdel
+ alias_command :pedit, :propedit
+ alias_command :pe, :propedit
+ alias_command :pget, :propget
+ alias_command :pg, :propget
+ alias_command :plist, :proplist
+ alias_command :pl, :proplist
+ alias_command :pset, :propset
+ alias_command :ps, :propset
+ alias_command :st, :status
+ alias_command :stat, :status
+ alias_command :sw, :switch
+ alias_command :up, :update
+
+ # Cvs Alias
+ alias_command :new, :add
+ alias_command :rcs, :admin
+ alias_command :get, :checkout
+ alias_command :rlog, :log
+ alias_command :patch, :rdiff
+ alias_command :remove, :delete
+ alias_command :rm, :delete
+ alias_command :rfreeze, :rtag
+ alias_command :freeze, :tag
+
+ # Prcs Alias
+ alias_command :checkin, :commit
+ alias_command :populate, :add
+
+end # class Rcs
+
Index: rcs-wrapper/src/cvs.rb
--- rcs-wrapper/src/cvs.rb (revision 0)
+++ rcs-wrapper/src/cvs.rb (revision 0)
@@ -0,0 +1,21 @@
+# Author:: Nicolas Pouillard <ertai(a)lrde.epita.fr>.
+# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
+# License:: GNU General Public License (GPL).
+
+# $LastChangedBy: ertai $
+# $Id: header 98 2004-09-29 12:07:43Z ertai $
+
+require 'rcs'
+
+class Cvs < Rcs
+
+ def initialize ( aCmd='cvs' )
+ super
+ end
+
+ %w[ rdiff rtag tag ].each do |m|
+ add_basic_method(m)
+ end
+
+end # class Cvs
+
Index: rcs-wrapper/src/news.rb
--- rcs-wrapper/src/news.rb (revision 0)
+++ rcs-wrapper/src/news.rb (revision 0)
@@ -0,0 +1,79 @@
+# Author:: Nicolas Pouillard <ertai(a)lrde.epita.fr>.
+# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
+# License:: GNU General Public License (GPL).
+
+# $LastChangedBy: ertai $
+# $Id: header 98 2004-09-29 12:07:43Z ertai $
+
+require 'tools'
+require 'message'
+
+class Rcs
+
+ @@news = Pathname.new(',news')
+
+ def parse_news_options ( *args )
+ require 'optparse'
+ result =
+ {
+ :from => FULL_EMAIL,
+ :groups => [],
+ :server => ENV['NNTPSERVER'],
+ }
+ if !args.nil? and !args.empty? and args[0].is_a?(Hash)
+ args[0].each do |k,v|
+ result[k] = v
+ end
+ return result
+ end
+ OptionParser.new do |opts|
+ opts.separator ''
+ opts.on('-g', '--group NAME', 'Choose a news group') do |aString|
+ result[:groups] << aString
+ end
+ opts.on('-s', '--server NAME', 'Choose a news server') do |aString|
+ result[:server] = aString
+ end
+ opts.on('-S', '--subject NAME', 'Choose your news subject') do |aString|
+ result[:subject] = aString
+ end
+ opts.on_tail('-h', '--help', 'Show this message') do
+ puts opts
+ exit
+ end
+ end.parse!(args)
+ raise Failure, 'No news group' if result[:groups].empty?
+ raise Failure, 'No news server' if result[:server].nil?
+ raise Failure, 'No news subject' if result[:subject].nil?
+ result
+ end
+ protected :parse_news_options
+
+ #
+ # Post the news.
+ #
+ def news ( *args )
+ print_body(@@news, parse_news_options(*args)) unless @@news.exist?
+
+ @@news.open('r') do |file|
+ opt = YAML::chop_header(file)
+ STDERR.puts "Nntp Server: #{opt[:server]}"
+ require 'socket'
+ TCPSocket.open(opt[:server], 119) do |f|
+ f.puts 'post'
+ f.puts "Newsgroups: #{opt[:groups].join(', ')}"
+ f.puts "From: #{opt[:from]}"
+ f.puts "Subject: #{opt[:subject]}"
+ f.puts
+ file.each do |line|
+ f.print line.gsub(/^\./, ' .')
+ end
+ f.puts '.'
+ f.puts 'quit'
+ end
+ end
+ @@news.delete
+ StringIO.new('News: Sent.')
+ end
+
+end # class Rcs
Index: rcs-wrapper/bin/rcsw
--- rcs-wrapper/bin/rcsw (revision 0)
+++ rcs-wrapper/bin/rcsw (revision 0)
@@ -0,0 +1,75 @@
+#!/usr/bin/env ruby
+# Author:: Nicolas Pouillard <ertai(a)lrde.epita.fr>.
+# Copyright:: Copyright (c) 2004 LRDE. All rights reserved.
+# License:: GNU General Public License (GPL).
+
+# $LastChangedBy: ertai $
+# $Id: header 98 2004-09-29 12:07:43Z ertai $
+
+
+# rcsw : The rcs wrapper.
+#
+# rcsw is a wrapper over any revision control system.
+
+require 'pathname'
+
+RCSW_PATH = Pathname.new(__FILE__).expand_path
+RCSW_DIR, RCSW = RCSW_PATH.split
+SRC = RCSW_DIR + '..' + 'src'
+$: << SRC
+
+
+if ARGV == ['--mk-alias']
+ %w[ svn cvs prcs ].each { |x| puts "alias #{x}=#{RCSW_PATH}" }
+ exit
+end
+
+$debug = ENV['RCSW_DEBUG'].to_i
+
+FULLNAME = ENV['FULLNAME'] || (Etc.getpwnam ENV['USER']).gecos
+EMAIL = ENV['EMAIL']
+FULL_EMAIL = "#{FULLNAME} <#{EMAIL}>"
+if FULLNAME.nil? or EMAIL.nil?
+ STDERR.error 'Need FULLNAME and EMAIL in the environement'
+ exit
+end
+
+Pathname.glob(SRC + '*.rb') do |file|
+ puts file.basename if $debug > 4
+ require file
+end
+
+def guess_rcs
+ if Pathname.new('CVS').directory?
+ Cvs
+ elsif Pathname.new('.svn').directory?
+ Svn
+ elsif Pathname.new('prj').exist?
+ Prcs
+ else
+ raise ArgumentError, 'Can\'t guess your RCS system'
+ end
+end
+
+def main
+ rcs = guess_rcs().new
+
+ if ARGV.empty?
+ meth = :help!
+ else
+ meth = ARGV.shift.sub(/([^!])$/, '\1!')
+ end
+
+ begin
+ rcs.send(meth, *ARGV)
+ rescue Exception
+ raise if $debug > 0
+ STDERR.error $!.to_s.sub(/\.$/, '') unless $!.to_s == 'exit'
+ end
+end
+
+if __FILE__ == $0
+
+ main()
+
+end
Property changes on: rcs-wrapper/bin/rcsw
___________________________________________________________________
Name: svn:executable
+ *
Index: rcs-wrapper/README
--- rcs-wrapper/README (revision 0)
+++ rcs-wrapper/README (revision 0)
@@ -0,0 +1,100 @@
+---
+
+Intro: >
+ Bon voilà je n'ai pas trop le temps en ce moment de m'occuper de cet outil.
+ Il est bien commencé et à mon goût déjà utilisable.
+
+ Je vais continuer à le debugger, mais en attendant vous pouvez vous amuser
+ avec.
+
+ C'est un wrapper pour les systèmes de versions comme Svn, Cvs, Prcs, Arch...
+
+ Il permet donc au minimum de faire tout ce que le système sous-jacent propose,
+ mais l'avantage est de pouvoir l'étendre facilement.
+
+Exemples d'utilisation:
+
+ - Pour plus de transparence on va faire des alias:
+ genre: alias svn=...../rcsw, idem pour cvs, prcs...
+ pour cela taper simplement: >
+ `le_chemin_vers_rcsw/bin/rcsw --mk-alias`
+
+ - Les commandes de svn fonctionnent toujours: >
+ placez vous dans un répertoire svn.
+
+ ex: svn status
+
+ - Les commandes de base peuvent être surchargées: >
+ par exemple `svn commit' a un comportement non interactif par défaut.
+
+ Mais l'on peut tout de même appeler le véritable `svn commit'.
+
+ Pour cela il y a une convention: toutes les méthodes terminant par `_'
+ sont directement celles du système.
+
+ Avec cela on peut vérifier que l'outil est bien devant le vrai svn:
+ svn status_
+
+ - Quelques fonctionnalités:
+
+ - Un des principaux avantages est la gestion des erreurs: >
+
+ Par exemple on utilise une commande qui commit puis poste une news.
+ Si le commit réussit et que la news ne passe pas, il suffit de
+ relancer l'envoi de la news: svn news
+
+ En effet chaque méthode peut conserver des fichiers, ces fichiers
+ commencent par `,'.
+
+ - Les alias de méthodes: >
+
+ Tout comme svn et cvs il existe des raccourcis pour certaines méthodes
+ et bien sûr lorsque l'on surcharge une méthode, le raccourci pointe
+ vers la nouvelle méthode.
+
+ - Quelques nouvelles méthodes:
+
+ - svn revision: Renvoie le numéro de révision courante
+ alias: rev
+
+ - svn mkchangelog: Génère une entrée de ChangeLog à partir de `status'
+ alias: mkcl
+
+ - svn changelog: Concatène la nouvelle entrée au véritable ChangeLog
+ alias: cl
+
+ - svn message: Crée le contenu du message du mail ou de la news
+ alias: msg
+
+ - svn mail: Envoie un mail.
+
+ - svn news: Poste une news.
+
+ - Plus facile d'écrire des scripts: >
+
+ Lorsque l'on veut automatiser un traitement fait avec un Rcs,
+ il est généralement plus simple de le faire en script shell
+ lorsque cela n'excède pas une dixaine de lignes. Après cela certains
+ avantages des langages de script évolués nous manquent.
+ Pourtant certaines choses très faciles peuvent devenir plus lourdes:
+ svn commit => system("svn commit")
+
+ Heureusement avec le modèle objet déjà posé cela devient plus
+ raisonnable, comparez par exemple:
+
+ svn commit => svn.commit
+
+ svn info | grep '^Revision' | sed s/^Revision: //
+
+ =>
+
+ svn.info.readlines.grep(/^Revision/)[0].sub(/^Revision: /, '').to_i
+
+ - Exemple final: commit complet pour les lrde tools.
+
+ commande: svn lrdetools_commit 'votre sujet pour la news'
+
+ ensuite: laissez vous guider.
+
+ - S'il y a des questions il y aura des réponses.
+
3
9
`-g' (without glib) was prefered to `-G' in reference to gcc's
`-w' option (without warning). If anyone here objects to this, speak
now, or forever hold your peace.
Index: ChangeLog
from Benoit Perrot <benoit(a)lrde.epita.fr>
* monoburg.c: Emit code to generate a file that does not need glib to
compile. Add `-g' option to control this emission.
Index: monoburg.c
--- monoburg.c (revision 1)
+++ monoburg.c (revision 2)
@@ -27,6 +27,7 @@
static FILE *deffd;
static FILE *cfd;
+static gboolean with_glib = TRUE;
static int dag_mode = 0;
static int predefined_terms = 0;
static int default_cost = 0;
@@ -268,8 +269,113 @@
{
GList *l;
+ if (with_glib) {
output ("#include <glib.h>\n");
output ("\n");
+ }
+ else {
+ output ("#ifndef guint8\n");
+ output ("# define guint8 unsigned char\n");
+ output ("#endif /* !guint8 */\n");
+ output ("#ifndef guint16\n");
+ output ("# define guint16 unsigned short\n");
+ output ("#endif /* !guint16 */\n");
+ output ("#ifndef gpointer\n");
+ output ("# define gpointer void*\n");
+ output ("#endif /* !gpointer */\n");
+ output ("\n");
+
+ output ("#ifndef g_new\n");
+ output ("static void *\n");
+ output ("mono_burg_xmalloc_ (size_t size)\n");
+ output ("{\n");
+ output (" void *p;\n");
+ output ("\n");
+ output (" p = malloc (size);\n");
+ output (" if (!p) {\n");
+ output (" fprintf (stderr, \"Not enough memory\\n\");\n");
+ output (" exit (1);\n");
+ output (" }\n");
+ output (" return p;\n");
+ output ("}\n");
+ output ("# define g_new(struct_type, n_structs) ((struct_type *) mono_burg_xmalloc_ (sizeof(struct_type) * n_structs))\n");
+ output ("#endif /* !g_new */\n");
+ output ("\n");
+
+ output ("#ifndef g_new0\n");
+ output ("static void *\n");
+ output ("mono_burg_xcalloc_ (size_t nmemb, size_t size)\n");
+ output ("{\n");
+ output (" void *p;\n");
+ output ("\n");
+ output (" p = calloc (nmemb, size);\n");
+ output (" if (!p) {\n");
+ output (" fprintf (stderr, \"Not enough memory\\n\");\n");
+ output (" exit (1);\n");
+ output (" }\n");
+ output (" return p;\n");
+ output ("}\n");
+ output ("#define g_new0(struct_type, n_structs) ((struct_type *) mono_burg_xcalloc_(1, sizeof(struct_type) * n_structs))\n");
+ output ("#endif /* !g_new0 */\n");
+ output ("\n");
+
+ output ("#if !defined(g_error) || !defined(g_warning)\n");
+ output ("# include <stdarg.h>\n");
+ output ("#endif /* !defined(g_error) || !defined(g_warning) */\n");
+
+ output ("#ifndef g_error\n");
+ output ("static int\n");
+ output ("mono_burg_error_ (const char *format, ...)\n");
+ output ("{\n");
+ output (" int n = 0;\n");
+ output (" va_list ap;\n");
+ output ("\n");
+ output (" n = fprintf (stderr, \"Error: \");\n");
+ output (" va_start (ap, format);\n");
+ output (" n += vfprintf (stderr, format, ap);\n");
+ output (" va_end (ap);\n");
+ output ("\n");
+ output (" return n;\n");
+ output ("}\n");
+ output ("# define g_error mono_burg_error_\n");
+ output ("#endif /* !g_error */\n");
+
+ output ("#ifndef g_warning\n");
+ output ("static int\n");
+ output ("mono_burg_warning_ (const char *format, ...)\n");
+ output ("{\n");
+ output (" int n = 0;\n");
+ output (" va_list ap;\n");
+ output ("\n");
+ output (" n = fprintf (stderr, \"Warning: \");\n");
+ output (" va_start (ap, format);\n");
+ output (" n += vfprintf (stderr, format, ap);\n");
+ output (" va_end (ap);\n");
+ output ("\n");
+ output (" return n;\n");
+ output ("}\n");
+ output ("# define g_warning mono_burg_warning_\n");
+ output ("#endif /* !g_warning */\n");
+ output ("\n");
+
+ output ("#ifndef g_assert\n");
+ output ("# include <assert.h>\n");
+ output ("# define g_assert assert\n");
+ output ("#endif /* !g_assert */\n");
+ output ("\n");
+
+ output ("#ifndef g_return_val_if_fail\n");
+ output ("# ifdef NDEBUG\n");
+ output ("# define g_return_val_if_fail(expr, val)\n");
+ output ("# else /* !NDEBUG */\n");
+ output ("# define g_return_val_if_fail(expr, val) do { if (! (expr)) return val; } while (0)\n");
+ output ("# endif /* NDEBUG */\n");
+ output ("#endif /* !g_return_val_if_fail */\n");
+ output ("#ifndef g_assert_not_reached\n");
+ output ("# define g_assert_not_reached(X) assert (!\"Should not be there\")\n");
+ output ("#endif /* !g_assert_not_reached */\n");
+ output ("\n");
+ }
output ("#ifndef MBTREE_TYPE\n#error MBTREE_TYPE undefined\n#endif\n");
output ("#ifndef MBTREE_OP\n#define MBTREE_OP(t) ((t)->op)\n#endif\n");
@@ -1020,6 +1126,8 @@
} else if (argv [i][1] == 'D') {
g_hash_table_insert (definedvars, &argv [i][2],
GUINT_TO_POINTER (1));
+ } else if (argv [i][1] == 'g') {
+ with_glib = FALSE;
} else {
usage ();
}
2
3

MESSAGE NOT DELIVERED: do you want viagra? i selling some.. cheap?
by ferguson@resortnetmeetings.com 13 Oct '04
by ferguson@resortnetmeetings.com 13 Oct '04
13 Oct '04
Your message could not be delivered. The User is out of space. Please try to send your message again at a later time.
1
0
Index: ChangeLog
from Benoit Perrot <benoit(a)lrde.epita.fr>
* TODO: New.
2004-10-13 Benoit Perrot <benoit(a)lrde.epita.fr>
Index: TODO
--- TODO (revision 0)
+++ TODO (revision 4)
@@ -0,0 +1,20 @@
+ MonoBURG
+ ********
+General
+=======
+
+* Make monoburg output C++ friendly.
+
+* Fix monoburg scanner (do not use fixed-length strings, etc.).
+
+* Enhance error detection in input.
+
+Suggestions
+===========
+
+* Suggested by Akim Demaille:
+ The macros emited to compensate glib might be grouped in a single string,
+ defined in an external file `/usr/share/monoburg/monoburg-header.h', then
+ output by a single call to output().
+
+ This is nicer but it needs an external file to be installed.
1
0
Index: ChangeLog
from Benoit Perrot <benoit(a)lrde.epita.fr>
* monoburg.c: Emit `stdio.h' and `stdlib.h' inclusions when `-g'
is specified to kill warnings.
2004-10-13 Benoit Perrot <benoit(a)lrde.epita.fr>
Index: monoburg.c
--- monoburg.c (revision 2)
+++ monoburg.c (revision 3)
@@ -285,6 +285,11 @@
output ("#endif /* !gpointer */\n");
output ("\n");
+ output ("#if !defined(g_new) || !defined(g_new0)\n");
+ output ("# include <stdio.h>\n");
+ output ("# include <stdlib.h>\n");
+ output ("#endif /* !defined(g_new) || !defined(g_new0) */\n");
+
output ("#ifndef g_new\n");
output ("static void *\n");
output ("mono_burg_xmalloc_ (size_t size)\n");
@@ -320,6 +325,7 @@
output ("\n");
output ("#if !defined(g_error) || !defined(g_warning)\n");
+ output ("# include <stdio.h>\n");
output ("# include <stdarg.h>\n");
output ("#endif /* !defined(g_error) || !defined(g_warning) */\n");
1
0
Index: ChangeLog
from Nicolas Pouillard <ertai(a)lrde.epita.fr>
* rcs-wrapper/src/message.rb: Fix a bug with mkchangelog call.
* rcs-wrapper/src/mail.rb: Use StringIO for the final message.
Index: rcs-wrapper/src/message.rb
--- rcs-wrapper/src/message.rb (revision 114)
+++ rcs-wrapper/src/message.rb (working copy)
@@ -27,13 +27,13 @@
def message ( *args )
unless @@message.exist?
- cl = mkchangelog
+ cl = mkchangelog(*args)
@@message.open('w') do |f|
f.puts 'Index: ChangeLog'
cl.each { |line| f.print line.sub(/^\d+-\d+-\d+/, 'from') }
f.puts
# FIXME: need to remove the ChangeLog entry in diff.
- diff.each { |line| f.print line unless line =~ /^=+$/ }
+ diff(*args).each { |line| f.print line unless line =~ /^=+$/ }
end
end
@@message.open('r')
Index: rcs-wrapper/src/mail.rb
--- rcs-wrapper/src/mail.rb (revision 114)
+++ rcs-wrapper/src/mail.rb (working copy)
@@ -16,7 +16,7 @@
require 'optparse'
result =
{
- :from => EMAIL, #FULL_EMAIL,
+ :from => FULL_EMAIL,
:to => [],
:server => ENV['SMTPSERVER'] || 'localhost',
}
@@ -71,7 +71,7 @@
end
end
@@mail.delete
- ['Mail: Sent.']
+ StringIO.new('Mail: Sent.')
end
end # class Rcs
1
0

09 Oct '04
Ce message n'a pas été remis pour la raison suivante :
Les adresses de destination suivantes sont inconnues (vérifiez-les
puis renvoyez le message) :
SMTP <lipe(a)terra.es>
Veuillez répondre à<postmaster(a)teleline.es>
si vous pensez que ce message n'est pas valide.
1
0
Index: ChangeLog
from Benoit Perrot <benoit(a)lrde.epita.fr>
* monoburg.y: Rename to...
* parser.y: This, and let automake automaticaly invoke bison to
create `parser.c'.
* Makefile.am: Let autoconf add the correct extension to the
generated binary. Distribute `sample.brg' as a test.
* config/Makefile.am: New.
* configure.ac: New.
2004-06-24 David Waite <mass(a)akuma.org>
* monoburg.c: change to C90-style comments from C99/C++-style
Wed Apr 14 12:40:54 CEST 2004 Paolo Molaro <lupus(a)ximian.com>
* monoburg.c, monoburg.h, monoburg.y: changed the grammar so that
the same emit code can be easily associated with multiple rules.
Coalesce identical emit functions to reduce code size (10 KB - 10 % -
with the current unchanged x86 JIT rules).
2002-10-28 Dietmar Maurer <dietmar(a)ximian.com>
* monoburg.c (emit_state): use 16bit values for registers, removed
reg3 and spilled flag.
2002-10-17 Dietmar Maurer <dietmar(a)ximian.com>
* monoburg.y: added missing semicolon
2002-10-11 Dietmar Maurer <dietmar(a)ximian.com>
* monoburg.c (emit_tree_match): omit unnecessary compare
(emit_label_func): make it possible to print operator names in
error messages.
2002-10-09 Dietmar Maurer <dietmar(a)ximian.com>
* monoburg.c (check_result): emit a warning instead of an error
2002-10-03 Dietmar Maurer <dietmar(a)ximian.com>
* monoburg.c: added new %termprefix mode
2002-09-30 Dietmar Maurer <dietmar(a)ximian.com>
* monoburg.c (main): add option to specify default costs, added
experimental code to handle several input files.
2002-09-26 Dietmar Maurer <dietmar(a)ximian.com>
* monoburg.c (emit_state): include additional fields to handle
register allocation in dag_mode
2002-09-25 Dietmar Maurer <dietmar(a)ximian.com>
* added -p and -e options. monoburg is now able to work with DAGs.
2002-04-20 Dietmar Maurer <dietmar(a)ximian.com>
* monoburg.y (yylex): bug fix in number parsing
2002-04-12 Gonzalo Paniagua Javier <gonzalo(a)ximian.com>
* monoburg.c: added option -s to specify the c source file for output.
2002-04-11 Gonzalo Paniagua Javier <gonzalo(a)ximian.com>
* monoburg.c: added a default handler for warning messages that just
output the messages to stderr instead of stdout.
Mon Feb 18 14:28:10 CET 2002 Paolo Molaro <lupus(a)ximian.com>
* Makefile.am: fix compatibility problem with automake 1.4.
Fri Feb 15 14:20:30 CET 2002 Paolo Molaro <lupus(a)ximian.com>
* Makefile.am: avoid automake for build on host stuff.
Fri Feb 8 12:31:40 CET 2002 Paolo Molaro <lupus(a)ximian.com>
* monoburg.c: make generated arrays const, so that they are shared.
Fri Feb 1 15:14:16 CET 2002 Paolo Molaro <lupus(a)ximian.com>
* Makefile.am: support cross-compilation.
2001-11-07 Miguel de Icaza <miguel(a)ximian.com>
* monoburg.y: Include string.h, stdlib.h to kill warnings.
* sample.brg: Include string.h to remove warnings.
2001-09-23 Dietmar Maurer <dietmar(a)ximian.com>
* monoburg.c: add a macro MBALLOC_STATE to define the allocation
function for MBState. Added an additional user data argument to
mono_burg_label - the data can be used in the cost functions. The
type can be defined with MBCOST_DATA macro.
(emit_cost_func): inline cost functions
2001-09-22 Dietmar Maurer <dietmar(a)ximian.com>
* monoburg.y (strndup): removed, use g_strndup instead
* monoburg.c (create_term): bug fix: g_strdup strings from the parser
2001-09-21 Miguel de Icaza <miguel(a)ximian.com>
* Makefile.am (EXTRA_DIST): Add man page to the distro
2001-09-21 Dietmar Maurer <dietmar(a)ximian.com>
* monoburg.y (yylex): bug fix
2001-09-19 Dietmar Maurer <dietmar(a)ximian.com>
* monoburg.c (emit_header): bug fix for MBCOND macro
Tue Sep 18 13:15:12 CEST 2001 Paolo Molaro <lupus(a)ximian.com>
* monoburg.y: fix ANSI C issue.
2001-09-14 Dietmar Maurer <dietmar(a)ximian.com>
* monoburg.c (emit_prototypes): add an additional argument to the
code emit function - a pointer to the code buffer
Tue Sep 11 13:46:35 CEST 2001 Paolo Molaro <lupus(a)ximian.com>
* Makefile.am: get it to work on platforms that insist on having
a weird extension at the end of an executable name.
Mon Sep 10 17:24:45 CEST 2001 Paolo Molaro <lupus(a)ximian.com>
* Makefile.am: make it work for make distcheck.
2001-09-09 Nick Drochak <ndrochak(a)gol.com>
* Makefile.am: change CLEANFILES line to use just '=' instead of '+='
some versions of automake complain if you try to '+=' before you '='
2001-09-08 Dietmar Maurer <dietmar(a)ximian.com>
* monoburg.c (emit_header): added some convenient macros
* monoburg.y (optcfunc): allow arbitrary cost functions
2001-09-06 Dietmar Maurer <dietmar(a)ximian.com>
* monoburg.c (emit_header): use macros to access the tree (like in iburg)
++ monoburg.1 (revision 0)
.\"
.\" monoburg manual page.
.\" (C) Ximian, Inc.
.\" Author:
.\" Dietmar Maurer (dietmar(a)ximian.com)
.\"
.TH Mono "Mono 1.0"
.SH NAME
monoburg \- code generator generator
.SH SYNOPSIS
.PP
.B monoburg
[\-h]
[\-e]
[\-p]
[\-c VALUE]
[\-d HEADER]
[\-DVALUE]
[FILE...]
.SH DESCRIPTION
The \fImonoburg\fP program is used to generate tree pattern matchers
from BURG specifications. \fImonoburg\fP accepts the following EBNF grammar.
.PP
.nf
.RS
.ft CW
spec: ccode `%%' { dcl } [`%%' ccode]
dcl: `%start' nonterm
`%term' { identifier [`=' integer] }
`%termprefix' { identifier }
nonterm `:' tree [cost] [ `{' ccode `}' ] [costfunc]
tree: term `(' tree `,' tree `)'
term `(' tree `)'
term
nonterm
cost: `"' string '"'
integer
costfunc: `cost' `{' ccode `}'
.RE
.fi
.PP
Where \fIccode\fP is arbitrary C code. \fIcost\fP and \fIcostfunc\fP are
used mutually exclusive, you can't use both in one rule. \fIcost\fP must be a C
expression, whereas \fIccode\fP inside \fIcostfunc\fP is the body of a C
function. Here are some example rules:
.PP
.nf
.RS
.ft CW
# define some terminal
%term Fetch Four Mul Plus
# this rule uses fixed costs
addr: Plus (con, Mul (Four, reg)) 2
{
printf ("Emit your code here.");
}
# this one computes costs inside a function
reg: Fetch (addr)
{
printf ("Tree address is %p", tree);
} cost {
int c;
c = 1; /* calculate the costs here */
return c;
}
.RE
.fi
.PP
A simple pre-processor is included, consisting of: %ifdef, %else and
%endif. %ifdef operates on definitions from the command line.
.SH OPTIONS
The following options are supported:
.TP
.I "-h"
Displays usage instructions.
.TP
.I "-d HEADER"
Writes a separate header file which contains all monoburg definitions.
.TP
.I "-p"
Assume termainals are already defined. Its possible to omit the %term
definitions in this mode if you use the %termprefix command. All symbols
starting with a prefix specified in %termprefix are considered to be terminals.
.TP
.I "-e"
Extended mode. Enables monoburg to work with DAGs.
.TP
.I "-c VALUE"
Set the default costs to VALUE
.TP
.I "-Dvar"
Defines the variable "var" as true. This is used with %ifdef, %else
and %endif in the source files to perform conditional compilation.
.PP
.SH AUTHOR
monoburg was written by Dietmar Maurer. It is based on the papers from
Christopher W.\ Fraser, Robert R.\ Henry and Todd A.\ Proebsting:
"BURG - Fast Optimal Instruction Selection and Tree Parsing" and
"Engineering a Simple, Efficient Code Generator Generator".
.SH SEE ALSO
.BR monodis(1)
.BR pedump(1)
++ Makefile.am (revision 0)
## Makefile.am -- Process this file with automake to produce Makefile.in
##
SUBDIRS = config
## Include path
INCLUDES = $(GLIB_CFLAGS) -I$(srcdir)
## MonoBURG binary
bin_PROGRAMS = monoburg
monoburg_SOURCES = \
parser.y \
monoburg.c monoburg.h
monoburg_LDADD = \
$(GLIB_LIBS)
## MonoBURG manual
man_MANS = monoburg.1
EXTRA_DIST = $(man_MANS)
## Check/Sample
check_PROGRAMS = sample
TESTS = sample
sample.c: monoburg$(EXEEXT) $(srcdir)/sample.brg
./monoburg$(EXEEXT) $(srcdir)/sample.brg > sample.c
sample_SOURCES = sample.brg
sample_LDADD = sample.o $(GLIB_LIBS)
CLEANFILES = sample.c
++ monoburg.c (revision 0)
/*
* monoburg.c: an iburg like code generator generator
*
* Author:
* Dietmar Maurer (dietmar(a)ximian.com)
*
* (C) 2001 Ximian, Inc.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "monoburg.h"
extern void yyparse (void);
static GHashTable *term_hash;
static GList *term_list;
static GHashTable *nonterm_hash;
static GList *nonterm_list;
static GList *rule_list;
static GList *prefix_list;
FILE *inputfd;
FILE *outputfd;
GHashTable *definedvars;
static FILE *deffd;
static FILE *cfd;
static int dag_mode = 0;
static int predefined_terms = 0;
static int default_cost = 0;
static void output (char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf (outputfd, fmt, ap);
va_end (ap);
}
Rule*
make_rule (char *id, Tree *tree)
{
Rule *rule = g_new0 (Rule, 1);
rule->lhs = nonterm (id);
rule->tree = tree;
return rule;
}
void
rule_add (Rule *rule, char *code, char *cost, char *cfunc)
{
if (!cfunc && !cost)
cost = g_strdup_printf ("%d", default_cost);
rule_list = g_list_append (rule_list, rule);
rule->cost = g_strdup (cost);
rule->cfunc = g_strdup (cfunc);
rule->code = g_strdup (code);
if (cfunc) {
if (cost)
yyerror ("duplicated costs (constant costs and cost function)");
else {
if (dag_mode)
rule->cost = g_strdup_printf ("mono_burg_cost_%d (p, data)",
g_list_length (rule_list));
else
rule->cost = g_strdup_printf ("mono_burg_cost_%d (tree, data)",
g_list_length (rule_list));
}
}
rule->lhs->rules = g_list_append (rule->lhs->rules, rule);
if (rule->tree->op)
rule->tree->op->rules = g_list_append (rule->tree->op->rules, rule);
else
rule->tree->nonterm->chain = g_list_append (rule->tree->nonterm->chain, rule);
}
void
create_rule (char *id, Tree *tree, char *code, char *cost, char *cfunc)
{
Rule *rule = make_rule (id, tree);
rule_add (rule, code, cost, cfunc);
}
Tree *
create_tree (char *id, Tree *left, Tree *right)
{
int arity = (left != NULL) + (right != NULL);
Term *term = NULL;
Tree *tree = g_new0 (Tree, 1);
if (term_hash)
term = g_hash_table_lookup (term_hash, id);
/* try if id has termprefix */
if (!term) {
GList *pl;
for (pl = prefix_list; pl; pl = pl->next) {
char *pfx = (char *)pl->data;
if (!strncmp (pfx, id, strlen (pfx))) {
term = create_term (id, -1);
break;
}
}
}
if (term) {
if (term->arity == -1)
term->arity = arity;
if (term->arity != arity)
yyerror ("changed arity of terminal %s from %d to %d",
id, term->arity, arity);
tree->op = term;
tree->left = left;
tree->right = right;
} else {
tree->nonterm = nonterm (id);
}
return tree;
}
static void
check_term_num (char *key, Term *value, int num)
{
if (num != -1 && value->number == num)
yyerror ("duplicate terminal id \"%s\"", key);
}
void
create_term_prefix (char *id)
{
if (!predefined_terms)
yyerror ("%termprefix is only available with -p option");
prefix_list = g_list_prepend (prefix_list, g_strdup (id));
}
Term *
create_term (char *id, int num)
{
Term *term;
if (!predefined_terms && nonterm_list)
yyerror ("terminal definition after nonterminal definition");
if (num < -1)
yyerror ("invalid terminal number %d", num);
if (!term_hash)
term_hash = g_hash_table_new (g_str_hash , g_str_equal);
g_hash_table_foreach (term_hash, (GHFunc) check_term_num, (gpointer) num);
term = g_new0 (Term, 1);
term->name = g_strdup (id);
term->number = num;
term->arity = -1;
term_list = g_list_append (term_list, term);
g_hash_table_insert (term_hash, term->name, term);
return term;
}
NonTerm *
nonterm (char *id)
{
NonTerm *nterm;
if (!nonterm_hash)
nonterm_hash = g_hash_table_new (g_str_hash , g_str_equal);
if ((nterm = g_hash_table_lookup (nonterm_hash, id)))
return nterm;
nterm = g_new0 (NonTerm, 1);
nterm->name = g_strdup (id);
nonterm_list = g_list_append (nonterm_list, nterm);
nterm->number = g_list_length (nonterm_list);
g_hash_table_insert (nonterm_hash, nterm->name, nterm);
return nterm;
}
void
start_nonterm (char *id)
{
static gboolean start_def;
if (start_def)
yyerror ("start symbol redeclared");
start_def = TRUE;
nonterm (id);
}
static void
emit_tree_string (Tree *tree)
{
if (tree->op) {
output ("%s", tree->op->name);
if (tree->op->arity) {
output ("(");
emit_tree_string (tree->left);
if (tree->right) {
output (", ");
emit_tree_string (tree->right);
}
output (")");
}
} else
output ("%s", tree->nonterm->name);
}
static void
emit_rule_string (Rule *rule, char *fill)
{
output ("%s/* ", fill);
output ("%s: ", rule->lhs->name);
emit_tree_string (rule->tree);
output (" */\n");
}
static int
next_term_num ()
{
GList *l = term_list;
int i = 1;
while (l) {
Term *t = (Term *)l->data;
if (t->number == i) {
l = term_list;
i++;
} else
l = l->next;
}
return i;
}
static int
term_compare_func (Term *t1, Term *t2)
{
return t1->number - t2->number;
}
static void
emit_header ()
{
GList *l;
output ("#include <glib.h>\n");
output ("\n");
output ("#ifndef MBTREE_TYPE\n#error MBTREE_TYPE undefined\n#endif\n");
output ("#ifndef MBTREE_OP\n#define MBTREE_OP(t) ((t)->op)\n#endif\n");
output ("#ifndef MBTREE_LEFT\n#define MBTREE_LEFT(t) ((t)->left)\n#endif\n");
output ("#ifndef MBTREE_RIGHT\n#define MBTREE_RIGHT(t) ((t)->right)\n#endif\n");
output ("#ifndef MBTREE_STATE\n#define MBTREE_STATE(t) ((t)->state)\n#endif\n");
output ("#ifndef MBCGEN_TYPE\n#define MBCGEN_TYPE int\n#endif\n");
output ("#ifndef MBALLOC_STATE\n#define MBALLOC_STATE g_new (MBState, 1)\n#endif\n");
output ("#ifndef MBCOST_DATA\n#define MBCOST_DATA gpointer\n#endif\n");
output ("\n");
output ("#define MBMAXCOST 32768\n");
output ("\n");
output ("#define MBCOND(x) if (!(x)) return MBMAXCOST;\n");
output ("\n");
for (l = term_list; l; l = l->next) {
Term *t = (Term *)l->data;
if (t->number == -1)
t->number = next_term_num ();
}
term_list = g_list_sort (term_list, (GCompareFunc)term_compare_func);
for (l = term_list; l; l = l->next) {
Term *t = (Term *)l->data;
if (t->number == -1)
t->number = next_term_num ();
if (predefined_terms)
output ("#define MB_TERM_%s\t %s\n", t->name, t->name);
else
output ("#define MB_TERM_%s\t %d\n", t->name, t->number);
}
output ("\n");
}
static void
emit_nonterm ()
{
GList *l;
for (l = nonterm_list; l; l = l->next) {
NonTerm *n = (NonTerm *)l->data;
output ("#define MB_NTERM_%s\t%d\n", n->name, n->number);
}
output ("#define MB_MAX_NTERMS\t%d\n", g_list_length (nonterm_list));
output ("\n");
}
static void
emit_state ()
{
GList *l;
int i, j;
output ("typedef struct _MBState MBState;\n");
output ("struct _MBState {\n");
output ("\tint\t\t op;\n");
if (dag_mode) {
output ("\tMBTREE_TYPE\t *tree;\n");
output ("\tgint32 reg1, reg2;\n");
}
output ("\tMBState\t\t*left, *right;\n");
output ("\tguint16\t\tcost[%d];\n", g_list_length (nonterm_list) + 1);
for (l = nonterm_list; l; l = l->next) {
NonTerm *n = (NonTerm *)l->data;
g_assert (g_list_length (n->rules) < 256);
i = g_list_length (n->rules);
j = 1;
while (i >>= 1)
j++;
output ("\tunsigned int\t rule_%s:%d;\n", n->name, j);
}
output ("};\n\n");
}
static void
emit_decoders ()
{
GList *l;
GList *rl;
for (l = nonterm_list; l; l = l->next) {
NonTerm *n = (NonTerm *)l->data;
output ("const int mono_burg_decode_%s[] = {\n", n->name);
output ("\t0,\n");
for (rl = n->rules; rl; rl = rl->next) {
Rule *rule = (Rule *)rl->data;
output ("\t%d,\n", g_list_index (rule_list, rule) + 1);
}
output ("};\n\n");
}
}
static void
emit_tree_match (char *st, Tree *t)
{
char *tn;
int not_first = strcmp (st, "p->");
/* we can omit this check at the top level */
if (not_first) {
if (predefined_terms)
output ("\t\t\t%sop == %s /* %s */", st, t->op->name, t->op->name);
else
output ("\t\t\t%sop == %d /* %s */", st, t->op->number, t->op->name);
}
if (t->left && t->left->op) {
tn = g_strconcat (st, "left->", NULL);
if (not_first)
output (" &&\n");
not_first = 1;
emit_tree_match (tn, t->left);
g_free (tn);
}
if (t->right && t->right->op) {
tn = g_strconcat (st, "right->", NULL);
if (not_first)
output (" &&\n");
emit_tree_match (tn, t->right);
g_free (tn);
}
}
static void
emit_rule_match (Rule *rule)
{
Tree *t = rule->tree;
if ((t->left && t->left->op) ||
(t->right && t->right->op)) {
output ("\t\tif (\n");
emit_tree_match ("p->", t);
output ("\n\t\t)\n");
}
}
static void
emit_costs (char *st, Tree *t)
{
char *tn;
if (t->op) {
if (t->left) {
tn = g_strconcat (st, "left->", NULL);
emit_costs (tn, t->left);
g_free (tn);
}
if (t->right) {
tn = g_strconcat (st, "right->", NULL);
emit_costs (tn, t->right);
}
} else
output ("%scost[MB_NTERM_%s] + ", st, t->nonterm->name);
}
static void
emit_cond_assign (Rule *rule, char *cost, char *fill)
{
char *rc;
if (cost)
rc = g_strconcat ("c + ", cost, NULL);
else
rc = g_strdup ("c");
output ("%sif (%s < p->cost[MB_NTERM_%s]) {\n", fill, rc, rule->lhs->name);
output ("%s\tp->cost[MB_NTERM_%s] = %s;\n", fill, rule->lhs->name, rc);
output ("%s\tp->rule_%s = %d;\n", fill, rule->lhs->name,
g_list_index (rule->lhs->rules, rule) + 1);
if (rule->lhs->chain)
output ("%s\tclosure_%s (p, %s);\n", fill, rule->lhs->name, rc);
output ("%s}\n", fill);
g_free (rc);
}
static void
emit_label_func ()
{
GList *l;
int i;
if (dag_mode) {
output ("static void\n");
output ("mono_burg_label_priv (MBTREE_TYPE *tree, MBCOST_DATA *data, MBState *p) {\n");
} else {
output ("static MBState *\n");
output ("mono_burg_label_priv (MBTREE_TYPE *tree, MBCOST_DATA *data) {\n");
}
output ("\tint arity;\n");
output ("\tint c;\n");
if (!dag_mode)
output ("\tMBState *p;\n");
output ("\tMBState *left = NULL, *right = NULL;\n\n");
output ("\tswitch (mono_burg_arity [MBTREE_OP(tree)]) {\n");
output ("\tcase 0:\n");
output ("\t\tbreak;\n");
output ("\tcase 1:\n");
if (dag_mode) {
output ("\t\tleft = MBALLOC_STATE;\n");
output ("\t\tmono_burg_label_priv (MBTREE_LEFT(tree), data, left);\n");
} else {
output ("\t\tleft = mono_burg_label_priv (MBTREE_LEFT(tree), data);\n");
output ("\t\tright = NULL;\n");
}
output ("\t\tbreak;\n");
output ("\tcase 2:\n");
if (dag_mode) {
output ("\t\tleft = MBALLOC_STATE;\n");
output ("\t\tmono_burg_label_priv (MBTREE_LEFT(tree), data, left);\n");
output ("\t\tright = MBALLOC_STATE;\n");
output ("\t\tmono_burg_label_priv (MBTREE_RIGHT(tree), data, right);\n");
} else {
output ("\t\tleft = mono_burg_label_priv (MBTREE_LEFT(tree), data);\n");
output ("\t\tright = mono_burg_label_priv (MBTREE_RIGHT(tree), data);\n");
}
output ("\t}\n\n");
output ("\tarity = (left != NULL) + (right != NULL);\n");
output ("\tg_assert (arity == mono_burg_arity [MBTREE_OP(tree)]);\n\n");
if (!dag_mode)
output ("\tp = MBALLOC_STATE;\n");
output ("\tmemset (p, 0, sizeof (MBState));\n");
output ("\tp->op = MBTREE_OP(tree);\n");
output ("\tp->left = left;\n");
output ("\tp->right = right;\n");
if (dag_mode)
output ("\tp->tree = tree;\n");
for (l = nonterm_list, i = 0; l; l = l->next) {
output ("\tp->cost [%d] = 32767;\n", ++i);
}
output ("\n");
output ("\tswitch (MBTREE_OP(tree)) {\n");
for (l = term_list; l; l = l->next) {
Term *t = (Term *)l->data;
GList *rl;
if (predefined_terms)
output ("\tcase %s: /* %s */\n", t->name, t->name);
else
output ("\tcase %d: /* %s */\n", t->number, t->name);
for (rl = t->rules; rl; rl = rl->next) {
Rule *rule = (Rule *)rl->data;
Tree *t = rule->tree;
emit_rule_string (rule, "\t\t");
emit_rule_match (rule);
output ("\t\t{\n");
output ("\t\t\tc = ");
emit_costs ("", t);
output ("%s;\n", rule->cost);
emit_cond_assign (rule, NULL, "\t\t\t");
output ("\t\t}\n");
}
output ("\t\tbreak;\n");
}
output ("\tdefault:\n");
output ("#ifdef MBGET_OP_NAME\n");
output ("\t\tg_error (\"unknown operator: %%s\", MBGET_OP_NAME(MBTREE_OP(tree)));\n");
output ("#else\n");
output ("\t\tg_error (\"unknown operator: 0x%%04x\", MBTREE_OP(tree));\n");
output ("#endif\n");
output ("\t}\n\n");
if (!dag_mode) {
output ("\tMBTREE_STATE(tree) = p;\n");
output ("\treturn p;\n");
}
output ("}\n\n");
output ("MBState *\n");
output ("mono_burg_label (MBTREE_TYPE *tree, MBCOST_DATA *data)\n{\n");
if (dag_mode) {
output ("\tMBState *p = MBALLOC_STATE;\n");
output ("\tmono_burg_label_priv (tree, data, p);\n");
} else {
output ("\tMBState *p = mono_burg_label_priv (tree, data);\n");
}
output ("\treturn p->rule_%s ? p : NULL;\n", ((NonTerm *)nonterm_list->data)->name);
output ("}\n\n");
}
static char *
compute_kids (char *ts, Tree *tree, int *n)
{
char *res;
if (tree->nonterm) {
return g_strdup_printf ("\t\tkids[%d] = %s;\n", (*n)++, ts);
} else if (tree->op && tree->op->arity) {
char *res2 = NULL;
if (dag_mode) {
res = compute_kids (g_strdup_printf ("%s->left", ts),
tree->left, n);
if (tree->op->arity == 2)
res2 = compute_kids (g_strdup_printf ("%s->right", ts),
tree->right, n);
} else {
res = compute_kids (g_strdup_printf ("MBTREE_LEFT(%s)", ts),
tree->left, n);
if (tree->op->arity == 2)
res2 = compute_kids (g_strdup_printf ("MBTREE_RIGHT(%s)", ts),
tree->right, n);
}
return g_strconcat (res, res2, NULL);
}
return "";
}
static void
emit_kids ()
{
GList *l, *nl;
int i, j, c, n, *si;
char **sa;
output ("int\n");
output ("mono_burg_rule (MBState *state, int goal)\n{\n");
output ("\tg_return_val_if_fail (state != NULL, 0);\n");
output ("\tg_return_val_if_fail (goal > 0, 0);\n\n");
output ("\tswitch (goal) {\n");
for (nl = nonterm_list; nl; nl = nl->next) {
NonTerm *n = (NonTerm *)nl->data;
output ("\tcase MB_NTERM_%s:\n", n->name);
output ("\t\treturn mono_burg_decode_%s [state->rule_%s];\n",
n->name, n->name);
}
output ("\tdefault: g_assert_not_reached ();\n");
output ("\t}\n");
output ("\treturn 0;\n");
output ("}\n\n");
if (dag_mode) {
output ("MBState **\n");
output ("mono_burg_kids (MBState *state, int rulenr, MBState *kids [])\n{\n");
output ("\tg_return_val_if_fail (state != NULL, NULL);\n");
output ("\tg_return_val_if_fail (kids != NULL, NULL);\n\n");
} else {
output ("MBTREE_TYPE **\n");
output ("mono_burg_kids (MBTREE_TYPE *tree, int rulenr, MBTREE_TYPE *kids [])\n{\n");
output ("\tg_return_val_if_fail (tree != NULL, NULL);\n");
output ("\tg_return_val_if_fail (kids != NULL, NULL);\n\n");
}
output ("\tswitch (rulenr) {\n");
n = g_list_length (rule_list);
sa = g_new0 (char *, n);
si = g_new0 (int, n);
/* compress the case statement */
for (l = rule_list, i = 0, c = 0; l; l = l->next) {
Rule *rule = (Rule *)l->data;
int kn = 0;
char *k;
if (dag_mode)
k = compute_kids ("state", rule->tree, &kn);
else
k = compute_kids ("tree", rule->tree, &kn);
for (j = 0; j < c; j++)
if (!strcmp (sa [j], k))
break;
si [i++] = j;
if (j == c)
sa [c++] = k;
}
for (i = 0; i < c; i++) {
for (l = rule_list, j = 0; l; l = l->next, j++)
if (i == si [j])
output ("\tcase %d:\n", j + 1);
output ("%s", sa [i]);
output ("\t\tbreak;\n");
}
output ("\tdefault:\n\t\tg_assert_not_reached ();\n");
output ("\t}\n");
output ("\treturn kids;\n");
output ("}\n\n");
}
static void
emit_emitter_func ()
{
GList *l;
int i, rulen;
GHashTable *cache = g_hash_table_new (g_str_hash, g_str_equal);
for (l = rule_list, i = 0; l; l = l->next) {
Rule *rule = (Rule *)l->data;
if (rule->code) {
if ((rulen = GPOINTER_TO_INT (g_hash_table_lookup (cache, rule->code)))) {
emit_rule_string (rule, "");
output ("#define mono_burg_emit_%d mono_burg_emit_%d\n\n", i, rulen);
i++;
continue;
}
output ("static void ");
emit_rule_string (rule, "");
if (dag_mode)
output ("mono_burg_emit_%d (MBState *state, MBTREE_TYPE *tree, MBCGEN_TYPE *s)\n", i);
else
output ("mono_burg_emit_%d (MBTREE_TYPE *tree, MBCGEN_TYPE *s)\n", i);
output ("{\n");
output ("%s\n", rule->code);
output ("}\n\n");
g_hash_table_insert (cache, rule->code, GINT_TO_POINTER (i));
}
i++;
}
g_hash_table_destroy (cache);
output ("MBEmitFunc const mono_burg_func [] = {\n");
output ("\tNULL,\n");
for (l = rule_list, i = 0; l; l = l->next) {
Rule *rule = (Rule *)l->data;
if (rule->code)
output ("\tmono_burg_emit_%d,\n", i);
else
output ("\tNULL,\n");
i++;
}
output ("};\n\n");
}
static void
emit_cost_func ()
{
GList *l;
int i;
for (l = rule_list, i = 0; l; l = l->next) {
Rule *rule = (Rule *)l->data;
if (rule->cfunc) {
output ("inline static guint16\n");
emit_rule_string (rule, "");
if (dag_mode)
output ("mono_burg_cost_%d (MBState *state, MBCOST_DATA *data)\n", i + 1);
else
output ("mono_burg_cost_%d (MBTREE_TYPE *tree, MBCOST_DATA *data)\n", i + 1);
output ("{\n");
output ("%s\n", rule->cfunc);
output ("}\n\n");
}
i++;
}
}
static void
emit_closure ()
{
GList *l, *rl;
for (l = nonterm_list; l; l = l->next) {
NonTerm *n = (NonTerm *)l->data;
if (n->chain)
output ("static void closure_%s (MBState *p, int c);\n", n->name);
}
output ("\n");
for (l = nonterm_list; l; l = l->next) {
NonTerm *n = (NonTerm *)l->data;
if (n->chain) {
output ("static void\n");
output ("closure_%s (MBState *p, int c)\n{\n", n->name);
for (rl = n->chain; rl; rl = rl->next) {
Rule *rule = (Rule *)rl->data;
emit_rule_string (rule, "\t");
emit_cond_assign (rule, rule->cost, "\t");
}
output ("}\n\n");
}
}
}
static char *
compute_nonterms (Tree *tree)
{
if (!tree)
return "";
if (tree->nonterm) {
return g_strdup_printf ("MB_NTERM_%s, ", tree->nonterm->name);
} else {
return g_strconcat (compute_nonterms (tree->left),
compute_nonterms (tree->right), NULL);
}
}
static void
emit_vardefs ()
{
GList *l;
int i, j, c, n, *si;
char **sa;
if (predefined_terms) {
output ("guint8 mono_burg_arity [MBMAX_OPCODES];\n");
output ("void\nmono_burg_init (void)\n{\n");
for (l = term_list, i = 0; l; l = l->next) {
Term *t = (Term *)l->data;
output ("\tmono_burg_arity [%s] = %d; /* %s */\n", t->name, t->arity, t->name);
}
output ("}\n\n");
} else {
output ("const guint8 mono_burg_arity [] = {\n");
for (l = term_list, i = 0; l; l = l->next) {
Term *t = (Term *)l->data;
while (i < t->number) {
output ("\t0,\n");
i++;
}
output ("\t%d, /* %s */\n", t->arity, t->name);
i++;
}
output ("};\n\n");
output ("const char *const mono_burg_term_string [] = {\n");
output ("\tNULL,\n");
for (l = term_list, i = 0; l; l = l->next) {
Term *t = (Term *)l->data;
output ("\t\"%s\",\n", t->name);
}
output ("};\n\n");
}
output ("const char * const mono_burg_rule_string [] = {\n");
output ("\tNULL,\n");
for (l = rule_list, i = 0; l; l = l->next) {
Rule *rule = (Rule *)l->data;
output ("\t\"%s: ", rule->lhs->name);
emit_tree_string (rule->tree);
output ("\",\n");
}
output ("};\n\n");
n = g_list_length (rule_list);
sa = g_new0 (char *, n);
si = g_new0 (int, n);
/* compress the _nts array */
for (l = rule_list, i = 0, c = 0; l; l = l->next) {
Rule *rule = (Rule *)l->data;
char *s = compute_nonterms (rule->tree);
for (j = 0; j < c; j++)
if (!strcmp (sa [j], s))
break;
si [i++] = j;
if (j == c) {
output ("static const guint16 mono_burg_nts_%d [] = { %s0 };\n", c, s);
sa [c++] = s;
}
}
output ("\n");
output ("const guint16 *const mono_burg_nts [] = {\n");
output ("\t0,\n");
for (l = rule_list, i = 0; l; l = l->next) {
Rule *rule = (Rule *)l->data;
output ("\tmono_burg_nts_%d, ", si [i++]);
emit_rule_string (rule, "");
}
output ("};\n\n");
}
static void
emit_prototypes ()
{
if (dag_mode)
output ("typedef void (*MBEmitFunc) (MBState *state, MBTREE_TYPE *tree, MBCGEN_TYPE *s);\n\n");
else
output ("typedef void (*MBEmitFunc) (MBTREE_TYPE *tree, MBCGEN_TYPE *s);\n\n");
output ("extern const char * const mono_burg_term_string [];\n");
output ("extern const char * const mono_burg_rule_string [];\n");
output ("extern const guint16 *const mono_burg_nts [];\n");
output ("extern MBEmitFunc const mono_burg_func [];\n");
output ("MBState *mono_burg_label (MBTREE_TYPE *tree, MBCOST_DATA *data);\n");
output ("int mono_burg_rule (MBState *state, int goal);\n");
if (dag_mode)
output ("MBState **mono_burg_kids (MBState *state, int rulenr, MBState *kids []);\n");
else
output ("MBTREE_TYPE **mono_burg_kids (MBTREE_TYPE *tree, int rulenr, MBTREE_TYPE *kids []);\n");
output ("extern void mono_burg_init (void);\n");
output ("\n");
}
static void check_reach (NonTerm *n);
static void
mark_reached (Tree *tree)
{
if (tree->nonterm && !tree->nonterm->reached)
check_reach (tree->nonterm);
if (tree->left)
mark_reached (tree->left);
if (tree->right)
mark_reached (tree->right);
}
static void
check_reach (NonTerm *n)
{
GList *l;
n->reached = 1;
for (l = n->rules; l; l = l->next) {
Rule *rule = (Rule *)l->data;
mark_reached (rule->tree);
}
}
static void
check_result ()
{
GList *l;
for (l = term_list; l; l = l->next) {
Term *term = (Term *)l->data;
if (term->arity == -1)
g_warning ("unused terminal \"%s\"",term->name);
}
check_reach (((NonTerm *)nonterm_list->data));
for (l = nonterm_list; l; l = l->next) {
NonTerm *n = (NonTerm *)l->data;
if (!n->reached)
g_warning ("unreachable nonterm \"%s\"", n->name);
}
}
static void
usage ()
{
fprintf (stderr,
"Usage is: monoburg -d file.h -s file.c [inputfile] \n");
exit (1);
}
static void
warning_handler (const gchar *log_domain,
GLogLevelFlags log_level,
const gchar *message,
gpointer user_data)
{
(void) fprintf ((FILE *) user_data, "** WARNING **: %s\n", message);
}
int
main (int argc, char *argv [])
{
char *cfile = NULL;
char *deffile = NULL;
GList *infiles = NULL;
int i;
definedvars = g_hash_table_new (g_str_hash, g_str_equal);
g_log_set_handler (NULL, G_LOG_LEVEL_WARNING, warning_handler, stderr);
for (i = 1; i < argc; i++){
if (argv [i][0] == '-'){
if (argv [i][1] == 'h') {
usage ();
} else if (argv [i][1] == 'e') {
dag_mode = 1;
} else if (argv [i][1] == 'p') {
predefined_terms = 1;
} else if (argv [i][1] == 'd') {
deffile = argv [++i];
} else if (argv [i][1] == 's') {
cfile = argv [++i];
} else if (argv [i][1] == 'c') {
default_cost = atoi (argv [++i]);
} else if (argv [i][1] == 'D') {
g_hash_table_insert (definedvars, &argv [i][2],
GUINT_TO_POINTER (1));
} else {
usage ();
}
} else {
infiles = g_list_append (infiles, argv [i]);
}
}
if (deffile) {
if (!(deffd = fopen (deffile, "w"))) {
perror ("cant open header output file");
exit (-1);
}
outputfd = deffd;
output ("#ifndef _MONO_BURG_DEFS_\n");
output ("#define _MONO_BURG_DEFS_\n\n");
} else
outputfd = stdout;
if (infiles) {
GList *l = infiles;
while (l) {
char *infile = (char *)l->data;
if (!(inputfd = fopen (infile, "r"))) {
perror ("cant open input file");
exit (-1);
}
yyparse ();
reset_parser ();
l->data = inputfd;
l = l->next;
}
} else {
inputfd = stdin;
yyparse ();
}
check_result ();
if (!nonterm_list)
g_error ("no start symbol found");
emit_header ();
emit_nonterm ();
emit_state ();
emit_prototypes ();
if (deffd) {
output ("#endif /* _MONO_BURG_DEFS_ */\n");
fclose (deffd);
if (cfile == NULL)
outputfd = stdout;
else {
if (!(cfd = fopen (cfile, "w"))) {
perror ("cant open c output file");
(void) remove (deffile);
exit (-1);
}
outputfd = cfd;
}
output ("#include \"%s\"\n\n", deffile);
}
emit_vardefs ();
emit_cost_func ();
emit_emitter_func ();
emit_decoders ();
emit_closure ();
emit_label_func ();
emit_kids ();
if (infiles) {
GList *l = infiles;
while (l) {
inputfd = l->data;
yyparsetail ();
fclose (inputfd);
l = l->next;
}
} else {
yyparsetail ();
}
if (cfile)
fclose (cfd);
return 0;
}
++ sample.brg (revision 0)
/*
* This header (everything before the first "%%") is copied
* directly to the output.
*/
#include <glib.h>
#include <stdio.h>
#include <string.h>
#define MBTREE_TYPE MBTree
typedef struct _MBTree MBTree;
struct _MBTree {
guint16 op;
MBTree *left, *right;
gpointer state;
};
%% these are the monoburg definition
#
# This is the start of the definitions
# comments start with a '#' as first line character
#
#
# we must fisrt define the terminals
# with or without numbers
#
%term Assign Constant Fetch=3 Four=8 Mul=5 Plus=6 AltFetch=7
#
# optional start nonterminal
#
%start reg
con: Constant 0
con: Four 0
addr: con 0
addr: Plus(con,reg)
{
int ern = mono_burg_rule (tree->state, MB_NTERM_addr);
printf ("%s\n", mono_burg_rule_string [ern]);
} cost
{
return 1;
}
addr: Plus(con,Mul(Four,reg)) 2
{
int ern = mono_burg_rule (tree->state, MB_NTERM_addr);
printf ("%s\n", mono_burg_rule_string [ern]);
}
reg: AltFetch(addr),
reg: Fetch(addr) 1
{
int ern = mono_burg_rule (tree->state, MB_NTERM_reg);
printf ("%s\n", mono_burg_rule_string [ern]);
}
reg: Assign(addr,reg) 1
{
int ern = mono_burg_rule (tree->state, MB_NTERM_reg);
printf ("%s\n", mono_burg_rule_string [ern]);
}
%% the rest is also copied directly to the output
/* everything below the second "%%" is also copied directly
* to the output file.
*/
static MBTree *
create_tree (int op, MBTree *left, MBTree *right)
{
MBTree *t = g_new0 (MBTree, 1);
t->op = op;
t->left = left;
t->right = right;
return t;
}
static void
reduce (MBTree *tree, int goal)
{
MBTree *kids[10];
int ern = mono_burg_rule (tree->state, goal);
guint16 *nts = mono_burg_nts [ern];
int i, n;
mono_burg_kids (tree, ern, kids);
// printf ("TEST %d %d %s %d\n", goal, ern, mono_burg_rule_string [ern], nts [0]);
for (i = 0; nts [i]; i++)
reduce (kids [i], nts [i]);
n = (tree->left != NULL) + (tree->right != NULL);
if (n) { /* not a terminal */
// printf ("XXTE %s %d\n", mono_burg_rule_string [ern], n);
if (mono_burg_func [ern])
mono_burg_func [ern] (tree, NULL);
else
g_warning ("no code for rule %s\n",
mono_burg_rule_string [ern]);
} else {
if (mono_burg_func [ern])
g_warning ("unused code in rule %s\n",
mono_burg_rule_string [ern]);
}
}
int
main ()
{
MBTree *t, *l, *r;
MBState *s;
l = create_tree (MB_TERM_Constant, NULL, NULL);
r = create_tree (MB_TERM_Fetch, l, NULL);
l = create_tree (MB_TERM_Constant, NULL, NULL);
r = create_tree (MB_TERM_Assign, l, r);
l = create_tree (MB_TERM_Four, NULL, NULL);
r = create_tree (MB_TERM_Mul, l, r);
l = create_tree (MB_TERM_Constant, NULL, NULL);
l = create_tree (MB_TERM_Plus, l, r);
t = create_tree (MB_TERM_Fetch, l, NULL);
s = mono_burg_label (t, NULL);
g_assert (s);
reduce (t, MB_NTERM_reg);
return 0;
}
++ README (revision 0)
This is an implementation of an IBurg like code generator generator. It is
based on the papers from Christopher W. Fraser, Robert R. Henry and Todd
A. Proebsting:
Reference 1: BURG - Fast Optimal Instruction Selection and Tree Parsing
Reference 2: Engineering a Simple, Efficient Code Generator Generator
Examples: sample.brg
++ bootstrap (revision 0)
#!/bin/sh
autoreconf -f -v -i -m
Index: configure.ac
--- configure.ac (revision 0)
+++ configure.ac (revision 0)
@@ -0,0 +1,46 @@
+## ----------------------------------------------------------------------------
+## Configure MonoBURG, an IBurg-like code generator generator
+##
+
+## -------------------------------------
+## Project
+AC_INIT([MonoBURG], [1.0.1])
+
+## -------------------------------------
+## Setup autotools
+
+# Need autoconf 2.57 at least.
+AC_PREREQ([2.57])
+
+# Auxiliary files.
+AC_CONFIG_AUX_DIR([config])
+AC_CONFIG_FILES([config/Makefile])
+
+# Initiate automake.
+AM_INIT_AUTOMAKE([foreign 1.7.5 dist-bzip2])
+
+## -------------------------------------
+## Development tools
+
+# Look for a C compiler
+AC_PROG_CC
+
+# Look for a yacc-like program
+AC_PROG_YACC
+
+## -------------------------------------
+## Environment
+
+# Check for GLIB-2.0 presence
+AM_PATH_GLIB_2_0
+
+## -------------------------------------
+## Epilogue
+
+# Ask for Makefile creation
+AC_CONFIG_FILES([
+ Makefile
+])
+
+# Instantiate the output files
+AC_OUTPUT
Index: parser.y
--- parser.y (revision 0)
+++ parser.y (revision 0)
@@ -0,0 +1,363 @@
+%{
+/*
+ * monoburg.y: yacc input grammer
+ *
+ * Author:
+ * Dietmar Maurer (dietmar(a)ximian.com)
+ *
+ * (C) 2001 Ximian, Inc.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <assert.h>
+#include <stdarg.h>
+
+#include "monoburg.h"
+
+static int yylineno = 0;
+static int yylinepos = 0;
+
+%}
+
+%union {
+ char *text;
+ int ivalue;
+ Tree *tree;
+ Rule *rule;
+ GList *rule_list;
+}
+
+%token <text> IDENT
+%token <text> CODE
+%token <text> STRING
+%token START
+%token COST
+%token TERM
+%token TERMPREFIX
+%token <ivalue> INTEGER
+
+%type <tree> tree
+%type <text> optcost
+%type <text> optcfunc
+%type <text> optcode
+%type <rule> rule
+%type <rule_list> rule_list
+
+%%
+
+decls : /* empty */
+ | START IDENT { start_nonterm ($2); } decls
+ | TERM tlist decls
+ | TERMPREFIX plist decls
+ | rule_list optcost optcode optcfunc {
+ GList *tmp;
+ for (tmp = $1; tmp; tmp = tmp->next) {
+ rule_add (tmp->data, $3, $2, $4);
+ }
+ g_list_free ($1);
+ } decls
+ ;
+
+rule : IDENT ':' tree { $$ = make_rule ($1, $3); }
+ ;
+
+rule_list : rule { $$ = g_list_append (NULL, $1); }
+ | rule ',' rule_list { $$ = g_list_prepend ($3, $1); }
+ ;
+
+optcode : /* empty */ { $$ = NULL; }
+ | CODE
+ ;
+
+plist : /* empty */
+ | plist IDENT { create_term_prefix ($2);}
+ ;
+
+tlist : /* empty */
+ | tlist IDENT { create_term ($2, -1);}
+ | tlist IDENT '=' INTEGER { create_term ($2, $4); }
+ ;
+
+tree : IDENT { $$ = create_tree ($1, NULL, NULL); }
+ | IDENT '(' tree ')' { $$ = create_tree ($1, $3, NULL); }
+ | IDENT '(' tree ',' tree ')' { $$ = create_tree ($1, $3, $5); }
+ ;
+
+optcost : /* empty */ {$$ = NULL; }
+ | STRING
+ | INTEGER { $$ = g_strdup_printf ("%d", $1); }
+ ;
+
+optcfunc : /*empty */ { $$ = NULL; }
+ | COST CODE { $$ = $2; }
+ ;
+%%
+
+static char input[2048];
+static char *next = input;
+
+void
+yyerror (char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ fprintf (stderr, "line %d(%d): ", yylineno, yylinepos);
+ vfprintf (stderr, fmt, ap);
+ fprintf(stderr, "\n");
+
+ va_end (ap);
+
+ exit (-1);
+}
+
+static int state = 0;
+
+void
+reset_parser ()
+{
+ state = 0;
+}
+
+struct pplist {
+ struct pplist *next;
+ gboolean ignore;
+};
+
+static struct pplist *pp = NULL;
+
+static char*
+getvar (const char *input)
+{
+ char *var = g_strchug (g_strdup (input));
+ char *ptr;
+
+ for (ptr = var; *ptr && *ptr != '\n'; ++ptr) {
+ if (g_ascii_isspace (*ptr)) {
+ break;
+ }
+ }
+ *ptr = '\0';
+
+ return var;
+}
+
+static void
+push_if (char *input, gboolean flip)
+{
+ struct pplist *new_pp = g_new (struct pplist, 1);
+ char *var = getvar (input);
+
+ new_pp->ignore = (g_hash_table_lookup (definedvars, var) == NULL) ^ flip;
+ new_pp->next = pp;
+
+ new_pp->ignore |= (pp ? pp->ignore : 0);
+ pp = new_pp;
+ g_free (var);
+}
+
+static void
+flip_if ()
+{
+ if (!pp)
+ yyerror ("%%else without %%if");
+
+ pp->ignore = !pp->ignore | (pp->next ? pp->next->ignore : 0);
+}
+
+static void
+pop_if ()
+{
+ struct pplist *prev_pp = pp;
+
+ if (!pp)
+ yyerror ("%%endif without %%if");
+
+ pp = pp->next;
+ g_free (prev_pp);
+}
+
+static char
+nextchar ()
+{
+ int next_state ;
+ gboolean ll;
+
+ if (!*next) {
+ next = input;
+ *next = 0;
+ do {
+ if (!fgets (input, sizeof (input), inputfd))
+ return 0;
+
+ ll = (input [0] == '%' && input [1] == '%');
+ next_state = state;
+
+ if (state == 1) {
+ if (!ll && input [0] == '%') {
+ if (!strncmp (&input [1], "ifdef", 5)) {
+ push_if (&input [6], FALSE);
+ ll = TRUE;
+ continue;
+ }
+ else if (!strncmp (&input [1], "ifndef", 6)) {
+ push_if (&input [7], TRUE);
+ ll = TRUE;
+ continue;
+ }
+ else if (!strncmp (&input [1], "else", 4)) {
+ flip_if ();
+ ll = TRUE;
+ continue;
+ }
+ else if (!strncmp (&input [1], "endif", 5)) {
+ pop_if ();
+ ll = TRUE;
+ continue;
+ }
+ }
+ if (pp && pp->ignore) {
+ ll = TRUE;
+ continue;
+ }
+ }
+
+ switch (state) {
+ case 0:
+ if (ll) {
+ next_state = 1;
+ } else
+ fputs (input, outputfd);
+ break;
+ case 1:
+ if (ll) {
+ next_state = 2;
+ *next = 0;
+ }
+ break;
+ default:
+ return 0;
+ }
+ ll = state != 1 || input[0] == '#';
+ state = next_state;
+ yylineno++;
+ } while (next_state == 2 || ll);
+ }
+
+ return *next++;
+}
+
+void
+yyparsetail (void)
+{
+ fputs (input, outputfd);
+ while (fgets (input, sizeof (input), inputfd))
+ fputs (input, outputfd);
+}
+
+int
+yylex (void)
+{
+ char c;
+
+ do {
+
+ if (!(c = nextchar ()))
+ return 0;
+
+ yylinepos = next - input + 1;
+
+ if (isspace (c))
+ continue;
+
+ if (c == '%') {
+ if (!strncmp (next, "start", 5) && isspace (next[5])) {
+ next += 5;
+ return START;
+ }
+
+ if (!strncmp (next, "termprefix", 10) && isspace (next[10])) {
+ next += 10;
+ return TERMPREFIX;
+ }
+
+ if (!strncmp (next, "term", 4) && isspace (next[4])) {
+ next += 4;
+ return TERM;
+ }
+ return c;
+ }
+
+ if (isdigit (c)) {
+ int num = 0;
+
+ do {
+ num = 10*num + (c - '0');
+ } while (isdigit (c = (*next++)));
+
+ yylval.ivalue = num;
+ return INTEGER;
+ }
+
+ if (isalpha (c)) {
+ char *n = next;
+ int l;
+
+ if (!strncmp (next - 1, "cost", 4) && isspace (next[3])) {
+ next += 4;
+ return COST;
+ }
+
+ while (isalpha (*n) || isdigit (*n) || *n == '_')
+ n++;
+
+ l = n - next + 1;
+ yylval.text = g_strndup (next - 1, l);
+ next = n;
+ return IDENT;
+ }
+
+ if (c == '"') {
+ int i = 0;
+ static char buf [100000];
+
+ while ((c = *next++) != '"' && c)
+ buf [i++] = c;
+
+ buf [i] = '\0';
+ yylval.text = g_strdup (buf);
+
+ return STRING;
+ }
+
+ if (c == '{') {
+ int i = 0, d = 1;
+ static char buf [100000];
+
+ while (d && (c = nextchar ())) {
+ buf [i++] = c;
+ assert (i < sizeof (buf));
+
+ switch (c) {
+ case '{': d++; break;
+ case '}': d--; break;
+ default:
+ break;
+ }
+ }
+ buf [--i] = '\0';
+ yylval.text = g_strdup (buf);
+
+ return CODE;
+ }
+
+ return c;
+
+ } while (1);
+}
+
Index: config/Makefile.am
--- config/Makefile.am (revision 0)
+++ config/Makefile.am (revision 0)
@@ -0,0 +1,7 @@
+## Makefile.am -- Process this file with automake to produce Makefile.in
+##
+
+MAINTAINERCLEANFILES = \
+ depcomp \
+ install-sh \
+ missing
Index: monoburg.h
--- monoburg.h (revision 0)
+++ monoburg.h (revision 0)
@@ -0,0 +1,72 @@
+#ifndef __MONO_MONOBURG_H__
+#define __MONO_MONOBURG_H__
+
+#include <glib.h>
+
+void yyerror (char *fmt, ...);
+int yylex (void);
+
+extern FILE *inputfd;
+extern FILE *outputfd;
+extern GHashTable *definedvars;
+
+typedef struct _Rule Rule;
+
+typedef struct _Term Term;
+struct _Term{
+ char *name;
+ int number;
+ int arity;
+ GList *rules; /* rules that start with this terminal */
+};
+
+typedef struct _NonTerm NonTerm;
+
+struct _NonTerm {
+ char *name;
+ int number;
+ GList *rules; /* rules with this nonterm on the left side */
+ GList *chain;
+ gboolean reached;
+};
+
+typedef struct _Tree Tree;
+
+struct _Tree {
+ Term *op;
+ Tree *left;
+ Tree *right;
+ NonTerm *nonterm; /* used by chain rules */
+};
+
+struct _Rule {
+ NonTerm *lhs;
+ Tree *tree;
+ char *code;
+ char *cost;
+ char *cfunc;
+};
+
+
+Tree *create_tree (char *id, Tree *left, Tree *right);
+
+Term *create_term (char *id, int num);
+
+void create_term_prefix (char *id);
+
+NonTerm *nonterm (char *id);
+
+void start_nonterm (char *id);
+
+Rule *make_rule (char *id, Tree *tree);
+
+void rule_add (Rule *rule, char *code, char *cost, char *cfunc);
+
+void create_rule (char *id, Tree *tree, char *code, char *cost,
+ char *cfunc);
+
+void yyparsetail (void);
+
+void reset_parser (void);
+
+#endif
2
1
Index: ChangeLog
from Benoît Perrot <benoit(a)lrde.epita.fr>
Use a dedicated script to launch bison to control the directory
where the generated files are output.
* config/move-if-change, config/bison++: Provided by Akim Demaille.
* config/Makefile.am: Distribute them.
* src/parse/Makefile.am: Use bison++.
Index: src/parse/Makefile.am
--- src/parse/Makefile.am (revision 135)
+++ src/parse/Makefile.am (working copy)
@@ -30,18 +30,21 @@
@mv -f $@.tmp $@
asm-parse.yy: parse-asm-parse.stamp
-bison.stamp: asm-parse.yy
- @rm -rf $@.tmp
- @touch $@.tmp
- bison -S lalr1.cc -d -ra asm-parse.yy -o asm-parse.cc
- @mv -f $@.tmp $@
+
+BISONXX = $(top_srcdir)/config/bison++
+EXTRA_DIST = $(srcdir)/bison++.stamp
+$(srcdir)/bison++.stamp: $(srcdir)/asm-parse.yy
+ @rm -rf bison++.stamp.tmp
+ @touch bison++.stamp.tmp
+ $(BISONXX) $(srcdir) asm-parse.yy asm-parse.cc -d -ra
+ @mv -f bison++.stamp.tmp $@
# Run bison if a file that can be created by it is missing:
-asm-parse.cc $(FROM_ASM_PARSE_YY): bison.stamp
+$(srcdir)/asm-parse.cc $(FROM_ASM_PARSE_YY): $(srcdir)/bison++.stamp
@if test ! -f $@; then \
- @rm -f bison.stamp; \
- $(MAKE) $(AM_MAKEFLAGS) bison.stamp; \
+ rm -f $(srcdir)/bison++.stamp; \
+ $(MAKE) $(AM_MAKEFLAGS) $(srcdir)/bison++.stamp; \
fi
MAINTAINERCLEANFILES = asm-scan.ll asm-scan.yy $(FROM_ASM_PARSE_YY)
Index: config/Makefile.am
--- config/Makefile.am (revision 135)
+++ config/Makefile.am (working copy)
@@ -1,6 +1,8 @@
## Makefile.am -- Process this file with automake to produce Makefile.in
##
+dist_noinst_SCRIPTS = move-if-change bison++
+
EXTRA_DIST = $(SPECIFIC_MACROS) $(STANDARD_MACROS) $(SPECIFIC_TOOLS)
MAINTAINERCLEANFILES = \
Index: config/bison++
--- config/bison++ (revision 0)
+++ config/bison++ (revision 136)
@@ -0,0 +1,49 @@
+#! /bin/sh
+
+# Any tool failure is a failure of the script.
+set -e
+
+# bison++ SRCDIR INPUT OUTPUT OPTIONS
+# -----------------------------------
+
+me=$(basename $0)
+auxdir=$(cd $(dirname $0) && pwd)
+
+srcdir=$1
+shift
+input=$1
+shift
+output=$1
+shift
+options="-S lalr1.cc $@"
+
+# Alexandre Duret-Lutz also notes that in VPATH-builds $(srcdir) can
+# be an absolute path depending on how ./configure is called ...
+# In that case
+
+# bison $(srcdir)/parsetiger.yy [...]
+
+# will hard code the path in the maintainer's tree. Hence, do not use
+# paths with Bison, chdir there.
+
+# A tmp dir.
+tmp=$output.dir
+rm -rf $tmp
+mkdir $tmp
+
+# Compile in this dir.
+# Don't use `ln -s' as its semantics of paths sucks.
+cp $srcdir/$input $tmp
+cd $tmp
+bison $options -S lalr1.cc $input -o $output
+for file in *
+do
+ case $file in
+ $input) ;;
+ *) $auxdir/move-if-change $file ../$srcdir/$file;;
+ esac
+done
+
+# Get rid of the tmp dir.
+cd ..
+rm -rf $tmp
Index: config/move-if-change
--- config/move-if-change (revision 0)
+++ config/move-if-change (revision 136)
@@ -0,0 +1,18 @@
+#!/bin/sh
+# Like mv $1 $2, but if the files are the same, just delete $1.
+# Status is 0 if $2 is changed, 1 otherwise.
+if
+test -r $2
+then
+if
+cmp -s $1 $2
+then
+echo $2 is unchanged
+rm -f $1
+else
+mv -f $1 $2
+fi
+else
+mv -f $1 $2
+fi
+
1
0
To avoid svn failure, I suggest you to remove src/inst/Makefile.am
before to `svn update'. `bootstrap' must also be launch to create
`nodes.mk' for the first time.
Index: ChangeLog
from Benoît Perrot <benoit(a)lrde.epita.fr>
* dev/inst-nodes-mk-gen.py: Split into...
* src/inst/Makefile.am: This file.
* bootstrap: Ask for nodes.mk generation.
2004-10-03 Benoît Perrot <benoit(a)lrde.epita.fr>
Index: src/inst/Makefile.am
--- src/inst/Makefile.am (revision 0)
+++ src/inst/Makefile.am (revision 134)
@@ -0,0 +1,59 @@
+include $(srcdir)/nodes.mk
+
+INCLUDES = -I $(top_srcdir)/src -I $(top_builddir)/src
+
+BUILT_SOURCES = \
+ $(FROM_INST_NODES_GEN_PY) inst-nodes-gen.stamp \
+ program_builder.hh inst-builder-gen.stamp \
+ program_solver.hh program_solver.cc inst-solver-gen.stamp
+
+# This code comes from "Handling Tools that Produce Many Outputs",
+# from the Automake documentation.
+
+nodes.mk: $(top_srcdir)/dev/inst-nodes-mk-gen.py $(top_srcdir)/dev/nolimips.xml
+ $(top_srcdir)/dev/inst-nodes-mk-gen.py < $(top_srcdir)/dev/nolimips.xml >$@.tmp
+ mv -f $@.tmp $@
+
+inst-nodes-gen.stamp: $(top_srcdir)/dev/inst-nodes-gen.py $(top_srcdir)/dev/nolimips.xml
+ @rm -rf $@.tmp
+ @touch $@.tmp
+ $(top_srcdir)/dev/inst-nodes-gen.py < $(top_srcdir)/dev/nolimips.xml
+ @mv -f $@.tmp $@
+$(FROM_INST_NODES_GEN_PY): inst-nodes-gen.stamp
+
+inst-builder-gen.stamp: $(top_srcdir)/dev/inst-builder-gen.py $(top_srcdir)/dev/nolimips.xml
+ @rm -rf $@.tmp
+ @touch $@.tmp
+ $(top_srcdir)/dev/inst-builder-gen.py < $(top_srcdir)/dev/nolimips.xml
+ @mv -f $@.tmp $@
+program_builder.hh: inst-builder-gen.stamp
+
+inst-solver-gen.stamp: $(top_srcdir)/dev/inst-solver-gen.py $(top_srcdir)/dev/nolimips.xml
+ @rm -rf $@.tmp
+ @touch $@.tmp
+ $(top_srcdir)/dev/inst-solver-gen.py < $(top_srcdir)/dev/nolimips.xml
+ @mv -f $@.tmp $@
+program_solver.hh program_solver.cc: inst-solver-gen.stamp
+
+
+MAINTAINERCLEANFILES = \
+ $(FROM_INST_NODES_GEN_PY) \
+ program_builder.hh \
+ program_solver.hh program_solver.cc
+
+noinst_LIBRARIES = libinst.a
+libinst_a_SOURCES = \
+ $(FROM_INST_NODES_GEN_PY) inst-nodes-gen.stamp \
+ register.hh \
+ exp.hh exp.cc \
+ exp-visitor.hh \
+ inst.hh \
+ program.hh \
+ label.hh label.cc \
+ section.hh \
+ text_section.hh text_section.cc \
+ data_section.hh data_section.cc \
+ program.hh \
+ program_builder.hh program_builder.cc inst-builder-gen.stamp \
+ program_solver.hh program_solver.cc inst-solver-gen.stamp \
+ inst-tasks.hh inst-tasks.cc
Index: bootstrap
--- bootstrap (revision 133)
+++ bootstrap (working copy)
@@ -1,4 +1,4 @@
#!/bin/sh
-cd src/inst && ../../dev/inst-nodes-mk-gen.py < ../../dev/nolimips.xml && cd -
+cd src/inst && ../../dev/inst-nodes-mk-gen.py < ../../dev/nolimips.xml > nodes.mk && cd -
autoreconf -f -v -i -m
Index: dev/inst-nodes-mk-gen.py
--- dev/inst-nodes-mk-gen.py (revision 133)
+++ dev/inst-nodes-mk-gen.py (working copy)
@@ -29,11 +29,7 @@
parser = nolimips.InstructionSetParser()
instructions = parser.parse(sys.stdin)
-sys.stdout = file("Makefile.am.tmp", "w")
-
-print """INCLUDES = -I $(top_srcdir)/src -I $(top_builddir)/src
-
-FROM_INST_NODES_GEN_PY = \\"""
+print "FROM_INST_NODES_GEN_PY = \\"
for i in range(0, len(instructions)):
if instructions[i].level == "native":
line = "\t"
@@ -43,62 +39,3 @@
print """ decl.hh \\
all.hh \\
visitor.hh"""
-
-print """
-BUILT_SOURCES = \\
- $(FROM_INST_NODES_GEN_PY) inst-nodes-gen.stamp \\
- program_builder.hh inst-builder-gen.stamp \\
- program_solver.hh program_solver.cc inst-solver-gen.stamp
-
-# This code comes from \"Handling Tools that Produce Many Outputs\",
-# from the Automake documentation.
-
-inst-nodes-gen.stamp: $(top_srcdir)/dev/inst-nodes-gen.py $(top_srcdir)/dev/nolimips.xml
- @rm -rf $@.tmp
- @touch $@.tmp
- $(top_srcdir)/dev/inst-nodes-gen.py < $(top_srcdir)/dev/nolimips.xml
- @mv -f $@.tmp $@
-$(FROM_INST_NODES_GEN_PY): inst-nodes-gen.stamp
-
-inst-builder-gen.stamp: $(top_srcdir)/dev/inst-builder-gen.py $(top_srcdir)/dev/nolimips.xml
- @rm -rf $@.tmp
- @touch $@.tmp
- $(top_srcdir)/dev/inst-builder-gen.py < $(top_srcdir)/dev/nolimips.xml
- @mv -f $@.tmp $@
-program_builder.hh: inst-builder-gen.stamp
-
-inst-solver-gen.stamp: $(top_srcdir)/dev/inst-solver-gen.py $(top_srcdir)/dev/nolimips.xml
- @rm -rf $@.tmp
- @touch $@.tmp
- $(top_srcdir)/dev/inst-solver-gen.py < $(top_srcdir)/dev/nolimips.xml
- @mv -f $@.tmp $@
-program_solver.hh program_solver.cc: inst-solver-gen.stamp
-
-
-MAINTAINERCLEANFILES = \\
- $(FROM_INST_NODES_GEN_PY) \\
- program_builder.hh \\
- program_solver.hh program_solver.cc
-
-noinst_LIBRARIES = libinst.a
-libinst_a_SOURCES = \\
- $(FROM_INST_NODES_GEN_PY) inst-nodes-gen.stamp \\
- register.hh \\
- exp.hh exp.cc \\
- exp-visitor.hh \\
- inst.hh \\
- program.hh \\
- label.hh label.cc \\
- section.hh \\
- text_section.hh text_section.cc \\
- data_section.hh data_section.cc \\
- program.hh \\
- program_builder.hh program_builder.cc inst-builder-gen.stamp \\
- program_solver.hh program_solver.cc inst-solver-gen.stamp \\
- inst-tasks.hh inst-tasks.cc"""
-
-## Epilogue
-sys.stdout.close()
-sys.stdout = sys.__stdout__
-nolimips.lazy_overwrite("Makefile.am", "Makefile.am.tmp")
-os.remove("Makefile.am.tmp")
1
0