Anti-nuisance lawsuit warning: The purpose of these notes is to remind me, Zoegond, of stuff or to help me work stuff out. They may contain mistakes.

Quick

  • ($a, $b....) = unpack("A2A7...", $packed)
  • push( array, list )

Saturday, December 29, 2012

Compile-time actions for FORTH-style structures

Assumptions:
NFA is the address that the next instruction will be compiled at
JC is a conditional jump
JP is an unconditional jump
All jump operands are absolute and take up 1 address cell
poke n, x = place x in address n
CASE..OF..ENDOF..ENDCASE can have unconditionally executed code anywhere inside the CASE but outside any OF clauses

IF
compile "JC 0" ; jump past the if clause
push NFA-1 ; address of the JC operand

ELSE ; may not be present
compile "JP 0" ; jump past the else clause
pop JC_ADDR
poke JC_ADDR, NFA ; fill in the JC operand of the IF code
push NFA-1 ; address of the JC operand

ENDIF
pop J_ADDR
poke J_ADDR, NFA ; fill in the JP operand of the ELSE code (or the JC of the IF if there was no ELSE clause)

--

BEGIN
push NFA ; to be used by REPEAT

WHILE
compile "JC 0" ; jump past the end of the loop
push NFA-1 ; address of the JC operand

REPEAT
pop JC_OUT_ADDR
pop JC_TOP_ADDR
compile "JP JC_TOP_ADDR" ; jump back to the BEGIN
poke JC_OUT_ADDR, NFA ; fill in the JC operand of the jump in WHILE

--

CASE
push 0 ; count of OF clauses

OF ; there can be any number of these
compile "JC 0" ; jump past this OF clause
pop COUNT ; temp store of count
push NFA-1 ; address of the JC operand
push COUNT ; restore count to top of stack

ENDOF ; one of these for each OF
compile "JP 0"
pop COUNT ; pop current OF clause count
++COUNT ; increase by exactly 1
pop JC_ADDR
poke JC_ADDR, NFA ; fill in the JC operand of the jump in the OF
push NFA-1 ; address of the JP operand we compiled just now
push COUNT ; put the (incremented) count back on the stack

ENDCASE
pop COUNT
for (I = 1; I <= COUNT; ++I) {
pop JP_ADDR
poke JP_ADDR, NFA ; fill in the JP operand of the jump in each ENDOF
}

Saturday, December 22, 2012

Perl closures

Remember a variable must be declared with my (not local) to retain its value in a closure.


Technique for handlers (or 'how to supply a reference to an instance method'):

set_callback( \&method )

will not work inside an object because at the time the callback is run, Perl doesn't know what object the method belongs to. Instead I use

$copyinst = $inst;
set_callback( sub { &method($copyinst, @_); } )

where $inst is the instance variable (I'm never sure whether the copy is necessary or not). method will now be called properly, and like all methods will have the instance as the first argument, followed by whatever arguments the caller supplies.

There's supposed to be another way round this but I've never been able to make that work.

Day for a given declination of the Sun


\frac{365 \cdot cos^{-1}(\frac{\delta}{-23.45})}{360}

(365 * acos(declination/-23.45)) / 360

An approximation in days from the winter solstice in any year. Good enough for calculating on which days of the year, say, the sun sets at 8pm. Not good enough for eclipses.

NB that acos has two results, one positive and one negative, or to put it another way, the Sun has the same declination on two days each year (eg Mar 21 and Sep 21).

Calculators and programming languages will only return one result (the positive one, ie the day in the first half of the year) - to get the other one, substitute -1*acos(declination/-23.45) in the formula.

(People have asked me to say when the winter solstice is. I assume it's Dec 21, using any more accuracy together with this approximation formula seems pointless).

(People have also been asking me to say what I mean by 'An approximation in days from the winter solstice in any year'. Well, if you put a declination (eg -23.45) into the formula above, and get the result 0, then the answer is '0 days from Dec 21' or 'Dec 21'. If the result was 1, then the answer is '1 days from Dec 21' or 'Dec 22', and so on and so forth.)

Copy constructor

If you don't define a copy constructor - a Thing(const Thing &t)() constructor - the compiler will generate a default one which just copies all the members bit-for-bit.

This is bad because the copy constructor is used, not just for stuff like

Thing t1 = Thing(t0);

but also for initialising arguments to functions, so if you have

void f(Thing a) { ... }

Thing t;
f(t);


the copy constructor will be used when a is created. And if it's the default one, all a's members will be literally and exactly the same as t's, even if their pointers. Particularly bad news if your destructor deletes those pointers - because at the end of f(), ~Thing will be called on a, and the referents of a's pointers are the same as the referents of t's pointers, so when f() has returned, t will have lost those referents.

So, in short, if you want to pass your class to functions, make a copy constructor for it.

sqlite output formats

I hadn't previously noticed that sqlite has output formats other than line and column. In particular there are also the csv and tcl modes.

The difference between csv and tcl modes appears to be that in tcl all items are quoted, and newline is represented as \n, whereas in csv mode items are not always quoted and newline is represented as a newline.

I can't work out the exact rules it uses for quoting in csv mode, it appears to be that an item is quoted if it contains a newline or a separator, and sometimes even if it doesn't contain either of those.

Unfortunately, it doesn't seem possible to tcl mode from the command line, even if you use a script to construct a multi-line command line with the .mode tcl separated from the SQL by a newline. This makes them considerably less useful.

You can however specify -csv on the command line (contrary to my previous assertion). You have to be prepared to parse fields with an embedded newline, but it can be done.

Friday, December 14, 2012

Syntax for parseability

Fascinating - VB, which doesn't require brackets round the expression following 'if', won't allow you to create a subroutine or function called 'then'.

This is presumably because it can't, like the C family, use the trailing ) to tell where the expression ends, and wants to assume that 'then' on the end of a line that began 'if' always delimits it. Btw I see you can't have a variable called 'if' in C.

And Perl throws a syntax error at "$a--5", you have to put "$a- -5". Fascinating.

Even more fascinatingly, mingw C won't accept a--5. I've been expecting far too much of my own expression evaluators.

Followers

Blog Archive