Vegan (well, mainly) Cookbook Suggestions : Yr golygfa o Hescwm Uchaf, rhif 21

Cookbooks are one of the parts of the book trade that just seems to be forever growing. There are an overwhelming number available and, well, it can be a bit of lottery if just you’re looking for a cookbook you will actually use when you make your dinner. Below, some books we cook from often, and which you might also like to cook from.

The Joy Of Vegan Cooking

Amanda Grant’s The Joy Of Vegan Cookery is, despite its slightly hokey title, one of the few vegan cookbooks I’d absolutely recommend. It has a cheerful tone, presents straightforward recipes that use fresh ingredients to make good food. It was my everyday cookbook for an extended period, and I still use it regularly. The battered and stained state of my copy attests to its “higher then normal number of recipes that you will actually cook” quotient.

  • Sample recipe - Pacific Rim Curry

The Green Roasting Tin

Rukmini Iyer’s Green Roasting Tin’s gimmick is straightforward - all the recipes involve sticking everything into one pot and then in the oven. The most complicated involved opening the oven a bit later and stirring. It’s dividend into vegan and vegetarian recipes, and then into quick, medium, and slow. Most of the vegetarian recipes can be easily veganised, often by just not putting cheese on the top.

The recipes are simple, imaginative, veg forward, and delicious. We use it a lot, right now more than weekly.

Veg Every Day

Hugh Fearnley-Whittingstall’s been on something of journey over the years. You might recall one of his earlier books had a picture of him hungrily eyeing a piglet he had tucked under his arm. Well, this book has a picture of him sheltering under a big ole cabbage leaf.

Some terrific recipes, lots of ideas and suggestions beyond recipes and into cooking more widely, working with what’s available in shops, or in your garden, should you have one. Really good, really helpful.

Who doesn’t like cookies? Vegan Cookies Invade Your Cookie Jar is slightly mistitled in that the cookies will not actually make it to your biscuit tin. Banger.

Veganomicon

Everybody needs that recipe book you pull out for a special occasion. For me that used to be Cooking with Stones, but for the past few years it’s been Ira Chandra Moskowitz and Terry Hope Romero’s Veganomicon. It’s big, it’s very American, but it’s fun and punky, and, while I’ve barely scraped the surface, I’ve always been delighted by what I’ve made from it.

  • No direct sample, but you can get the feel of the kinds of recipes in the book by browsing around The Post-Punk Kitchen.


Tagged cooking-with-pete

December Linkfarm

  • A tour of Self - Self is an image-based programming language, similar to Smalltalk. It provides a programming environment that you interact with as the system is running. The runtime is based on the idea of “processes”: each piece of Self code you run has its own process (not an OS process – a Self process) in which it runs until termination. During its runtime it can interact with other objects it can reach, and create new ones.

  • CNN ‘Black Beauty’ was found on Earth in 2011. Now, scientists say it has revealed a new clue to life on Mars - A mineral trapped within a Martian meteorite that fell to Earth has revealed traces of water on Mars that date back 4.45 billion years, according to new research. The zircon grain may contain the oldest direct evidence of ancient hot water on the red planet, which may have provided environments such as hot springs that are associated with life on Earth.

  • The Jujutsu version control system - Omitting details, you can think of Jujutsu (hereafter “jj”) as a new Git frontend. The underlying data is still stored in Git. The difference is how you interact with your files locally, with a different conceptual model and a different set of commands.

  • A working game of Tetris in Conway’s Game of Life
    Splendid.

  • Never Forgive Them
    Ed Zitron directs his fearful anger at the technology industry that actively makes our lives worse, when it could so easily be making them better.

Games that are quite old but are still pretty fresh in my mind because I, too, am quite old

AI Nonsense

Jez’s Weird Ongoing Interest In Software From The Early History Of Unix

  • Customizing ed(1) - ed is too simple to be customizable, right? Maybe it is not customizable, but the environment around it is!

  • Beautiful Documents with Groff


Tagged linkfarm

STinC++ - Macro, a macro processor, step two : Yr golygfa o Hescwm Uchaf, rhif 20

STinC++ rewrites the programs in Software Tools in Pascal using C++

In Chapter 8 of Software Tools in Pascal, Brian Kernigan and PJ Plauger outline three stages in the development of macro, an m4-lite macro processor:

  1. Simple text replacement, “the most elementary form of macro processing”

  2. “A much bigger job”, expanding the processor to allow macros with arguments

  3. Extending the processor with extra built-in operations that help write “truly powerful macros”, such as conditionals and arithmetic.

I described step one earlier, where simple text substitution was achieved by pushing tokens back onto the input stream, in order that they could then be read and processed as if they’d had been in the input stream all along. This works even in the case with macro definitions which expanded to other macro definitions.

Step two involves extending the processor to handle arguments to macros. For example

define(incr, $1:=$1+1)
incr(x)
incr(y)

expands to

x:=x+1
y:=y+1

The rules as before still apply - if arguments are themselves macros, they must be expanded out as the macro is evaluated. Thus

define(x, a[i])
define(incr, $1:=$1+1)
incr(x)

becomes

a[i]=a[i]+1

Within a replacement string, any dollar sign $ followed by a digit is replaced by the argument corresponding to that digit. Arguments are written as a parenthesized list of strings following the identifier, e.g.

ident(arg1, arg2, ...)

So $1 is replaced in the arguments string by arg1, $2 by arg2, and so on; $0 is replaced by ident. Missing arguments are taken as empty strings; extra arguments are ignored.

Macros with arguments

At the end of step one, our text replacement implementation was a one-liner

void macro_processor::apply_macro(std::string const& tok) {
  buffer_.push_tokens(macro_definition(tok));
}

Having identified a macro, look up it’s definition, and pop the resulting tokens onto the front of the input buffer.

We need to get a little bit fancier for our argument substitution. For a start, we need to see if there are any arguments.

using token_seq = std::deque<std::string>;

std::vector<token_seq> macro_processor::gather_arguments() {
  auto argument_tokens = parenthesised_sequence(this); (1)
  if (argument_tokens.empty())
    return { };

  argument_tokens.pop_front(); (2)
  argument_tokens.pop_back();

  auto arguments = std::vector<token_seq> { };
  auto tokens = token_buffer { argument_tokens };

  while(tokens.token_available()) {
    skip_whitespace(tokens);

    arguments.push_back(next_argument(tokens)); (3)

    if (tokens.token_available())
      tokens.pop_token(); // must be a comma
  }

  return arguments; (4)
}
  1. parenthesised_sequence looks for a ( and, should it find one reads all the following tokens up to and including it reaches a balancing ). It will read parentheses within parentheses properly, so it either returns a proper argument sequence or throws an exception because we’ve hit the end of the input.

  2. Drop the leading ( and trailing ).

  3. next_argument reads tokens until it hits a comma. It also understand parentheses.

  4. What we end up with is a vector of vector of tokens, with leading whitespace and commas stripped out.

With our list of arguments to hand, we can simply proceed through the macro definition plucking off each token in turn. If it isn’t a $ (because $ is a token in its own right) we can simply carry on, but if it does we can reach into our argument list instead.

void macro_processor::apply_macro(std::string const& tok) {
  auto const arguments = gather_arguments();
  auto definition = token_buffer { macro_definition(tok) };

  auto with_arg_substitution = token_seq { };
  while (definition.token_available()) {
    while (not_reached(definition, Dollar))
      with_arg_substitution += definition.pop_token();

    if (is_next(definition, Dollar))
      with_arg_substitution += argument_substitution(definition, arguments);
  }

  buffer_.push_tokens(with_arg_substitution);
}

token_seq argument_substitution(
    token_buffer& definition,
    std::vector<token_seq> const& arguments
) {
  auto const dollar = definition.pop_token(); (1)
  auto const index_tok =
    definition.token_available() ? definition.peek_token() : ""; (2)
  auto const index = argument_index(index_tok); (3)

  if (index == -1) (4)
    return { dollar };

  definition.pop_token(); (5)
  return (index < arguments.size()) (6)
    ? arguments[index]
    : token_seq { };
}

token_seq& operator+=(token_seq& seq, std::string const& tok) { (7)
    seq.push_back(tok);
    return seq;
}
  1. Grab that $.

  2. Look ahead to the argument index.

  3. Try to convert to an integer

  4. Something’s gone wrong, so output $ and continue.

  5. Pop off and discard the index token.

  6. Look the matching argument in the argument list.

  7. Yes, this is a bit naughty but I think it reads better here.

At the end of apply_macro we’ve looped over the macro definition, dropped in any arguments we need, and pushed the whole shebang back onto the input buffer_. As before, those tokens are then read and processed as normal, so further macros within macros will be expanded as we find them. Job done!

That is pretty much it. It took a little a bit of back and forth to get there, and I initially tried to push everything directly into buffer_ but, appropriately enough, I needed a bit more buffering[1]. Adding the name token_seq certainly helped clarify things, and once I’d alighted on it, bits of duplication started appearing that I was able to lift out. But, overall, step two really wasn’t the “much bigger job” that Kernighan and Plauger had threatened.

Really, though?

If you’ve been following closely, you might have seen that code I’ve presented does not, in fact, do what I described at the start. Specifically, it doesn’t handle $0, and this is simply because I forgot about it. The bulk of the work is in the argument list and substitution, and once I had that going, I felt like I’d finished and didn’t notice until later.

There’s another, more significant, problem too. But I’ll leave that as a teaser for step three, building a “truly powerful” macro processor.

Source code

Source code for this program, indeed the whole project, is available in the stiX GitHub repository. macro is the only program in Chapter 8.

Endnotes

This whole business springs from Software Tools in Pascal and Software Tools, both by Brian W Kernighan and PJ Plauger. I love these books and commend them to you. They are both still in print, but new copies are wildly expensive. Happily, there are plenty of second-hand copies around, or you can borrow them from The Internet Archive using the links above.

I started using JetBrain‘s CLion IDE back at the start of all this - it was good then, and it’s got gently better and better since. It‘s a really good tool, and I‘m more than content to spend money on it.


Tagged code, and software-tools-in-c++
Older posts are available in the archive or through tags.


Jez Higgins

Freelance software grandad
software created
extended or repaired


Jez Higgins

Freelance software grandad
software created
extended or repaired


Jez Higgins

Freelance software grandad
software created
extended or repaired



Jez Higgins

Freelance software grandad
software created
extended or repaired


Jez Higgins

Freelance software grandad
software created
extended or repaired


Jez Higgins

Freelance software grandad
software created
extended or repaired