diff options
| author | Mohammad S Anwar <mohammad.anwar@yahoo.com> | 2019-10-13 21:21:23 +0100 |
|---|---|---|
| committer | Mohammad S Anwar <mohammad.anwar@yahoo.com> | 2019-10-13 21:21:23 +0100 |
| commit | 7a7ff0194d2f038d7e9644a019fa5a17ad4925aa (patch) | |
| tree | 830408cdfec40e3a9fe9f51aeedfae3cee30c1a9 /challenge-029 | |
| parent | 9413aa77625e076bc96176b7ae8b932cb78d0d9e (diff) | |
| download | perlweeklychallenge-club-7a7ff0194d2f038d7e9644a019fa5a17ad4925aa.tar.gz perlweeklychallenge-club-7a7ff0194d2f038d7e9644a019fa5a17ad4925aa.tar.bz2 perlweeklychallenge-club-7a7ff0194d2f038d7e9644a019fa5a17ad4925aa.zip | |
- Added solutions by Colin Crain.
Diffstat (limited to 'challenge-029')
| -rw-r--r-- | challenge-029/colin-crain/perl5/ch-1.pl | 91 | ||||
| -rw-r--r-- | challenge-029/colin-crain/perl5/ch-2.pl | 154 |
2 files changed, 245 insertions, 0 deletions
diff --git a/challenge-029/colin-crain/perl5/ch-1.pl b/challenge-029/colin-crain/perl5/ch-1.pl new file mode 100644 index 0000000000..479978c97d --- /dev/null +++ b/challenge-029/colin-crain/perl5/ch-1.pl @@ -0,0 +1,91 @@ +#! /opt/local/bin/perl +# +# brace_expansion.pl +# +# 29 Task #1: +# Write a script to demonstrate brace expansion. For example, script would take +# command line argument Perl {Daily,Weekly,Monthly,Yearly} Challenge and should +# expand it and print like below: +# +# Perl Daily Challenge +# +# Perl Weekly Challenge +# +# Perl Monthly Challenge +# +# Perl Yearly Challenge +# +# method: this seems like a job for a regex. Although not specified, let's make +# it recursive, to accommodate multiple bracketed blocks. Nesting braces, +# on the other hand, make no sense, won't parse right and need to be +# escaped to avoid unexpected results. Both inside and outside the block +# whitespace is preserved. The expanded text is inserted as is without +# additional spacing. Originally I had allowed whitespace inside the block +# for readability, which was ignored on rendering, but removed this to +# maximize flexability in inserting text fragments. Escaped brackets are +# ignored by the parser and passed through unchanged. +# +# results: +# $ ./brace_expansion.pl "Perl{ista's,esque,ite,escent, One Knit Two} {Daily,Weekly,Monthly,Yearly} Challenge" +# Perlista's Daily Challenge +# Perlista's Weekly Challenge +# Perlista's Monthly Challenge +# Perlista's Yearly Challenge +# Perlesque Daily Challenge +# Perlesque Weekly Challenge +# Perlesque Monthly Challenge +# Perlesque Yearly Challenge +# Perlite Daily Challenge +# Perlite Weekly Challenge +# Perlite Monthly Challenge +# Perlite Yearly Challenge +# Perlescent Daily Challenge +# Perlescent Weekly Challenge +# Perlescent Monthly Challenge +# Perlescent Yearly Challenge +# Perl One Knit Two Daily Challenge +# Perl One Knit Two Weekly Challenge +# Perl One Knit Two Monthly Challenge +# Perl One Knit Two Yearly Challenge +# +# 2019 colin crain +## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## + +use warnings; +use strict; +use feature ":5.26"; + +## ## ## ## ## MAIN + +my $input = shift @ARGV; + +my @output = expand_braces($input); + +say (join "\n", @output); + +## ## ## ## ## SUBS + +sub expand_braces { + my $input = shift; + my @expanded; + + if ( $input =~ m/ ^(.*?) ## group 1: from the beginning, whatever was before the brackets, minimally matched + (?<!\\)\{ ## a left bracket not preceeded by a backslash + (.*?) ## group 2: the bracketed text list, minimally matched + (?<!\\)\} ## a right bracket not preceeded by a backslash + (.*?)$ /x ) { ## group 3: whatever is left until the end, minimally matched + my $pre = $1; + my $post = $3; + my @wordlist = split /,/, $2; + + ## insert the word and recursively build an expanded array + for my $word ( @wordlist ){ + push @expanded, expand_braces("$pre$word$post"); + } + return @expanded; + } + else { + ## if no match pass the input right back out + return $input; + } +} diff --git a/challenge-029/colin-crain/perl5/ch-2.pl b/challenge-029/colin-crain/perl5/ch-2.pl new file mode 100644 index 0000000000..ee2ba2535a --- /dev/null +++ b/challenge-029/colin-crain/perl5/ch-2.pl @@ -0,0 +1,154 @@ +#! /opt/local/bin/perl +# +# c_function.pl +# +# 29 Task #2: +# Write a script to demonstrate calling a C function. It could be any +# user defined or standard C function. +# +# method: +# The easiest way to go about this is to use the module Inline::C. One still +# may need some familiarity with perlapi and perhaps perlguts to interact smoothly +# with Perl, but much less so than grappling directly with XS. +# +# make_primes( int num_primes, int quantity_asked ) +# To demonstrate the use of a C function, we will first need +# something that can really benefit from the added speed, in +# this case a rewrite of the prime-finding by trial division +# function last seen in PWC #23. This was rewritten in C with a +# few more optimizations added, and further modified to return +# a requested number of values at the end of a generated list +# of a specified number of primes. So we pass in values for the +# number of primes to generate and the number from the end of +# that list to display. To produce this variable-length list of +# values we will manually place the requested number of items +# on the Stack to be returned by the function. (Alternately we +# could insert them in a Perl array and return a reference) +# Because we do this manually, the function itself returns type +# void. Inline::C provides macros to perform this magic of +# directly manipulating the Stack, which we employ in the +# example. If we request more primes than we generate, rather +# than return a short list we choose to return no elements at +# all. +# +# In this example we use the perlapi functions newSViv( int ) +# -- which creates a new SV integer value, and sv_2mortal( SV +# ) which flags a variable for garbage collection when is no +# longer needed to be around. +# +# print_primes( *SV some_prime, ... ): +# Once we have a list of requested primes, we might wish to examine +# them in tabular form. This function takes a variable sized list of +# integers and prints such a table to STDOUT. +# +# usage: ./c_function.pl 2000000 10 +# This produces a table of the last 10 primes of a list of 2,000,000 +# +# +# +# 2019 colin crain +## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## + + + +use warnings; +use strict; +use feature ":5.26"; + +## ## ## ## ## MAIN + +## fetch the number of primes to generate and the number requested to be displayed off the end of that list +my ($number_of_primes, $number_requested) = @ARGV; + +print_primes( make_primes($number_of_primes, $number_requested) ); + +use Inline C => <<'END_OF_C_CODE'; +void make_primes( int num_primes, int quantity_asked ) { +/* returns array of Perl SV*s on the Stack, + the quantity_asked number of primes from the + end of a generated list of primes num_primes long. + The unreturned primes are not kept. */ + +/* the bool type seems to already be defined somewhere in the headers + loaded by Inline::C so this does not appear to be strictly required. */ + #include <stdbool.h> + +/* initialize variables associated with accessing the Stack */ + Inline_Stack_Vars; + +/* reset the stack pointer before we push output data to it */ + Inline_Stack_Reset; + +/* if the number of primes requested is greater than the number generated, fail and return (-1) */ + if ( quantity_asked > num_primes ) { + Inline_Stack_Push( sv_2mortal(newSViv( -1 )) ); + +/* make sure we call this to wrap up the stack */ + Inline_Stack_Done; + return; + } + +/* we will only push the first prime, 2 on if it will be required in the requested number of values to be returned */ + if ( quantity_asked == num_primes ) { + +/* if yes, to push the integer 2 on the Stack and start the prime list. We first cast it into a + Perl SV, then mark it as "mortal", to be collected as once copied to the Stack it is no longer + necessary and if allowed to remain will leak memory */ + Inline_Stack_Push( sv_2mortal(newSViv( 2 )) ); + } + + + int candidate; + int count = 0; + for( candidate = 3; count <= (num_primes - 2); candidate += 2 ) { + int sqrt_candidate = sqrt( candidate ); + bool is_prime = true; + int test; + for( test = 3; ( test <= sqrt_candidate ) && ( is_prime == 1 ); test += 2 ) { + if( candidate % test == 0 ) { + is_prime = false; + } + } + if( is_prime == true ) { + count++; + + if (count > num_primes - (quantity_asked + 1) ) { + + /* as above, we need to first cast data as a Perl SV* type, + then label it mortal for collection after it is copied over to the Stack*/ + Inline_Stack_Push( sv_2mortal(newSViv( candidate )) ); + } + } + } + + /* make sure we call this to wrap up the Stack */ + Inline_Stack_Done; +} + +void print_primes ( SV* some_prime, ... ){ +/* given a varible length list of primes, prints out a nice little enumerated table of the primes requested */ + +/* initialize variables associated with accessing the Stack */ + Inline_Stack_Vars; + + int idx; + int count = 1; + + printf("request # | prime\n"); + printf("-------------+-----------\n"); + +/* Inline_Stack_Items contains the number of values on the Stack */ +/* Inline_Stack_Item(idx) contains the value at that index */ +/* SvIV coerces an SV* into a integer value */ + for (idx = 0; idx < Inline_Stack_Items; idx++, count++) { + printf("%5d | %7d\n", count, SvIV( Inline_Stack_Item(idx) )); + } + + /* null out any data in the Stack */ + Inline_Stack_Void; + +/* make sure we call this to wrap up the Stack */ + Inline_Stack_Done; +} + +END_OF_C_CODE |
