summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Ankarstr\xf6m <john@ankarstrom.se>2021-06-02 12:57:24 +0200
committerJohn Ankarstr\xf6m <john@ankarstrom.se>2021-06-02 14:14:13 +0200
commitb61fcab3baf91ecd4b2ad4185e591cf339ad2b34 (patch)
tree9091676b4b07be854408b31e0be1b6d5eb5028e6
downloadref-b61fcab3baf91ecd4b2ad4185e591cf339ad2b34.tar.gz
First commit
-rwxr-xr-xexbin0 -> 8164 bytes
-rw-r--r--greet.c35
-rw-r--r--greet.ms48
-rwxr-xr-xre123
4 files changed, 206 insertions, 0 deletions
diff --git a/ex b/ex
new file mode 100755
index 0000000..56becd2
--- /dev/null
+++ b/ex
Binary files differ
diff --git a/greet.c b/greet.c
new file mode 100644
index 0000000..9d524ae
--- /dev/null
+++ b/greet.c
@@ -0,0 +1,35 @@
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+main(int argc, char *argv[])
+{
+ char *people;
+ int i, size, written;
+
+ people = NULL;
+ size = 0;
+ written = 0;
+
+args: if(argc==1){
+ fprintf(stderr, "usage: %s person ...\n", argv[0]);
+ return 1;
+ }
+ else if(argc==2)
+ people = argv[1];
+ else
+ for(i = 1; i<argc; i++){
+ if(written+strlen(argv[i])>size){
+ size += written+strlen(argv[i])+20;
+ people = realloc(people, size+1);
+ if(people==NULL) err(1, "realloc");
+ }
+concat: if(i==argc-1) strcat(people, " and ");
+ else if(i>1) strcat(people, ", ");
+ strcat(people, argv[i]);
+ }
+
+end: printf("Hello %s!\n", people);
+}
diff --git a/greet.ms b/greet.ms
new file mode 100644
index 0000000..58a8a55
--- /dev/null
+++ b/greet.ms
@@ -0,0 +1,48 @@
+.TL
+.BI greet ,
+an example C program
+.AU
+John Ankarström
+.AB
+This is the implementation of
+.I greet ,
+a simple C program which greets the people
+supplied as arguments on the command line.
+.AE
+.Re greet.c:/^#include/
+.LP
+First, we include all necessary libraries.
+.Re greet.c:/^main(/
+.LP
+As the program's operation is quite simple,
+all its code will be contained in the
+.I main
+function.
+.Re greet.c:/^args:/
+.LP
+This is where the main operation of the program takes place.
+At least one argument is required,
+in which case it is simply assigned to the
+.I people
+string.
+If multiple arguments are present,
+each is appended to the string in an intelligent way.
+At each iteration, it is made certain that the people string
+is large enough to contain the new name (and then some).
+.Re greet.c:/^concat:/
+.LP
+If it is the last argument,
+the appendix is prefixed with the string " and ".
+Otherwise, unless it is the first argument,
+it is prefixed with a comma and a space.
+Then, the argument is appended to the
+.I people
+string.
+.Re greet.c:/^end:/
+.LP
+Finally, the people are greeted.
+As the program ends here,
+there is no need to explicitly free the
+.I pepole
+string;
+the kernel will take care of it for us.
diff --git a/re b/re
new file mode 100755
index 0000000..8e0677e
--- /dev/null
+++ b/re
@@ -0,0 +1,123 @@
+#!/usr/bin/perl
+
+# re -- reference-based literate programming system
+
+use strict;
+use warnings;
+use POSIX::Regex qw/:all/;
+
+my $bytes;
+my $count;
+my %bytes; # file => current byte
+my %file_locations; # file => [location, ...]
+my %files; # byte => file
+my %handles; # file => handle
+my %lines; # file => current line
+my %locations; # byte => location (i.e. byte in source file)
+my @references;
+
+die "usage: $0 file\n" if @ARGV != 1;
+open my $fh, '<', $ARGV[0] or die "could not open $ARGV[0]: $!\n";
+
+# collect references
+$bytes = 0;
+while (<$fh>) {
+ $bytes += length($_);
+ push @references, [$bytes, $1] if /^\.\s*Re\s+(.*)/;
+}
+
+# find referenced locations
+for (@references) {
+ my ($bytes, $ref) = @$_;
+ my $loc = -1;
+
+ goto invalid if not $ref =~ /^([^:]+):(.*)/;
+ my ($file, $ident) = ($1, $2);
+
+ if (not exists $handles{$file}) {
+ open my $fh, '<', $file or die "could not open $file: $!\n";
+ $handles{$file} = $fh;
+ $bytes{$file} = 0;
+ $lines{$file} = 0;
+ }
+
+ if ($ident =~ /^(\d+)$/) {
+ my $line = $1;
+ if ($ident <= $lines{$file}) {
+ seek $handles{$file}, 0, 0;
+ $bytes{$file} = 0;
+ $lines{$file} = 0;
+ }
+ local $_;
+ while ($_ = readline $handles{$file}) {
+ $lines{$file}++;
+ if ($lines{$file} == $line) {
+ $loc = $bytes{$file};
+ last;
+ }
+ $bytes{$file} += length($_);
+ }
+ } elsif ($ident =~ m{^/(.*)/$}) {
+ my $rx = new POSIX::Regex($1);
+ seek $handles{$file}, 0, 0;
+ $bytes{$file} = 0;
+ $lines{$file} = 0;
+ local $_;
+ while ($_ = readline $handles{$file}) {
+ $lines{$file}++;
+ if ($rx->match($_)) {
+ $loc = $bytes{$file};
+ last;
+ }
+ $bytes{$file} += length($_);
+ }
+ } else {
+ goto invalid;
+ }
+
+ die "could not find location $ident in $file\n" if $loc == -1;
+ $locations{$bytes} = $loc;
+ $files{$bytes} = $file;
+ if (exists $file_locations{$file}) {
+ push @{$file_locations{$file}}, $loc;
+ } else {
+ $file_locations{$file} = [];
+ }
+
+ next;
+invalid:
+ die "invalid syntax: $ref at $bytes\n";
+}
+
+# intertwine
+seek $fh, 0, 0;
+$bytes = 0;
+$count = 0;
+while (<$fh>) {
+ $bytes += length($_);
+ goto normal if not @references;
+ my $ref_bytes = $references[0][0];
+ if ($bytes == $ref_bytes) {
+ shift @references;
+ my $file = $files{$bytes};
+ my $end = shift @{$file_locations{$file}};
+ my $loc = $locations{$bytes};
+
+ print "\n$file:$loc-$end\n";
+
+ seek $handles{$file}, $loc, 0;
+ local $_;
+ my $bytes = $loc;
+ while ($_ = readline $handles{$file}) {
+ $bytes += length($_);
+ last if $end and $bytes > $end;
+ print;
+ }
+ next;
+ }
+normal:
+ print;
+}
+
+close $_ for values %handles;
+close $fh;