How does lexical scope help the compilers? Does it help in compilation or optimization?
Lexical scope does not help the compiler or optimise the code. It is a language design decision. See this question for more explanation.
I do think that lexical scope helps the compiler and optimization. It depends what you mean by help though.
Lexical or static scope allow the compiler to proof availability of a variable when referenced locally, that means within its lexical context. It has to be in the scope of the method referencing the variable.
To do such in dynamic scope environments, all calling contexts have to be taken into consideration, as a function knows all variables its calling context knows as well. To make sure a variable is available for reference, a recursive backtrack of all calling contexts would be necessary at compile time.
As this is very complicated, it would be omitted at compile time, throwing exceptions at runtime.
See here: In dynamic scoping, by contrast, you search in the local function first, then you search in the function that called the local function, then you search in the function that called that function, and so on, up the call stack. "Dynamic" refers to change, in that the call stack can be different every time a given function is called, and so the function might hit different variables depending on where it is called from.
Lexical (or static) scoping reduces the amount of information a compiler needs to correctly transform text into code. It can help compilation because the compiler does not need to add additional information that must be accessed at runtime (as is the case with dynamic scoping). For optimizations, the compiler does not need to consider variables that could exist in other scopes, as you can either access local variables or global variables and nothing else.
With dynamic scope, many optimizations are impossible, because you cannot guarantee the constraints that make the optimization possible.
This is especially important in dynamic languages that do not guarantee storage sizes or representations.
For example a compiler for a dynamically typed language may be able to take a linked list of boxed objects and replace it with an array of unsigned 8 bit bytes, if it can prove that the elements of the list will always be integers between 0 and 255. This sort of thing is easy to prove with static scope when you use it properly, and can cause huge increase with both space and computational efficiency.
It is also often easier to debug lexically scoped code, because dynamic variables are much harder to track down in debugging. There is kind of a spaghetti-code of where things may have been defined, similar with the problems caused by goto and overuse of global variables.
Very simply said, lexical (or static) scope helps when a language is statically typed, dynamic scope helps when a language is dynamically typed.
In dynamic scope, the scope of a variable is resolved at runtime. If a variable declared int is used in another lexical environment where a variable with the same name has type float. The only was it to consider them two different variables, which means that variables must carry type information, in most static type systems, type information does not enter the object code at all. A program will simple only compile once it can prove that no type errors will occur, and then no type information is needed any more of course.
Dynamic languages which have lexical scope often need to use a heap rather than a stack to allocate runtime information to for this reason.