Ctrl+- (Ctrl+Hyphen-Minus) as ShortCut Key? - delphi

It might seem natural to use Ctrl + +, Ctrl + -, and Ctrl + 0 as shortcuts for an application's zoom in, zoom out, and restore default zoom (typically 100 %) actions. Now, in Delphi, I am able to assign Ctrl + + and Ctrl + 0 as shortcuts. The former, though, requires that the plus sign of the main part of the keyboard is used; the plus sign of the numerical keypad cannot be used.
Problem arises, however, when I want to assign Ctrl + - as a shortcut. It simply doesn't work. If I assign "Ctrl+-" in the IDE, the value stored in the ShortCut property is 16495. If we subtract ssCtrl from this, we obtain 111. A work-around, one would believe, would be to assign ShortCut := 45 + ssCtrl, or, equivalently, ShortCut := Menus.ShortCut(45, [ssCtrl]), because ord('-') = 45. But that doesn't work.
However, I have found a working solution: ShortCut := 189 + ssCtrl. I choose 189 because that is the number I receive when I depress the "-" key and listen to the KeyDown event.
So, why am I not happy with this? Well, I am afraid that the constant 189 only is valid on Swedish keyboards. I have tried to read about this, and, as usual, the MSDN documentation is rather clear, but then, who knows how Delphi handles things.

The key code 189 is VK_OEM_MINUS in Windows.pas, so your solution isn't just for Swedes.

the correct to use menu shortcut on the numeric pad is
CtrlNum + for the [+]
CtrlNum - for the [-]
there is a space between Num + and Num -

I'm not sure why you're getting 16495 for Ctrl + -. When I add that shortcut to an action, it gives me 16573, and it does show up on the menu as Ctrl + -, and that shortcut does work.
However, you are correct that Menus.ShortCut(ord('-', [ssCtrl]) does not work. It gives the value 16429 and shows up on the menu as Ctrl + Ins, and Ctrl + Ins works as the shortcut.
Maybe this is a problem with Delphi 2009 and later since they added Unicode.

Related

pgadmin 4 - cannot use select all and undo

I have used pgadmin 4 for months now.
but from about a month ago, suddenly on pgadmin 4 editor, I couldnt do ctrl + a (select all) and ctrl + z (undo).
I still can do other shortcut though like ctrl + c and ctrl + v.
this is not fatal, but very hindering in my work because I couldnt do select all and undo.
and this happened too on the new installation of pgadmin 4 on my vps server. So I think this is now a default behavior on pgadmin 4 ?
I can confirm that ctrl + a and ctrl + z worked on other tabs in the same browser, so it only happened on pgadmin 4.
is there anyway to make these shortcuts to work again ?
any setting that I might accidentally trigger maybe ?
thx.

How to implement a simple stack machine?

I've read a few articles about this, and have understood roughly what is most commonly used. The most simple and common method seems to be reverse Polish notation, which is as follows. To evaluate an expression, the first two operands are pushed onto the stack, an instruction is read, like an operation such as addition, that operator operates on the two topmost elements of the stack, the two topmost elements are popped off and the result is pushed onto the stack. However this only seems to work with the examples I've seen, but not in other cases. Here are some examples:
The expression:
(11 * 22 + 33 * 44) / 121
is noted as the following instructions:
push 11
push 22
mult
push 33
push 44
mult
add
push 121
div
I understand this. Likewise another example in another article is given:
The expression:
(12 + 45) * 98
has instructions:
push 98
push 12
push 45
+
*
I understand this too. But suppose in the first example we wanted to reverse the division like the following:
Instead of:
(11 * 22 + 33 * 44) / 121
have:
121 / (11 * 22 + 33 * 44)
Now instead of pushing 121 right at the end, it seems that it needs to be pushed right at the start and look something like this:
push 121
push 11
push 22
mult
push 33
push 44
mult
add
div
As you can see 121 is the first thing pushed rather than the second last in the original example. However because the other parts is in brackets it should be evaluated first, how do you get around this?
I'm also having the same problem with the other examples I've found. How do you order the values and operations correctly? Do you need to look ahead? Or is there a simple way to just walk across the expression and create the instructions? From what I've read this seems to be most simple way of evaluating expressions, and they seem to imply that writing the instructions is really easy as if you can just run across the expression and create the proper reverse polish notation for it. I'm having trouble understanding how to order the values and instructions in the right way.
As we discussed in the comments, order of evaluation has nothing to do with operator precedence. For example, in Java subexpressions are evaluated left-to right. In C, order of evaluation is unspecified. Rather, it has a concept of sequence points, which basically says "Whatever you need to get done, just make sure it happens before this semicolon."
So your reverse-polish notation can just be constructed left to right without needing to reorder for parentheses. If you're not sure how to construct the RPN at all, pick up a book on parsing or compilers. The Dragon book opens with a detailed example of translating an expression to RPN.
Now, there is one instance where evaluation order does matter. In most languages, && and || short-circuit, so we need to avoid evaluating the RHS in some cases. This can be accomplished with a jump instruction.
For example if we have 1 > 2 && 2 < 3, we might emit the following instructions:
push 1
push 2
>
jmp_f lbl0 ; jump if false to label lbl0
push 2
push 3
<
&&
label lbl0
(Of course, your VM may not have all these instructions, but this is just an example of how to conditionally evaluate expressions)

Does GNU FORTH have an editor?

Chapter 3 of Starting FORTH says,
Now that you've made a block "current", you can list it by simply typing the word L. Unlike LIST, L does not want to be proceeded by a block number; instead it lists the current block.
When I run 180 LIST, I get
Screen 180 not modified
0
...
15
ok
But when I run L, I get an error
:30: Undefined word
>>>L<<<
Backtrace:
$7F0876E99A68 throw
$7F0876EAFDE0 no.extensions
$7F0876E99D28 interpreter-notfound1
What am I doing wrong?
Yes, gForth supports an internal (BLOCK) editor. Start gforth
type: use blocked.fb (a demo page)
type: 1 load
type editor
words will show the editor words,
s b n bx nx qx dl il f y r d i t 'par 'line 'rest c a m ok
type 0 l to list screen 0 which describes the editor,
Screen 0 not modified
0 \\ some comments on this simple editor 29aug95py
1 m marks current position a goes to marked position
2 c moves cursor by n chars t goes to line n and inserts
3 i inserts d deletes marked area
4 r replaces marked area f search and mark
5 il insert a line dl delete a line
6 qx gives a quick index nx gives next index
7 bx gives previous index
8 n goes to next screen b goes to previous screen
9 l goes to screen n v goes to current screen
10 s searches until screen n y yank deleted string
11
12 Syntax and implementation style a la PolyFORTH
13 If you don't like it, write a block editor mode for Emacs!
14
15
ok
Creating your own block file
To create your own new block file myblocks.fb
type: use blocked.fb
type: 1 load
type editor
Then
type use myblocks.fb
1 load will show BLOCK #1 (lines 0 till 15. 16 Lines of 64 characters each)
1 t will highlight line 1
Type i this is text to [i]nsert into line 1
After the current BLOCK is edited type flush in order to write BLOCK #1 to the file myblocks.fb
For more information see, gForth Blocks
It turns out these are "Editor Commands" the book says,
For Those Whose EDITOR Doesn't Follow These Rules
The FORTH-79 Standard does not specify editor commands. Your system may use a different editor; if so, check your systems documentation
I don't believe gforth supports an internal editor at all. So L, T, I, P, F, E, D, R are all presumably unsupported.
gforth is well integrated with emacs. In my xemacs here, by default any file called *.fs is considered FORTH source. "C-h m", as usual, gives the available commands.
No, GNU Forth doesn't have an internal editor; I use Vim :)

Irregularities in Gforth's conversion to doubles

I'm fairly confused about how the s>d and d>s functions work in Forth.
From what I've read, typing 16.0 will put 160 0 on the stack (since it takes up two cells) and d. will show 160.
Now, if I enter 16 s>d I would expect the stack to be 160 0 and d. to show 160 like in the previous example. However, the stack is 16 0 and d. is 16.
Am I entering doubles incorrectly? Is s>d not as simple as "convert a single celled value into a double celled value? Is there any reason for this irregularity? Any clues would be much appreciated.
Gforth interpets all of these the same: 1.60, 16.0, and 160., i.e. 160 converted to a double number. Whereas 16 s>d converts 16 to a double number.
ANS Forth only mandates that when the text interpreter processes a number that is immediately followed by a decimal point and is not found as a definition name, the text interpreter shall convert it to a double-cell number. But Gforth goes beoynd that: http://www.complang.tuwien.ac.at/forth/gforth/Docs-html/Number-Conversion.html#Number-Conversion

Is there a safe way to clean up stack-based code when jumping out of a block?

I've been working on Issue 14 on the PascalScript scripting engine, in which using a Goto command to jump out of a Case block produces a compiler error, even though this is perfectly valid (if ugly) Object Pascal code.
Turns out the ProcessCase routine in the compiler calls HasInvalidJumps, which scans for any Gotos that lead outside of the Case block, and gives a compiler error if it finds one. If I comment that check out, it compiles just fine, but ends up crashing at runtime. A disassembly of the bytecode shows why. I've annotated it with the original script code:
[TYPES]
<SNIPPED>
[VARS]
Var [0]: 27 Class TFORM
Var [1]: 28 Class TAPPLICATION
Var [2]: 11 S32 //i: integer
[PROCS]
Proc [0] Export: !MAIN -1
{begin}
[0] ASSIGN GlobalVar[2], [1]
{ i := 1;}
[15] PUSHTYPE 11(S32) // 1
[20] ASSIGN Base[1], GlobalVar[2]
{ case i of}
[31] PUSHTYPE 25(U8) // 2
{ 0:}
[36] COMPARE into Base[2]: [0] = Base[1]
[57] COND_NOT_GOTO currpos + 5 Base[2] [72]
{ end;}
[67] GOTO currpos + 41 [113]
{ 1:}
[72] COMPARE into Base[2]: [1] = Base[1]
[93] COND_NOT_GOTO currpos + 10 Base[2] [113]
{ goto L1;}
[103] GOTO currpos + 8 [116]
{ end;}
[108] GOTO currpos + 0 [113]
{ end; //<-- case}
[113] POP // 1
[114] POP // 0
{ Exit;}
[115] RET
{L1:
Writeln('Label L1');}
[116] PUSHTYPE 17(WideString) // 1
[121] ASSIGN Base[1], ['????????']
[144] CALL 1
{end.}
[149] POP // 0
[150] RET
Proc [1]: External Decl: \00\00 WRITELN
The "goto L1;" statement at 103 skips the cleanup pops at 113 and 114, which leaves the stack in an invalid state.
Delphi doesn't have any trouble with this, because it doesn't use a calculation stack. PascalScript, though, is not as fortunate. I need some way to make this work, as this pattern is very common in some legacy scripts from a much simpler system with little in the way of control structures that I've translated to PascalScript and need to be able to support.
Anyone have any ideas how to patch the codegen so it'll clean up the stack properly?
IIRC the goto rules in classic pascals were:
jumps are only allowed out of a block (iow from a higher to a lower nesting level on the "same" branch of the tree)
from local procedures to their parents.
The later was afaik never supported by Borland derived Pascals, but the first still holds.
So you need to generate exiting code like Martin says, but possibly it can be for multiple block levels, so you can't have a could codegeneration for each goto, but must generate code (to exit the precise number of needed blocks).
A typical test pattern is to exit from multiple nested ifs (possibly within a loop) using a goto, since that was a classic microoptimization that was faster at least up to D7.
Keep in mind that the if evaluation(s) and the begin..end blocks of their branches might have generated temps that need cleanup.
---------- added later
I think the codegenerator needs a way to walk the scopes between the goto and its endpoint, generating the relevant exit code for blocks along the way. That way a fix works for the general case and not just this example.
Since you can only jump out of scopes, and not into it that might not that be that hard.
IOW generate something that is equivalent to (for a hypothetical double case block)
Lgoto1gluecode:
// exit code first block
pop x
pop y
// exit code first block
pop A
pop B
goto real_goto_destination
Additional analysis can be done. E.g. if there is only one scope, and it has already a cleanup exit label, you can jump directly. If you know for certain that the above pop's are only discarded values (and not saves of registers) you can do them at once with add $16,%esp (4*4 byte values) etc.
The straightforward solution would be:
When generating a GOTO for goto statement, prefix the GOTO with the same cleanup code that comes before RET.
It looks to me like the calculation of how far to jump forward is the problem. I would have to spend some time looking at the implementation of the parser to help further, but my guess would be that additional handling must be performed when using a goto and there are values on the stack AND the goto would be placed after those values would be removed from the stack. Of course to determine this you would need to save the current location being parsed (the goto) and the forward parse to the target location watching for stack changes, and if so then to either adjust the goto location backwards, or inject the code as Martin suggested.

Resources