diff options
author | John Ankarstr\xf6m <john@ankarstrom.se> | 2021-06-02 12:57:24 +0200 |
---|---|---|
committer | John Ankarstr\xf6m <john@ankarstrom.se> | 2021-06-02 14:14:13 +0200 |
commit | b61fcab3baf91ecd4b2ad4185e591cf339ad2b34 (patch) | |
tree | 9091676b4b07be854408b31e0be1b6d5eb5028e6 | |
download | ref-b61fcab3baf91ecd4b2ad4185e591cf339ad2b34.tar.gz |
First commit
-rwxr-xr-x | ex | bin | 0 -> 8164 bytes | |||
-rw-r--r-- | greet.c | 35 | ||||
-rw-r--r-- | greet.ms | 48 | ||||
-rwxr-xr-x | re | 123 |
4 files changed, 206 insertions, 0 deletions
Binary files differ @@ -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. @@ -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; |